【问题标题】:Laravel eloquent: How to filter with where() and whereHas()Laravel 雄辩:如何使用 where() 和 whereHas() 进行过滤
【发布时间】:2019-08-16 07:57:36
【问题描述】:

我正在尝试根据他们发布内容的类别以及搜索字符串直接过滤用户:

$users = User::when($search, function ($query) use ($request) {
    $query->where('name', 'like', '%' . $request['search'] . '%')
          ->orWhere('email', 'like', '%' . $request['search'] . '%');

    return $query;
})
->when($categories, function ($query) use ($request) {
    return $query->whereHas('posts.category', function ($query) use ($request) {
        $query->whereIn('name', $request['categories']);
    });
})
->select('id', 'name', 'email')
->paginate(10);

当我只过滤类别(没有$search)时,它按预期工作,但只要我输入搜索字符串,结果就会被搜索字符串$request['search'] 过滤,但完全忽略类别过滤。

例如:

名为“Jon”的用户在“生活方式”类别中有一个帖子。

另一个名为“Jonn”的用户在“体育”类别中有一个帖子。

现在,如果我只过滤“体育”类别,我会得到正确的结果 ->“乔恩”。

但是,如果我另外使用搜索字符串“Jon”进行过滤,结果是 ->“Jon”和“Jonn”,这不是预期的结果,因为它应该再次过滤“Sports”并命名为“%Jon%”结果应该只是“乔恩”。

我不知道如何实现where()whereHas() 的过滤器组合。

【问题讨论】:

  • 开始尝试echo $query_builder->toSql(); 以查看您的最终 SQL 语句。

标签: php laravel eloquent


【解决方案1】:

您的问题是约束的嵌套。转换为 SQL,您的查询如下所示:

SELECT id, name, email
FROM users
WHERE name like '%foo%'
   OR address like '%foo%'
   OR email like '%foo%'
  AND EXISTS (
    SELECT *
    FROM categories c
      INNER JOIN posts p ON p.category_id = c.id
    WHERE c.name IN ('bar', 'baz')
  )

注意:分页省略

如您所见,WHERE 语句应该做什么还不是很清楚。但这可以通过将所有搜索约束包装在一个额外的 where() 中来相当容易地解决:

$users = User::when($search, function ($query) use ($request) {
    $query->where(function $query) use ($request) {
        $query->where('name', 'like', '%' . $request['search'] . '%')
            ->orWhere('address', 'like', '%' . $request['search'] . '%')
            ->orWhere('email', 'like', '%' . $request['search'] . '%');
    });
})
->when($categories, function ($query) use ($request) {
    $query->whereHas('posts.category', function ($query) use ($request) {
        $query->whereIn('name', $request['categories']);
    });
})
->select('id', 'name', 'email')
->paginate(10);

这样您的查询将如下所示:

SELECT id, name, email
FROM users
WHERE
  (
     name like '%foo%'
     OR address like '%foo%'
     OR email like '%foo%'
  )
  AND EXISTS (
    SELECT *
    FROM categories c
      INNER JOIN posts p ON p.category_id = c.id
    WHERE c.name IN ('bar', 'baz')
  )

附注:您不必从回调中返回$query

【讨论】:

    【解决方案2】:

    你可以这样试试:

    $users = User::where(function ($query) {
        $query->when($search, function ($query) use ($request) {
            $query->where('name', 'like', '%' . $request['search'] . '%')
              ->orWhere('address', 'like', '%' . $request['search'] . '%')
              ->orWhere('email', 'like', '%' . $request['search'] . '%');
            })
        $query->when($categories, function ($query) use ($request) {
               $query->whereHas('posts.category', function ($query) use ($request) {
               $query->whereIn('name', $request['categories']);
            });
        })
    })
    ->select('id', 'name', 'email')
    ->paginate(10);
    

    我认为你不需要你的回报。但是,如果您将 when 语句放在一个像这样的 where 函数中,您就可以实现您想要的。

    我没有测试这个解决方案,所以如果您有错误,请在评论中提供。

    祝你好运!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-22
      • 2022-01-27
      • 1970-01-01
      • 2021-12-24
      • 2020-03-24
      • 1970-01-01
      相关资源
      最近更新 更多