我正在尝试根据用户发布过文章的类别来过滤用户,并根据搜索字符串直接过滤用户:
$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']
过滤,但完全忽略了类别过滤
例如:
名为“乔恩”的用户在“生活方式”类别中有一条帖子。
另一个名为“ Jonn”的用户在“体育”类别中有一条帖子。
现在,如果我仅针对“体育”类别进行过滤,则会得到正确的结果->“乔恩”。
但是,如果我另外使用搜索字符串“ Jon”进行过滤,结果将是->“ Jon”和“ Jonn”,这不是预期的结果,因为它应该过滤“ Sports”并命名为“%Jon%”结果应仅为“ Jonn”。
我不知道如何实现where()
和whereHas()
的过滤器组合。
答案 0 :(得分:4)
您的问题是约束的嵌套。转换为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
。
答案 1 :(得分:1)
您可以尝试这样:
$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
函数中,则可以实现您想要的东西。
我没有测试此解决方案,因此如果您有任何错误,请在评论中提供。
祝你好运!