For at kontrollere, om en given model er relateret til en anden, hvilket er det, du vil have, hvis jeg forstår dig rigtigt, er alt, hvad du behøver, denne lille metode, hvor du får mest muligt ud af Eloquent
:
(Implementer det i BaseModel
, Entity
eller et omfang, hvad end der passer dig)
// 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);
Magien sker her:
/**
* 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);
}
Hej, men hvad sker der?
isRelatedTo()
fungerer sådan her:
-
tjek om bestået
$id
er en model eller blot et id, og forbereder$related
model og dens$id
til brug ved tilbagekald. Hvis du ikke sender et objekt, skal Eloquent instansiere alle de relaterede modeller på$relations
(relation1.relation2.relation3...
) kæde for at få den, vi er interesseret i - det er, hvad der sker igetNestedRelated()
, ret ligetil. -
så skal vi gøre sådan noget:
// 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 vi ikke ved, hvor dybt relationen er indlejret, er vi nødt til at bruge gentagelse. Men vi sender en lukning til
whereHas
, så vi er nødt til at bruge et lille trick for at kalde sig selv inde i sin krop (faktisk kalder vi det ikke, men sender det snarere som$callback
tilwhereHas
metode, da sidstnævnte forventer en lukning som 2. param) - dette kan være nyttigt for dem, der ikke kender Anonyme rekursive PHP-funktioner :// save it to the variable and pass it by reference $callback = function () use (&$callback) { if (...) // call the $callback again else // finish; }
-
vi går også videre til lukningen
$relations
(som et array nu) ved reference for at fjerne dets elementer, og når vi fik dem alle (det betyder, at vi indlejredewhereHas
), sætter vi endeligwhere
klausul i stedet for en andenwhereHas
, for at søge efter vores$related
model. -
lad os endelig returnere
bool