Intereting Posts
Что такое расширение пользовательского кэша APCu в PHP? Как предотвратить множественные экземпляры скрипта? ошибка при выходе из базы после расширения класса LogoutListener Можем ли мы принудительно завершить выполнение программы C через несколько секунд Отображение документов с Google Диска на веб-странице AWS SDK для PHP: ошибка получения учетных данных с сервера метаданных профиля экземпляра (mysql, php) Как получить значение поля auto_increment перед вставкой данных? Код возвращает последнее значение перед последним обновлением вместо последнего введенного значения? Как расширить и изменить модель поставщика в Laravel 5? Ошибка синтаксиса, неожиданный T_CONSTANT_ENCAPSED_STRING в PHP PHP XML Expat parser: как читать только часть документа XML? Looping PHP Nested Arrays – Извлечение значений в Blade Views (Laravel) Как получить объект Container из LifecycleEventArgs postLoad в Entity? Обновление дублирующего ключа – несколько столбцов Проблема с sonataIntlBundle – я не могу установить с композитором

Несколько запросов, использующих orWhere, в полях модели и связанных моделей

У меня много таблиц (с учетом пользователя, а не SQL) с фильтрами на столбе. Столбцы имеют не только поля таблиц, но и поля связанных моделей.

Я пытаюсь добавить функцию, в которой при фильтрации данных можно использовать запятую как разделитель ИЛИ. Мне нужно сделать это вообще, поскольку у меня довольно большое количество таблиц, полей и отношений. Кроме того, некоторые таблицы построены динамически.

Код, который добавляет предложения where для собственных полей моделей, таков:

foreach ($filters as $column => $filter) { $q->where(function ($q) use ($filter, $model, $column) { $first = array_pop($filter); $q->where("$model.$column", 'LIKE', "%$first%"); foreach ($filter as $or) { $q->orWhere("$model.$column", 'LIKE', "%$or%"); } }); } 

Это работает так, как ожидалось. При попытке сделать то же самое с полями отношений единственное различие заключается в использовании whereHas и в том числе модели:

 foreach ($filters as $column => $filter) { $q->whereHas($model, function ($q) use ($filter, $model, $column) { $first = array_pop($filter); $q->where("$model.$column", 'LIKE', "%$first%"); foreach ($filter as $or) { $q->orWhere("$model.$column", 'LIKE', "%$or%"); } }); } 

Проблема в том, что если я фильтрую поля отношений, это не работает должным образом. Я подозреваю, что это связано с whereHas с sub, где / илиWhere клаузулы. Это результат, который я получаю

 No filters: |------------+-----------------------------------+--------------------------------------| | Contact ID | Type (Field in contact SQL table) | Ecozone (Field in Ecozone SQL table) | |------------+-----------------------------------+--------------------------------------| | Filter -> | | | |------------+-----------------------------------+--------------------------------------| | 1 | Manager | Bush | | 2 | | Forest | | 3 | Worker | | |------------+-----------------------------------+--------------------------------------| Single filter on current model (correct): |------------+-----------------------------------+--------------------------------------| | Contact ID | Type (Field in contact SQL table) | Ecozone (Field in Ecozone SQL table) | |------------+-----------------------------------+--------------------------------------| | Filter -> | man | | |------------+-----------------------------------+--------------------------------------| | 1 | Manager | Bush | |------------+-----------------------------------+--------------------------------------| Multiple filter on current model (correct): |------------+-----------------------------------+--------------------------------------| | Contact ID | Type (Field in contact SQL table) | Ecozone (Field in Ecozone SQL table) | |------------+-----------------------------------+--------------------------------------| | Filter -> | man, wor | | |------------+-----------------------------------+--------------------------------------| | 1 | Manager | Bush | | 3 | Worker | | |------------+-----------------------------------+--------------------------------------| Single filter on related model field (correct): |------------+-----------------------------------+--------------------------------------| | Contact ID | Type (Field in contact SQL table) | Ecozone (Field in Ecozone SQL table) | |------------+-----------------------------------+--------------------------------------| | Filter -> | | bus | |------------+-----------------------------------+--------------------------------------| | 1 | Manager | Bush | |------------+-----------------------------------+--------------------------------------| Multiple filter on related model field (incorrect): |------------+-----------------------------------+--------------------------------------| | Contact ID | Type (Field in contact SQL table) | Ecozone (Field in Ecozone SQL table) | |------------+-----------------------------------+--------------------------------------| | Filter -> | | bus,for | |------------+-----------------------------------+--------------------------------------| | 1 | Manager | Bush | | 2 | | Forest | | 3 | Worker | | |------------+-----------------------------------+--------------------------------------| 

