Last active
September 16, 2016 10:46
-
-
Save ethaizone/43749da85436ae125423a0fe98991134 to your computer and use it in GitHub Desktop.
Eloquent trait act as helper about relation on eloquent.
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; | |
use Illuminate\Database\Eloquent\Relations\Relation; | |
use Illuminate\Database\Eloquent\Relations\HasOneOrMany; | |
use Illuminate\Database\Eloquent\Relations\BelongsTo; | |
use Illuminate\Database\Eloquent\Relations\HasManyThrough; | |
use Closure; | |
use Exception; | |
/** | |
* RelationHelper | |
* | |
* @author Nimit Suwannagate <[email protected]> | |
*/ | |
trait RelationHelper | |
{ | |
/** | |
* Join table with eloquent relation | |
* @param \Illuminate\Database\Eloquent\Builder $query | |
* @param string $relation | |
*/ | |
public function scopeJoinRelation($query, $relation) | |
{ | |
if (empty($query->relationJoined)) { | |
$query->relationJoined = []; | |
} | |
$this->walkNestedRelation($relation, function($relation, $relationName, $relationDeep) use ($query) { | |
// Check relation is joined or not? | |
if (! in_array($relationName, $query->relationJoined)) { | |
// Create variable for join usage | |
$relationTable = $relation->getRelated()->getTable(); | |
if ($relation instanceof HasOneOrMany) { | |
$relationForeignKey = $relation->getForeignKey(); | |
$selfTableAndKey = $relation->getQualifiedParentKeyName(); | |
} | |
if ($relation instanceof BelongsTo) { | |
$relationForeignKey = $relation->getQualifiedOtherKeyName(); | |
$selfTableAndKey = $relation->getQualifiedForeignKey(); | |
} | |
if ($relation instanceof HasManyThrough) { | |
$relationForeignKey = $relation->getForeignKey(); | |
$selfTableAndKey = $relation->getThroughKey(); | |
} | |
if (empty($selfTableAndKey)) { | |
throw new Exception(get_class($relation) . " is not supported. This is new relation so please implement it."); | |
} | |
// Add join to query | |
$query->join($relationTable, $relationForeignKey, '=', $selfTableAndKey); | |
// Stamp relation name to protect double join. | |
$query->relationJoined[] = $relationName; | |
} | |
}); | |
} | |
/** | |
* Walk nested relation | |
* @param string $relation | |
* @param Closure $callback | |
* @return array | |
*/ | |
public function walkNestedRelation($relation, Closure $callback) | |
{ | |
$model = $this; | |
// Create chunk for collection relation that passed in loop. | |
$relationChunkPassed = []; | |
$results = []; | |
// Parse the nested relationships in a relation. | |
foreach (explode('.', $relation) as $relationDeep => $segment) { | |
// Add relation to chunk | |
$relationChunkPassed[] = $segment; | |
$relation = $model->$segment(); | |
if (! $relation instanceof Relation) { | |
throw new Exception("{$segment} is not relation method."); | |
} | |
// Make nested relation from temp chunk | |
$relationName = implode('.', $relationChunkPassed); | |
// Call callback with send relation, relationName, relationDeep | |
$results[$relationName] = $callback($relation, $relationName, $relationDeep); | |
// set model with relation for next deep | |
$model = $relation->getRelated(); | |
} | |
return $results; | |
} | |
/** | |
* Get relation table by nested relation | |
* @param string $relation | |
* @return string | |
*/ | |
public function getRelationTable($relation) | |
{ | |
$results = $this->walkNestedRelation($relation, function($relation, $relationName, $relationDeep) { | |
return $relation->getRelated()->getTable(); | |
}); | |
return last($results); | |
} | |
} |
I forget about support BelongsToMany. I think I will implement it later when I use it. Just don't have any model for test it right now. LOL
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This code will make join in your query based on current relations on model. This trait support nested dot relations of Eloquent so you don't have to do stupid job to get table name or foreign key to make a good join query. Just take a look!
Example usage:
My models
If you don't use my trait, this is code that you must write to do same effect.