动态查询laravel雄辩与whereHas

时间:2018-06-23 06:50:24

标签: php laravel laravel-5 eloquent dynamicquery

我想创建动态过滤器。
例如我要创建此代码

$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();

,所有参数都是可变的 namelike%Jhone%family<>Doe,..... 我想将变量传递给函数,并在上面的查询中创建函数。

1 个答案:

答案 0 :(得分:1)

我假设您的ContactUserAccount模型中的关系函数是用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。混合使用ANDOR将需要更复杂的系统。