Целый путь кода ниже:

В контроллере:

 return Contacts::with( 'ecozone' )->where( function ($q) { $this->set_filters($q, 'contact'); })->paginate($count); 

В BaseController:

 protected function set_filters($q, $current_model) { $filters_array = $this->parse_filters(); if ($filters_array) { foreach($filters_array as $model => $filters) { if ($model == $current_model) { foreach($filters as $column => $filter) { $q->where(function ($q) use ($filter, $model, $column) { $first = array_pop($filter); $q->where("$model.$column", 'LIKE', "%$first%"); foreach($filter as $or) { $q->orWhere("$model.$column", 'LIKE', "%$or%"); } }); } } else { foreach($filters as $column => $filter) { $q->whereHas($model, function ($q) use ($filter, $model, $column) { $first = array_pop($filter); $q->where("$model.$column", 'LIKE', "%$first%"); foreach($filter as $or) { $q->orWhere("$model.$column", 'LIKE', "%$or%"); } }); } } } } } 

$ this-> фильтры:

 protected function parse_filters() { $filters = Input::get('filters'); $filters = json_decode($filters); $filters = array_where($filters, function($key, $value) { return !empty($value); }); $filters = (Array) $filters; $has_filters = !empty($filters); if ($has_filters) { $filters_array = []; foreach ($filters as $key => $value) { $value = explode(',', $value); array_set($filters_array, $key, $value); } } else { $filters_array = false; } return $filters_array; } 

И возвращает, что я считаю правильным, следующий массив. Первый уровень – это модель, вторая – поле, третье – разделенные запятой ИЛИ предложения

 Array ( [ecozone] => Array ( [ecozone] => Array ( [0] => bush [1] => forest ) ) [contact] => Array ( [contact_type] => Array ( [0] => manager [1] => worker ) ) ) 

Дамп SQL, используемый при фильтрации по текущим полям модели. Это работает так, как ожидалось:

 array (size=4) 0 => array (size=3) 'query' => string 'select count(*) as aggregate from `contact` where `contact`.`deleted_at` is null and ((`contact`.`physical_address` LIKE ? or `contact`.`physical_address` LIKE ?))' (length=163) 'bindings' => array (size=2) 0 => string '%add%' (length=5) 1 => string '%nana%' (length=6) 'time' => float 1.67 1 => array (size=3) 'query' => string 'select * from `contact` where `contact`.`deleted_at` is null and ((`contact`.`physical_address` LIKE ? or `contact`.`physical_address` LIKE ?)) limit 10 offset 0' (length=161) 'bindings' => array (size=2) 0 => string '%add%' (length=5) 1 => string '%nana%' (length=6) 'time' => float 0.91 2 => array (size=3) 'query' => string 'select * from `ecozone` where `ecozone`.`deleted_at` is null and `ecozone`.`id` in (?, ?)' (length=89) 'bindings' => array (size=2) 0 => string '1' (length=1) 1 => string '2' (length=1) 'time' => float 0.8 

Дамп SQL-запроса для фильтрации по связанным моделям. Это не работает должным образом:

 array (size=4) 0 => array (size=3) 'query' => string 'select count(*) as aggregate from `contact` where `contact`.`deleted_at` is null and ((select count(*) from `ecozone` where `ecozone`.`deleted_at` is null and `contact`.`ecozone_id` = `ecozone`.`id` and `ecozone`.`ecozone` LIKE ? or `ecozone`.`ecozone` LIKE ? and `ecozone`.`deleted_at` is null) >= 1)' (length=301) 'bindings' => array (size=2) 0 => string '%grass%' (length=7) 1 => string '%bush%' (length=6) 'time' => float 1.18 1 => array (size=3) 'query' => string 'select * from `contact` where `contact`.`deleted_at` is null and ((select count(*) from `ecozone` where `ecozone`.`deleted_at` is null and `contact`.`ecozone_id` = `ecozone`.`id` and `ecozone`.`ecozone` LIKE ? or `ecozone`.`ecozone` LIKE ? and `ecozone`.`deleted_at` is null) >= 1) limit 10 offset 0' (length=299) 'bindings' => array (size=2) 0 => string '%grass%' (length=7) 1 => string '%bush%' (length=6) 'time' => float 0.89 2 => array (size=3) 'query' => string 'select * from `ecozone` where `ecozone`.`deleted_at` is null and `ecozone`.`id` in (?, ?)' (length=89) 'bindings' => array (size=2) 0 => string '1' (length=1) 1 => string '2' (length=1) 'time' => float 1.38