Я хочу создавать динамические фильтры.
например я хочу создать этот код
$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
, …..
и я хочу передать переменные в функцию и функцию создать запрос выше.
Я предполагаю, что отношения функционируют внутри вашего Contact
, User
а также Account
модели написаны в 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
Параметры указаны по запросу. Если параметр для username
присутствует, он будет возвращать только те контакты, для которых существует пользователь с указанным именем. Если к тому же familyname
параметр присутствует, он даст контакты с пользователем, у которого совпадает имя пользователя или фамилия, отличная от указанной. То же самое относится к аккаунту, имени аккаунта и городу.
В частности, в этом примере есть две интересные вещи:
when($value, $callback)
Функция может быть использована для создания очень динамических запросов, которые выполняют только $callback
когда $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
Смешанный потребует гораздо более сложной системы.
Других решений пока нет …