Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Permissão de recursos aninhados do MySQL (tabelas dinâmicas) para visualizar/atualizar/gerenciar


Para verificar se um determinado modelo está relacionado a outro, que é o que você quer se eu acertar, tudo que você precisa é deste pequeno método aproveitando ao máximo o Eloquent :

(Implemente em BaseModel , Entity ou um escopo, o que mais lhe convier)
// 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);

A mágica acontece aqui:
/**
 * 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);
}

Ei, mas o que está acontecendo aí?


isRelatedTo() funciona assim:

  1. verifique se passou $id é um modelo ou apenas um id e prepara $related model e seu $id para uso no retorno de chamada. Se você não passar um objeto, o Eloquent precisará instanciar todos os modelos relacionados no $relations (relation1.relation2.relation3... ) para obter o que estamos interessados ​​- é o que acontece em getNestedRelated() , bem direto.

  2. então precisamos fazer algo assim:
    // 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. como não sabemos quão profundamente a relação está aninhada, precisamos usar a recorrência. No entanto, passamos um Closure para o whereHas , então precisamos usar um pequeno truque para chamar a si mesmo dentro de seu corpo (na verdade, não o chamamos, mas o passamos como $callback para o whereHas método, já que o último espera um encerramento como segundo parâmetro) - isso pode ser útil para aqueles que não estão familiarizados com Funções PHP recursivas anônimas :
    // save it to the variable and pass it by reference
    $callback = function () use (&$callback) {
      if (...) // call the $callback again
      else // finish;
    }
    

  4. também passamos para o fechamento $relations (como uma matriz agora) por referência para desfazer o deslocamento de seus elementos, e quando obtivemos todos eles (o que significa que aninhamos whereHas ), finalmente colocamos o where cláusula em vez de outra whereHas , para pesquisar nosso $related modelo.

  5. finalmente vamos retornar bool