Om te controleren of een bepaald model gerelateerd is aan een ander model, wat je wilt als ik het goed begrijp, is alles wat je nodig hebt deze kleine methode om het meeste uit Eloquent
te halen. :
(Implementeer het in BaseModel
, Entity
of een scope, wat bij je past)
// usage
$task->isRelatedTo('transactions.users', $id);
// or
$template->isRelatedTo('tasks.transactions.users', Auth::user());
// or any kind of relation:
// imagine this: User m-m Transaction 1-m Item m-1 Group
$group->isRelatedTo('items.transaction.users', $id);
De magie gebeurt hier:
/**
* Check if it is related to any given model through dot nested relations
*
* @param string $relations
* @param int|\Illuminate\Database\Eloquent\Model $id
* @return boolean
*/
public function isRelatedTo($relations, $id)
{
$relations = explode('.', $relations);
if ($id instanceof Model)
{
$related = $id;
$id = $related->getKey();
}
else
{
$related = $this->getNestedRelated($relations);
}
// recursive closure
$callback = function ($q) use (&$callback, &$relations, $related, $id)
{
if (count($relations))
{
$q->whereHas(array_shift($relations), $callback);
}
else
{
$q->where($related->getQualifiedKeyName(), $id);
}
};
return (bool) $this->whereHas(array_shift($relations), $callback)->find($this->getKey());
}
protected function getNestedRelated(array $relations)
{
$models = [];
foreach ($relations as $key => $relation)
{
$parent = ($key) ? $models[$key-1] : $this;
$models[] = $parent->{$relation}()->getRelated();
}
return end($models);
}
Hé, maar wat is daar aan de hand?
isRelatedTo()
werkt als volgt:
-
controleer of doorgegeven
$id
is een model of gewoon een ID, en bereidt$related
. voor model en zijn$id
voor gebruik bij het terugbellen. Als u geen object doorgeeft, moet Eloquent alle gerelateerde modellen op de$relations
instantiëren (relation1.relation2.relation3...
) keten om degene te krijgen waarin we geïnteresseerd zijn - dat is wat er gebeurt ingetNestedRelated()
, vrij eenvoudig. -
dan moeten we zoiets als dit doen:
// assuming relations 'relation1.relation2.relation3' $this->whereHas('relation1', function ($q) use ($id) { $q->whereHas('relation2', function ($q) use ($id) { $q->whereHas('relation3', function ($q) use ($id) { $q->where('id', $id); }); }); })->find($this->getKey()); // returns new instance of current model or null, thus cast to (bool)
-
omdat we niet weten hoe diep de relatie is genest, moeten we herhaling gebruiken. We geven echter een sluiting door aan de
whereHas
, dus we moeten een klein trucje gebruiken om zichzelf in zijn lichaam te noemen (in feite noemen we het niet, maar geven het door als$callback
naar dewhereHas
methode, aangezien de laatste een sluiting verwacht als 2e parameter) - dit kan handig zijn voor degenen die onbekend zijn Anonieme recursieve PHP-functies :// save it to the variable and pass it by reference $callback = function () use (&$callback) { if (...) // call the $callback again else // finish; }
-
we gaan ook door naar de sluiting
$relations
(nu als een array) door te verwijzen om de elementen ervan ongedaan te maken, en wanneer we ze allemaal hebben (wat betekent dat wewhereHas
hebben genest ), plaatsen we tenslotte dewhere
clausule in plaats van een anderewhereHas
, om te zoeken naar onze$related
model. -
laten we tot slot
bool
return teruggeven