cakephp 构建查询以过滤模型或关联模型
cakephp build query to filter on model OR associated model
我想通过过滤 table 的列来查找行, 或 在关联的 table的专栏。我可以使用 AND 版本,但我不确定如何将 ->where()
和 ->matching()
之间的条件更改为 OR.
在此示例中,我想通过用户名或常规名称查找用户。在这种情况下,用户 hasMany
名称。
$users = $this->Users->find()
->where(['username LIKE' => '%' . $search_term . '%'])
->matching('Names', function($q) use ($search_term){
return $q->where(function($exp, $query) use ($search_term) {
$full_name = $query->func()->concat([
'first' => 'identifier', ' ',
'last' => 'identifier'
]);
return $exp->like($full_name, '%' . $search_term . '%');
});
})
->contain(['Names'])
->limit(10)
->all();
matching()
creates INNER
joins,在联接的 ON
子句中应用条件,如果不存在匹配的名称,则会导致用户被过滤掉,因此您不能使用它来创建 OR
您正在寻找的条件。
例如,您可以将您的姓名检查移动到相关子查询(引用外部查询列的查询),以及 use it with EXISTS
,类似于:
$namesMatcher = $this->Users->Names
->find()
->select(['Names.id'])
->where(function($exp, $query) use ($search_term) {
$full_name = $query->func()->concat([
'Names.first' => 'identifier', ' ',
'Names.last' => 'identifier'
]);
return $exp
->equalFields('Names.user_id', 'Users.id')
->like($full_name, '%' . $search_term . '%');
});
$users = $this->Users->find()
->where(function($exp, $query) use ($search_term, $namesMatcher) {
return $exp
->or_(['Users.username LIKE' => '%' . $search_term . '%'])
->exists($namesMatcher);
})
->contain(['Names'])
->limit(10)
->all();
生成的查询看起来像这样:
SELECT
Users.id ...
FROM
users Users
WHERE
Users.username LIKE '%term%' OR
EXISTS(
SELECT
Names.id
FROM
names Names
WHERE
Names.user_id = Users.id AND
CONCAT(Names.first, ' ', Names.last) LIKE '%term%'
)
这也可以通过使用 LEFT
联接来解决,这样用户记录就不会受到联接的影响(请参阅 Query::leftJoinWith()
),从而允许您创建一个 OR
相应条件,但由于您似乎不需要进一步访问查询中的名称,因此选择它们并没有什么意义。
我想通过过滤 table 的列来查找行, 或 在关联的 table的专栏。我可以使用 AND 版本,但我不确定如何将 ->where()
和 ->matching()
之间的条件更改为 OR.
在此示例中,我想通过用户名或常规名称查找用户。在这种情况下,用户 hasMany
名称。
$users = $this->Users->find()
->where(['username LIKE' => '%' . $search_term . '%'])
->matching('Names', function($q) use ($search_term){
return $q->where(function($exp, $query) use ($search_term) {
$full_name = $query->func()->concat([
'first' => 'identifier', ' ',
'last' => 'identifier'
]);
return $exp->like($full_name, '%' . $search_term . '%');
});
})
->contain(['Names'])
->limit(10)
->all();
matching()
creates INNER
joins,在联接的 ON
子句中应用条件,如果不存在匹配的名称,则会导致用户被过滤掉,因此您不能使用它来创建 OR
您正在寻找的条件。
例如,您可以将您的姓名检查移动到相关子查询(引用外部查询列的查询),以及 use it with EXISTS
,类似于:
$namesMatcher = $this->Users->Names
->find()
->select(['Names.id'])
->where(function($exp, $query) use ($search_term) {
$full_name = $query->func()->concat([
'Names.first' => 'identifier', ' ',
'Names.last' => 'identifier'
]);
return $exp
->equalFields('Names.user_id', 'Users.id')
->like($full_name, '%' . $search_term . '%');
});
$users = $this->Users->find()
->where(function($exp, $query) use ($search_term, $namesMatcher) {
return $exp
->or_(['Users.username LIKE' => '%' . $search_term . '%'])
->exists($namesMatcher);
})
->contain(['Names'])
->limit(10)
->all();
生成的查询看起来像这样:
SELECT
Users.id ...
FROM
users Users
WHERE
Users.username LIKE '%term%' OR
EXISTS(
SELECT
Names.id
FROM
names Names
WHERE
Names.user_id = Users.id AND
CONCAT(Names.first, ' ', Names.last) LIKE '%term%'
)
这也可以通过使用 LEFT
联接来解决,这样用户记录就不会受到联接的影响(请参阅 Query::leftJoinWith()
),从而允许您创建一个 OR
相应条件,但由于您似乎不需要进一步访问查询中的名称,因此选择它们并没有什么意义。