我想创建动态过滤器。
例如我要创建此代码
$Contact = Contact::whereHas('User', function ($query) use ($searchString) {
$query->where('name', 'like', '%Jhone%')->orwhere('family', '<>' . 'Doe');
})->whereHas('Account', function ($query) use ($searchString) {
$query->where('account_name', '=' , 'test_account' )->orwhere('account_city', 'like', '%test_city%');
})->get();
,所有参数都是可变的
name
,like
,%Jhone%
,family
,<>
,Doe
,.....
我想将变量传递给函数,并在上面的查询中创建函数。
答案 0 :(得分:1)
我假设您的Contact
,User
和Account
模型中的关系函数是用camelCase
而不是PascalCase
编写的,如您的示例所示。 / p>
public function getContacts(Request $request)
{
return Contact::when($request->get('username'), function ($query, $val) use ($request) {
$query->whereHas('user', function ($q) use ($val, $request) {
$q->where('name', 'like', '%'.$val.'%');
if ($request->has('familyname')) {
$q->orWhere('family', '<>', $request->get('familyname'));
}
});
})
->when($request->get('accountname'), function ($query, $val) use ($request) {
$query->whereHas('account', function ($q) use ($val, $request) {
$q->where('account_name', $val);
if ($request->has('city')) {
$q->orWhere('account_city', 'like', '%'.$request->get('city').'%');
}
});
})
->get();
}
在请求中未提供任何GET
参数时,此函数将返回所有联系人。如果存在username
的参数,它将仅返回存在给定名称用户的联系人。如果还存在一个familyname
参数,它将与用户名或姓氏与给定的用户名或姓氏匹配的用户进行联系。帐户,帐户名和城市也是如此。
尤其是,此示例有两点有趣:
when($value, $callback)
函数可用于构建非常动态的查询,仅在$callback
为true时才执行$value
。如果您使用$request->get('something')
并且something
不能用作参数,则该函数将返回null
并且不执行回调。回调本身的格式为function ($query, $value) { ... }
,其中$value
是您作为第一个参数传递给when()
的变量。$request->has('something')
来动态构建查询约束是when()
的替代方法。我仅出于演示目的添加了它-通常,我建议坚持一种样式。如果继续扩展示例,还可以构建高度动态的查询,其中不仅将诸如姓氏的Doe
之类的变量内容作为参数,而且还提供诸如=
之类的比较器, <>
或like
。但是,对于这个问题,进一步扩展该主题实在太多了,无论如何,已经有关于此主题的教程。
编辑:这是带有更详细输入的动态查询示例
预期的输入(与您的请求略有不同,因为您的请求无法正常工作):
$filters = [
'user' => [
['name','like','%Jhone%'],
['family','<>','Doe'],
],
'account' => [
['account_name','=','test_account'],
['account_city','like','%test_city%'],
]
];
函数:
public function getContacts(Request $request, array $filters)
{
$query = Contact::query();
foreach ($filters as $key => $constraints) {
$query->whereHas($key, function ($q) use ($constraints) {
if (count($constraints) > 0) {
$q->where($constraints[0][0], $constraints[0][1], $constraints[0][2]);
}
for ($i = 1; $i < count($constraints); $i++) {
$q->orWhere($constraints[$i][0], $constraints[$i][1], $constraints[$i][2]);
}
});
}
return $query->get();
}
这将始终将OR
用于多个约束,而不是AND
。混合使用AND
和OR
将需要更复杂的系统。