cakephp建立查询以过滤模型或相关模型

时间:2019-01-01 22:16:42

标签: cakephp cakephp-3.0

我想通过过滤表的列(关联表的列上的 OR )来查找行。我可以使用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();

1 个答案:

答案 0 :(得分:1)

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()),从而允许您创建{{1} }条件,但是由于您似乎不需要进一步访问查询中的名称,因此选择它们实际上没有意义。