Last active
February 29, 2020 13:08
-
-
Save pionl/fae06d53e6e9a66ca18d to your computer and use it in GitHub Desktop.
Model join trait with Automatic Join on Laravel 5 Eloquent Models with relations setup. With automatic filling relation object if detected
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace App\Traits\Models; | |
| use Illuminate\Database\Eloquent\Relations\Relation; | |
| use Illuminate\Database\Query\Expression; | |
| use Illuminate\Support\Str; | |
| /** | |
| * Class ModelJoinTrait | |
| * | |
| * Trait to create model join for scope with detection of model in the attributes. | |
| * | |
| * Prefils the relations array | |
| * | |
| * @package App\Traits\Models | |
| */ | |
| trait ModelJoinTrait | |
| { | |
| protected $modelJoined = array(); | |
| /** | |
| * This determines the foreign key relations automatically to prevent the need to figure out the columns. | |
| * | |
| * Based on http://laravel-tricks.com/tricks/automatic-join-on-eloquent-models-with-relations-setup | |
| * | |
| * @param \Illuminate\Database\Query\Builder $query | |
| * @param string $relation_name the function that return the relation | |
| * @param string $operatorOrCollumns ON condition operator | |
| * @param string $type join type (left, right, '', etc) | |
| * @param bool $where custom where condition | |
| * @param array $collumns if you will not pass collumns, it will retreive the collumn listing via | |
| * all collumns * | |
| * | |
| * @return \Illuminate\Database\Query\Builder | |
| * | |
| * @link http://laravel-tricks.com/tricks/automatic-join-on-eloquent-models-with-relations-setup | |
| */ | |
| public function scopeModelJoin($query, $relation_name, $operatorOrCollumns = '=', $type = 'left', | |
| $where = false, $collumns = array()) { | |
| $relation = $this->$relation_name(); | |
| $table = $relation->getRelated()->getTable(); | |
| $one = $relation->getQualifiedParentKeyName(); | |
| $two = $relation->getForeignKey(); | |
| // if the operator collumns are in | |
| if (is_array($operatorOrCollumns)) { | |
| $collumns = $operatorOrCollumns; | |
| $operatorOrCollumns = "="; | |
| } | |
| // if the query has missing collumns list, we need to add select for all collumns | |
| // of this table | |
| if (empty($query->columns)) { | |
| $query->select($this->getTable().".*"); | |
| } | |
| // if there is no specific collumns, lets get all | |
| if (empty($collumns)) { | |
| $collumns = \Schema::getColumnListing($table); | |
| } | |
| // build the table values prefixed by the table to ensure unique values | |
| foreach ($collumns as $related_column) { | |
| $query->addSelect(new Expression("`$table`.`$related_column` AS `$table.$related_column`")); | |
| } | |
| $this->modelJoined[$table] = $relation; | |
| return $query->join($table, $one, $operatorOrCollumns, $two, $type, $where); | |
| } | |
| /** | |
| * Overides the basic attributes filling with check if the attributes has | |
| * collumns with table format. Checks if we can make a model based on table prefix and | |
| * relation definition. Tested on BelonstTo and left join | |
| * | |
| * @param array $attributes | |
| * @param bool|false $sync | |
| * @return mixed | |
| */ | |
| public function setRawAttributes(array $attributes, $sync = false) | |
| { | |
| // find | |
| $tableAttributes = $this->getAttributesByTablePrefix($attributes); | |
| if (!empty($tableAttributes)) { | |
| foreach ($tableAttributes as $tableFull => $newAttributes) { | |
| // check if its relation function. The table names can | |
| // be in plurar | |
| $table = Str::singular($tableFull); | |
| // check if exists | |
| if (method_exists($this, $table)) { | |
| $relation = $this->$table(); | |
| if (is_object($relation) && method_exists($relation, "getRelated")) { | |
| $instance = $relation->getRelated()->newInstance($newAttributes, true); | |
| $this->relations[$table] = $instance; | |
| foreach ($newAttributes as $key => $attribute) { | |
| unset($attributes[$key]); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| return parent::setRawAttributes($attributes, $sync); | |
| } | |
| /** | |
| * Loops all the attributes and finds only values that have prefix format | |
| * TABLE.COLLUMN | |
| * @param array $attributes | |
| * @return array | |
| */ | |
| public function getAttributesByTablePrefix(array $attributes) | |
| { | |
| $tableAttributes = array(); | |
| foreach ($attributes as $attribute => $value) { | |
| // check prefix format | |
| if (preg_match("/([^\.]+)\.(.*)/", $attribute, $matches)) { | |
| $tableAttributes[$matches[1]][$matches[2]] = $value; | |
| } | |
| } | |
| return $tableAttributes; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How to use this in many to many relations.