查询生成器 when() 方法生成条件错误的查询

Query builder when() method producing wrongly conditioned query

我发布了一个我认为是 Laravel 错误 (https://github.com/laravel/framework/issues/39398) 的帖子,但它已被关闭,因为我不是 100% 确定它确实是一个错误。其他人可以告诉我这种行为是否有误吗?

我有如下一段代码:

$user=251;
$description='created';
Activity::when($user, function ($query, $user) {
    return $query->where('causer_id', $user)
    ->orWhere(function($query) use ($user) {
        $query->where('subject_id', $user)
        ->where('subject_type', "App\User");
    });
})->when($description, function ($query, $description) {
    return $query->where('description', $description);
});

从逻辑上讲,我认为它应该生成一个查询,该查询 return 所有具有正确用户和正确描述的行,但无论描述如何,我都会得到该用户的所有行。

上面的代码产生这个 sql 查询:

select * from activity_log where causer_id = '251' or (subject_id = '251' and subject_type = 'App\User') and description = 'created'

...而我认为它应该产生:

select * from activity_log where (causer_id = '251' or (subject_id = '251' and subject_type = 'App\User')) and (description = 'created')

简而言之:when() 函数不应该在其 returned 结果周围加上括号以不影响查询的其他部分吗?它不是一个错误吗?

我不认为这是一个错误。这不是破坏的预期行为。这将是一个要添加到框架中的新功能。您可以访问 Discord 服务器并尝试提出您的理由,或者简单地提交包含更改的 PR 并为其辩护,但这并不是“破坏”了现有功能。

when() 方法只是语法糖,因此您可以有条件地修改方法链中的查询,而不必分解为单独的 if 语句。以下代码是等效的:

$query = Activity::query();

if ($user) {
    $query->where('causer_id', $user)
        ->orWhere(function($query) use ($user) {
            $query->where('subject_id', $user)
                ->where('subject_type', "App\User");
        });
}

if ($description) {
    $query->where('description', $description);
}

如您在上面的代码中所见,不会期望任何有条件添加的子句都包含在括号中(除非在您的 orWhere() 调用中明确指定)。

您所期望的一个问题是 when() 方法可用于以任何方式修改查询,而不仅仅是添加额外的条件。因此,如果您在 when() 子句中添加 orderBy()limit(),您希望发生什么情况?

因此,when() 方法本身不会修改您的查询,但它会 运行 完全按照您的指示进行修改。因此,要执行您正在寻找的操作,您需要自己将查询包装在 when() 子句中:

Activity::when($user, function ($query, $user) {
              return $query->where(function($query) use ($user) {
                  return $query->where('causer_id', $user)
                               ->orWhere(function($query) use ($user) {
                                   $query->where('subject_id', $user)
                                         ->where('subject_type', "App\User");
                               });
              });
       })
       ->when($description, function ($query, $description) {
           return $query->where('description', $description);
       });