Cakephp 如何按条件筛选关联模型?

Cakephp 如何按条件筛选关联模型?,cakephp,associations,conditional-statements,cakephp-3.0,query-builder,Cakephp,Associations,Conditional Statements,Cakephp 3.0,Query Builder,我有一个关于用户和联系人的私人协会 我想找到给定用户的联系人。 我需要像这样的东西 $this->Contacts->find()->contain(['Users' => ['Users.id' => 1]]); 这本食谱谈到了提供包含条件、自定义查找器方法和通过关联键进行搜索,但我没有找到如何将它们组合在一起。使用Query::matching()或Query::innerJoinWith() 当从联系人表查询时,您要查找的是Query::matching()

我有一个关于用户和联系人的私人协会

我想找到给定用户的联系人。 我需要像这样的东西

$this->Contacts->find()->contain(['Users' => ['Users.id' => 1]]);
这本食谱谈到了提供包含条件、自定义查找器方法和通过关联键进行搜索,但我没有找到如何将它们组合在一起。

使用Query::matching()或Query::innerJoinWith() 当从
联系人
表查询时,您要查找的是
Query::matching()
Query::innerJoinWith()
,而不是(仅)
Query::contain()

请注意,
innerJoinWith()
通常是首选,以避免出现严格分组问题,因为
matching()
会将关联字段添加到选择列表中,这可能会导致问题,因为它们通常不依赖于功能

下面是一个使用表格的示例:

$this->Contacts
    ->find()
    ->innerJoinWith('Users', function(\Cake\ORM\Query $q) {
        return $q->where(['Users.id' => 1]);
    });
这将自动将所需的连接+条件添加到生成的查询中,以便仅检索与至少一个id为
1
的用户关联的联系人

以联接表为目标 如果您需要通过
hasMany
belongsTo
手动设置多对多关联,您可以直接针对联接表:

$this->Contacts
    ->find()
    ->innerJoinWith('ContactsUsers', function(\Cake\ORM\Query $q) {
        return $q->where(['ContactsUsers.user_id' => 1]);
    });
包括集装箱 如果您确实希望在结果中返回所有关联,那么也只需继续使用
contain()

$this->Contacts
    ->find()
    ->contain('Users')
    ->innerJoinWith('Users', function(\Cake\ORM\Query $q) {
        return $q->where(['Users.id' => 1]);
    });
它将包含属于某个联系人的所有用户

限制集装箱 如果您有多个匹配项,并且希望只包含这些匹配项,那么您也必须过滤包含项。在本例中,这没有多大意义,因为只有一个匹配项,但在其他情况下,它可能很有用,例如,如果您希望匹配所有具有活动用户的联系人,并检索仅包括活动关联用户的联系人:

$this->Contacts
    ->find()
    ->contain(['Users' => function(\Cake\ORM\Query $q) {
        return $q->where(['Users.active' => true]);
    }])
    ->innerJoinWith('Users', function(\Cake\ORM\Query $q) {
        return $q->where(['Users.active' => true]);
    })
    ->group('Contacts.id');
考虑到可能存在重复的联系人,即单个联系人有多个活动用户,您可能希望相应地对内容进行分组,以避免检索重复的联系人记录

深联想 通过使用
Query::contain()
中的点符号路径语法,您还可以通过这种方式定位更深层次的关联。例如,假设您有一个
用户拥有一个Profiles
关联,并且您只希望匹配那些希望接收通知的用户,这可能类似于:

->innerJoinWith('Users.Profiles', function(\Cake\ORM\Query $q) {
    return $q->where(['Profiles.receive_notifications' => true]);
})
这将自动创建所有必需的附加联接

改为从另一个表中选择 有了这些关联和您的简单需求,您还可以轻松地从另一端查询,即通过
Users
表,使用
query::contain()
包含关联的联系人,如

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

所有联系人都可以在entities
contacts
属性中找到。

虽然@ndm answer解决了我需要解决的类似问题,但解决方案需要稍加调整。 问题是让用户通过joinTable上的数据进行筛选添加匹配不会返回用户。这就是我的结局,希望它能帮助别人

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

这使我与关联表中某些_字段设置为1的用户取得了联系。还是我太复杂了,有更好的解决方案?

谢谢,不知怎么的,我错过了这一部分。谢谢。昨天我无意中发现了另一种方法来完成更新中包含的内容$此->联系人->查找()->包含(['users'])->匹配('users',函数($q){return$q->where(['users.id'=>1]);});看:@rrd啊,我应该仔细阅读这篇文章,第一眼我就觉得这两篇文章都不会给你想要的结果。现在,有人需要找出套管技巧是否与更“复杂”的附加关联解决方案一样可行:)当条件为
return$q->where(['ContactsUsers.user_id IN'=>[1,2,3]]时,我会得到重复的结果。请让我知道如何获得独特的结果?或者请在这里回答@ndm@SumonSarker选中“链接文档”部分下的警告框,您必须执行或相应地应用(两者都使用主键)。