Cómo filtrar por condiciones para los modelos asociados?

Tengo una asociación belongsToMany en Usuarios y Contactos.

Me gustaría encontrar los contactos del usuario dado. Necesitaría algo como

$this->Contacts->find()->contain(['Users' => ['Users.id' => 1]]); 

El libro de cocina habla sobre dar condiciones para contener, métodos de búsqueda personalizados y cantar a través de la clave de asociación, pero no descubrí cómo juntarlos.

    Utilice Query :: matching () o Query :: innerJoinWith ()

    Al realizar consultas desde la tabla de Contacts , lo que está buscando es Query::matching() o Query::innerJoinWith() , no (solo) Query::contain() .

    Consulte Libro de cocina> Acceso a la base de datos y ORM> Creador de consultas> Filtrado por datos asociados

    Aquí hay un ejemplo usando sus tablas:

     $this->Contacts ->find() ->matching('Users', function(\Cake\ORM\Query $q) { return $q->where(['Users.id' => 1]); }); 

    Esto agregará automáticamente las uniones requeridas + condiciones a la consulta generada.

    Apunte a la mesa de unión

    En caso de que tenga una configuración manual de muchas a muchas asociaciones a través de hasMany y belongsTo , puede orientar directamente la tabla de unión:

     $this->Contacts ->find() ->matching('ContactsUsers', function(\Cake\ORM\Query $q) { return $q->where(['ContactsUsers.user_id' => 1]); }); 

    Incluir contenciones

    En caso de que realmente desee que todas las asociaciones sean devueltas en sus resultados también, simplemente siga usando contain() también

     $this->Contacts ->find() ->contain('Users') ->matching('Users', function(\Cake\ORM\Query $q) { return $q->where(['Users.id' => 1]); }); 

    Eso contendría a todos los usuarios que pertenecen a un contacto.

    En los casos en que tienes múltiples coincidencias y quisieras contener solo esas coincidencias, también deberías filtrar la contención. En este ejemplo, no tiene mucho sentido, ya que solo habría una coincidencia, pero en otras situaciones podría ser útil, por ejemplo, si quisieras hacer coincidir todos los contactos que tienen usuarios activos, y recuperar los contactos que incluyen todos los usuarios activos asociados:

     $this->Contacts ->find() ->contain(['Users' => function(\Cake\ORM\Query $q) { return $q->where(['Users.active' => true]); }]) ->matching('Users', function(\Cake\ORM\Query $q) { return $q->where(['Users.active' => true]); }); 

    Asociaciones profundas

    También puede orientar las asociaciones más profundas de esa manera, mediante el uso de la syntax de ruta notada por punto conocida de Query::contain() , por ejemplo, si también tiene una asociación de Users hasOne Xyz , puede filtrar por Xyz.id usando

     ->matching('Users.Xyz', function(\Cake\ORM\Query $q) { return $q->where(['Xyz.id' => 1]); }) 

    Seleccione de la otra mesa en su lugar

    Con estas asociaciones y sus requisitos simples, también podría consultar fácilmente desde el otro lado, es decir, a través de la tabla Users y usar solo Query::contain() para incluir los contactos asociados, como

     $this->Users ->find() ->contain('Contacts') ->where([ 'Users.id' => 1 ]) ->first(); 

    Todos los contactos se pueden encontrar en la propiedad de contacts las entidades.