Mysql
 sql >> Database >  >> RDS >> Mysql

Permesso di visualizzazione/aggiornamento/gestione delle risorse nidificate MySQL (tabelle pivot).

Per verificare se un determinato modello è correlato a un altro, che è quello che vuoi se ho capito bene, tutto ciò di cui hai bisogno è questo piccolo metodo che sfrutta al meglio Eloquent :

(Implementalo in BaseModel , Entity o un cannocchiale, quello che ti si addice)

// 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);

La magia avviene qui:

/**
 * 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);
}

Ehi, ma cosa sta succedendo lì?

isRelatedTo() funziona così:

  1. controlla se è passato $id è un modello o solo un id e prepara $related modello e il suo $id da utilizzare nella richiamata. Se non si passa un oggetto, Eloquent deve istanziare tutti i modelli correlati su $relations (relation1.relation2.relation3... ) per ottenere quello che ci interessa - ecco cosa succede in getNestedRelated() , piuttosto semplice.

  2. quindi dobbiamo fare qualcosa del genere:

    // 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. poiché non sappiamo quanto sia nidificata la relazione, dobbiamo usare la ricorrenza. Tuttavia passiamo una chiusura a whereHas , quindi dobbiamo usare un piccolo trucco per potersi chiamare all'interno del suo corpo (infatti non lo chiamiamo, ma lo passiamo come $callback al whereHas metodo, poiché quest'ultimo prevede una chiusura come 2° parametro) - questo potrebbe essere utile per chi non ha familiarità con Funzioni PHP ricorsive anonime :

    // save it to the variable and pass it by reference
    $callback = function () use (&$callback) {
      if (...) // call the $callback again
      else // finish;
    }
    
  4. passiamo anche alla chiusura $relations (come un array ora) per riferimento per non spostare i suoi elementi e quando li abbiamo ottenuti tutti (il che significa che abbiamo nidificato whereHas ), finalmente mettiamo il where clausola invece di un altro whereHas , per cercare il nostro $related modello.

  5. finalmente restituiamo bool