Um zu überprüfen, ob ein bestimmtes Modell mit einem anderen verwandt ist, was Sie wollen, wenn ich Sie richtig verstehe, brauchen Sie nur diese winzige Methode, um das Beste aus Eloquent zu machen :
(Implementieren Sie es in BaseModel , Entity oder ein Umfang, was auch immer zu Ihnen passt)
// 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);
Die Magie passiert 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);
}
Hey, aber was ist da los?
isRelatedTo() funktioniert so:
-
prüfen, ob
$idbestanden wurde ist ein Modell oder nur eine ID und bereitet$relatedvor model und seine$idzur Verwendung im Rückruf. Wenn Sie kein Objekt übergeben, muss Eloquent alle zugehörigen Modelle in$relationsinstanziieren (relation1.relation2.relation3...)-Kette, um diejenige zu erhalten, an der wir interessiert sind - das passiert ingetNestedRelated(), ziemlich einfach. -
dann müssen wir so etwas tun:
// 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) -
Da wir nicht wissen, wie tief die Beziehung verschachtelt ist, müssen wir die Rekursion verwenden. Wir übergeben jedoch eine Closure an
whereHas, also müssen wir einen kleinen Trick anwenden, um sich selbst in seinem Körper aufzurufen (tatsächlich rufen wir es nicht auf, sondern übergeben es als$callbackzuwhereHas-Methode, da letztere einen Abschluss als 2. Param erwartet) - dies könnte für diejenigen nützlich sein, die Anonyme rekursive PHP-Funktionen :// save it to the variable and pass it by reference $callback = function () use (&$callback) { if (...) // call the $callback again else // finish; } -
wir gehen auch zum Abschluss
$relationsüber (jetzt als Array) per Referenz, um die Verschiebung seiner Elemente rückgängig zu machen, und wenn wir sie alle haben (was bedeutet, dass wirwhereHasverschachtelt haben). ), setzen wir schließlich daswhere-Klausel anstelle eines weiterenwhereHas, um nach unserem$relatedzu suchen Modell. -
Lassen Sie uns schließlich
boolzurückgeben