За да проверите дали даден модел е свързан с друг, което искате, ако ви разбера правилно, всичко, от което се нуждаете, е този малък метод, който се възползва максимално от Eloquent
:
(Приложете го в BaseModel
, Entity
или обхват, както ви подхожда)
// 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);
Магията се случва тук:
/**
* 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);
}
Хей, но какво става там?
isRelatedTo()
работи така:
-
проверете дали е предадено
$id
е модел или просто идентификатор и подготвя$related
модел и неговия$id
за използване в обратното повикване. Ако не предадете обект, тогава Eloquent трябва да инстанцира всички свързани модели в$relations
(relation1.relation2.relation3...
) верига, за да получим този, който ни интересува - това се случва вgetNestedRelated()
, доста просто. -
тогава трябва да направим нещо подобно:
// 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)
-
тъй като не знаем колко дълбоко е вложена връзката, трябва да използваме рекурентност. Въпреки това ние предаваме Closure на
whereHas
, така че трябва да използваме малък трик, за да извикаме себе си вътре в тялото му (всъщност не го извикваме, а по-скоро го предаваме като$callback
къмwhereHas
метод, тъй като последният очаква затваряне като 2-ри параметър) - това може да е полезно за тези, които не са запознати Анонимни рекурсивни PHP функции :// save it to the variable and pass it by reference $callback = function () use (&$callback) { if (...) // call the $callback again else // finish; }
-
ние също преминаваме към затварянето
$relations
(като масив сега) чрез препратка, за да премахнем изместването на неговите елементи, и когато ги получихме всички (което означава, че сме вложилиwhereHas
), накрая поставямеwhere
клауза вместо другаwhereHas
, за да потърсите нашия$related
модел. -
накрая нека върнем
bool