动态查询 laravel eloquent with whereHas

dynamic query laravel eloquent with whereHas

我想创建动态过滤器。
例如我想创建这个代码

$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,..... 我想将变量传递给上面查询中创建的函数和函数。

我假设您的 ContactUserAccount 模型中的关系函数是用 camelCase 编写的,而不是像您的示例所示的 PascalCase .

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 参数,此函数将 return 所有联系人。如果存在 username 的参数,它只会 return 存在具有给定名称的用户的联系人。如果还存在 familyname 参数,它将提供与具有匹配用户名或姓氏的用户的联系方式。这同样适用于帐户、帐户名和城市。

这个例子有两点特别有趣:

  • when($value, $callback) 函数可用于构建非常动态的查询,仅在 $value 为真时才执行 $callback。如果您使用 $request->get('something') 并且 something 不可用作参数,则该函数将 return null 并且不会执行回调。回调本身具有 function ($query, $value) { ... } 形式,其中 $value 是您作为第一个参数传递给 when() 的变量。
  • 在查询构建器函数中使用 $request->has('something') 动态构建查询约束是 when() 的替代方法。我添加它只是为了演示目的 - 通常我会建议坚持一种风格。

如果你想扩展这个例子,你也可以构建高度动态的查询,其中不仅像 Doe 这样的姓氏的变量内容作为参数,而且像 [=33= 这样的比较器]、<>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 需要更复杂的系统。