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
$id
bestanden wurde ist ein Modell oder nur eine ID und bereitet$related
vor model und seine$id
zur Verwendung im Rückruf. Wenn Sie kein Objekt übergeben, muss Eloquent alle zugehörigen Modelle in$relations
instanziieren (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$callback
zuwhereHas
-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 wirwhereHas
verschachtelt haben). ), setzen wir schließlich daswhere
-Klausel anstelle eines weiterenwhereHas
, um nach unserem$related
zu suchen Modell. -
Lassen Sie uns schließlich
bool
zurückgeben