【问题标题】:Laravel multiple where condition in whereHas callbackLaravel 多个 where 条件 whereHas 回调
【发布时间】:2016-06-17 10:47:37
【问题描述】:

我正在使用 Laravel 5.2 创建一个通用搜索功能,我想显示所有出现搜索关键字的书籍:书名、书名、书的情节、书的作者姓名、书的作者姓氏; 我认为这段代码会起作用:

$results = Book::whereHas('author', function ($query) use ($keyword)
                     {
                          $query->where('surname', 'LIKE', '%'.$keyword.'%')
                               ->orWhere('name', 'LIKE', '%'.$keyword.'%');
                     })
                     ->orWhere('title', 'LIKE', '%'.$keyword.'%')
                     ->orWhere('plot', 'LIKE', '%'.$keyword.'%')
                     ->orWhere('subject', 'LIKE', '%'.$keyword.'%')
                     ->get();

但是当我使用作者的名字作为关键字时,我会得到整个库的结果。 相反,如果我输入作者的姓氏,它就可以完美地工作。

我发现了这个解决方案,我认为这不是最佳的,但至少它有效:

$results = Book::whereHas('author', function ($query) use ($keyword)
                     {
                          $query->where('surname', 'LIKE', '%'.$keyword.'%');
                     })
                     ->orWhereHas('author', function ($query) use ($keyword)
                     {
                          $query->where('name', 'LIKE', '%'.$keyword.'%');
                     })
                     ->orWhere('title', 'LIKE', '%'.$keyword.'%')
                     ->orWhere('plot', 'LIKE', '%'.$keyword.'%')
                     ->orWhere('subject', 'LIKE', '%'.$keyword.'%')
                     ->get();

有什么建议吗? 提前感谢您的帮助!

【问题讨论】:

  • 也许为搜索(关键字)创建一些额外的索引表?如果你想要“一些”速度,请使用 redis 而不是 mysql。
  • @Hardy 感谢您的建议,但实际上只是学校的一个项目;自从发现了laravel这个有趣的行为,我就想知道原因,仅此而已。

标签: php mysql sql laravel


【解决方案1】:

问题是在闭包中添加的 where 子句并不是唯一应用于子查询的 where 子句。 whereHas() 方法生成一个子查询,该子查询以关系 id 上的 where 子句开头。因此,您的子查询不仅仅是where x or y,它实际上是where x and y or z。

鉴于这组 where 子句以及逻辑运算符的操作顺序,如果 z 条件为真(您的“姓名”条件),则整个 where 子句将返回 true,这意味着仅查看的约束相关对象被完全忽略。由于相关对象的约束被忽略,has 条件对于每条记录都将为真(如果 'name' 匹配任何记录)。

以下是您的逻辑条件的示例:

// first boolean is the related keys check
// second boolean is the surname check
// third boolean is the name check

// this is your current logic
// as you can see, this returns true even when looking at an
// author not even related to the book.
var_export(false && false || true); // true

// this is what your logic needs to be
var_export(false && (false || true)); // false

因此,要解决此问题,您需要将 or 条件括在括号中,以便按照您的预期评估它们。您可以通过将闭包传递给where() 方法来做到这一点,然后在闭包内添加的任何条件都将放在括号内:

$results = Book::whereHas('author', function ($query) use ($keyword) {
        $query->where(function ($q) use ($keyword) {
            $q->where('surname', 'LIKE', '%'.$keyword.'%')
                ->orWhere('name', 'LIKE', '%'.$keyword.'%');
        });
    })
    ->orWhere('title', 'LIKE', '%'.$keyword.'%')
    ->orWhere('plot', 'LIKE', '%'.$keyword.'%')
    ->orWhere('subject', 'LIKE', '%'.$keyword.'%')
    ->get();

【讨论】:

  • 非常感谢您的聪明回答,非常感谢!
【解决方案2】:

您是否尝试过为您的作者/用户模型创建一个本地查询范围,例如 named() 然后应用它

public function scopeNamed($query)
{
    return $query->where('surname', 'LIKE', '%'.$keyword.'%')
                 ->orWhere('name', 'LIKE', '%'.$keyword.'%');
}

然后你的查询

$results = Book::whereHas('author', function ($query) use ($keyword)
                 {
                      $query->named();
                 })
                 ->orWhere('title', 'LIKE', '%'.$keyword.'%')
                 ->orWhere('plot', 'LIKE', '%'.$keyword.'%')
                 ->orWhere('subject', 'LIKE', '%'.$keyword.'%')
                 ->get();

https://laravel.com/docs/master/eloquent#query-scopes

【讨论】:

  • 我想这是因为,尽管这个答案对于展示如何创建范围很有用,但它对解决问题没有任何作用。原始代码和此答案中的代码在功能上是等效的。您刚刚移动到定义 where 子句的位置。
猜你喜欢
  • 2021-07-01
  • 2019-12-28
  • 2019-02-09
  • 2017-11-02
  • 1970-01-01
  • 2021-12-03
  • 2021-01-08
  • 1970-01-01
  • 2023-03-14
相关资源
最近更新 更多