sql >> Databasteknik >  >> RDS >> Mysql

MySQL kapslade resurser (pivottabeller) behörighet att visa/uppdatera/hantera

För att kontrollera om en given modell är relaterad till en annan, vilket är vad du vill ha om jag förstår dig rätt, behöver du bara den här lilla metoden som gör det bästa av Eloquent :

(Implementera det i BaseModel , Entity eller en omfattning, vad som än passar 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);

Magin händer här:

/**
 * 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 vad händer där?

isRelatedTo() fungerar så här:

  1. kontrollera om $id har gått igenom är en modell eller bara ett id, och förbereder $related modell och dess $id för användning vid återuppringning. Om du inte skickar ett objekt måste Eloquent instansiera alla relaterade modeller på $relations (relation1.relation2.relation3... ) kedja för att få den vi är intresserade av - det är vad som händer i getNestedRelated() , ganska okomplicerat.

  2. då måste vi göra något sånt här:

    // 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)
    
  3. eftersom vi inte vet hur djupt relationen är kapslad måste vi använda upprepning. Men vi skickar en stängning till whereHas , så vi måste använda lite knep för att kalla sig inuti sin kropp (i själva verket kallar vi det inte, utan skickar det som $callback till whereHas metod, eftersom den senare förväntar sig en stängning som 2:a param) - det här kan vara användbart för de obekanta Anonyma rekursiva PHP-funktioner :

    // save it to the variable and pass it by reference
    $callback = function () use (&$callback) {
      if (...) // call the $callback again
      else // finish;
    }
    
  4. vi går också över till stängningen $relations (som en array nu) genom referens för att avskifta dess element, och när vi fick dem alla (vilket betyder att vi kapslade whereHas ), lägger vi till slut where sats istället för en annan whereHas , för att söka efter vår $related modell.

  5. låt oss slutligen returnera bool



  1. #1067 - Ogiltigt standardvärde för 'bonusid' hur kan jag åtgärda detta fel?

  2. 12 vanliga SQL-operatorer

  3. Det gick inte att byta namn på en kolumn i MySQL

  4. En recension av de nya analytiska fönsterfunktionerna i MySQL 8.0