Opencart, OcStore: Умный фильтр и поиск
Запуская интернет магазин, столкнулся с проблемой при которой фильтр товаров не отрабатывал на подстроку, которая начинается не с первого символа. Исправил в своей версии, получилось удобно. Решил запилить про это пост-заметку, чтобы в будущем использовать и в других местах..
Итак, начнем с описания проблемы:
- Заходим в админку и создаем товар, с названием Test12345
- Пробуем вбить в фильтр в поле имени: Test - видим наш товар
- Пробуем вбить в фильтр в поле имени: t123 - не видим наш товар
Смотрим исходник контроллера: /admin/controller/catalog/product.php
там видим, что запрос передается в модель: /admin/model/catalog/product.php
открываем её и видим что запрос формируется таким образом:
1 2 3 4 5 6 7 |
public function getProducts($data = array()) { ... $sql .= " AND p.model LIKE '" . $this->db->escape($data['filter_name'])."%'"; ... } |
Как видим фильтр позволяет опускать только последнюю часть. Сделанно так неспроста и связанно это с тем как mysql обрабатывает запросы, а точнее с производительностью. Вдаваться в подробности не буду, пост не про это. Кому интересно читайте в справке mysql о том как работает LIKE оператор.
Что же делать, ведь всё же хочется иногда искать по выражению %Condition% - все просто, добавим условный оператор в запрос, при наличии которого будет искать по %Condition%, а во всех остальных случаях, по оригинальному Condition%. В качестве такого оператора, я выбрал знак восклицания. Меняем код так :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public function getProducts($data = array()) { ... if (!empty($data['filter_name'])) { $searchCondition = $this->db->escape($data['filter_name']).'%'; if (!empty($data['filter_name'][0]) && $data['filter_name'][0]=='!') { $data['filter_name'] = trim(substr($data['filter_name'],1)); $searchCondition = '%'.$this->db->escape($data['filter_name']).'%'; } $sql .= " AND pd.name LIKE '" .$searchCondition. "'"; ... } |
Проверяем:
- Заходим в админку и создаем товар, с названием Test12345
- Пробуем вбить в фильтр в поле имени: Test - видим наш товар
- Пробуем вбить в фильтр в поле имени: t123 - не видим наш товар
- Пробуем вбить в фильтр в поле имени: ! t123 - видим наш товар
Аналогично меняем код для фильтра по модели товара:
1 2 3 4 5 6 7 8 9 10 11 |
if (!empty($data['filter_model'])) { $searchCondition = $this->db->escape($data['filter_model']).'%'; if (!empty($data['filter_model'][0]) && $data['filter_model'][0]=='!') { $data['filter_model'] = trim(substr($data['filter_model'],1)); $searchCondition = '%'.$this->db->escape($data['filter_model']).'%'; } $sql .= " AND p.model LIKE '" . $searchCondition . "'"; } |
Таким образом мы убили двух зайцев: сохранили старый функционал и добавили новый который не изменяет поведение старого.
Author: | Tags: /
| Rating:
Leave a Reply