sql >> Base de Datos >  >> RDS >> Mysql

Permiso de recursos anidados de MySQL (tablas dinámicas) para ver/actualizar/administrar

Para verificar si el modelo dado está relacionado con otro, que es lo que quieres si te entiendo bien, todo lo que necesitas es este pequeño método que aprovecha al máximo Eloquent :

(Impleméntelo en BaseModel , Entity o un alcance, lo que más le convenga)

// 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 sucede aquí:

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

Oye, pero ¿qué está pasando ahí?

isRelatedTo() funciona así:

  1. verificar si pasó $id es un modelo o simplemente una identificación, y prepara $related modelo y su $id para su uso en la devolución de llamada. Si no pasa un objeto, Eloquent necesita instanciar todos los modelos relacionados en $relations (relation1.relation2.relation3... ) cadena para obtener el que nos interesa; eso es lo que sucede en getNestedRelated() , bastante sencillo.

  2. entonces tenemos que hacer algo como esto:

    // 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. dado que no sabemos qué tan profundamente está anidada la relación, necesitamos usar la recurrencia. Sin embargo, pasamos un Closure al whereHas , por lo que necesitamos usar un pequeño truco para llamarse a sí mismo dentro de su cuerpo (de hecho, no lo llamamos, sino que lo pasamos como $callback al whereHas método, ya que este último espera un Cierre como segundo parámetro) - esto podría ser útil para aquellos que no están familiarizados con Funciones 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. también pasamos al cierre $relations (como una matriz ahora) por referencia con el fin de cambiar sus elementos, y cuando los obtuvimos todos (lo que significa que anidamos whereHas ), finalmente ponemos el where cláusula en lugar de otro whereHas , para buscar nuestro $related modelo.

  5. finalmente regresemos bool