Поиск по магазину VM или как найти вчерашний день.

Угораздило меня однажды на один из подопечных сайтов (основанный на движке Joomla) прикрутить электронный магазин VirtueMart версии 2.6.0. Потом меня попросили изменить вывод списка товаров и прочие «фенечки-рюшечки». Ну и я отказываться не стал взял да и изменил скрипты, причём ничего не задокументировал (а менял там много всего). Народ остался доволен, а я как водица «сделал и забыл». Время шло. В какой-то момент народишко мой обнаружил, что на сайте не работает поиск по каталогу товаров. Точнее он работает, но ищет везде кроме «магазина». Опять я засел за этот несчастный сайт.

Первым делом было выяснено что стандартный поиск Jooml-ы для магазина не годится. Но это вопрос, как показалось, легко поправимый ибо у VirtueMart-а есть свой плагин поиска — «VM — Search in Shop». Включил я его и понял, что всё в этой жизни не так просто. Поиск как ничего не искал раньше так и продолжил ничего не искать. Сразу же вспомнилась фраза из кинофильма «Константин»: «Всегда есть какой-то подвох». Тем более выяснилось, что данная версия движка оказалась глючной и надо бы её обновить, но не тут то было. Как я уже упомянул я кучу всего правил в движке и ничего не задокументировал, потому простой путь для меня был закрыт.

Принялся думать дальше. Поиски в сети ничего не дали и, если честно, меня даже утомили, ибо по этой тематике материала немерено, а вот то что нужно нет. Плюнул и предпринял «финт ушами» — полез в движок ручками. День потратил на поиски того что происходит после того как пользователь решил что-то найти на сайте.  После третьего вскипания мозга я наконец упёрся в то место «где собака порылась». Оно оказалось в файле ./administrator/components/com_virtuemart/modules/product.php, точнее сказать в одной из функций которую он содержит под названием sortSearchListQuery. Это собственно та самая функция которая отвечает за поиск по каталогу магазина. Её изучение тоже заняло некоторое время и в конечном итоге дало свой плоды. Оно привело меня к $this -> valid_search_fields. Это не что иное как свойство объекта MartModulProduct (в данном случае псевдоним this подразумевает именно его), имеющее тип массив строк и содержащее имена полей поиска.

Должен вернуться немного назад, чтобы рассказать о том как нашёл в чём собственно состоит ошибка. У упомянутого VirtueMart-а есть свои логи и вот в одном из них я нашёл постоянные жалобы о плохом запросе и сообщения, что о недоступном поле product_name. Проанализировал запрос и покопался в базе данных. Выяснил, что поле product_name почему-то оказалось в таблице joomla_virtuemart_products вместо таблицы joomla_virtuemart_products_ru_ru, на которую опирается поиск да и как я понял должен опираться весь движок (но почему-то это не так, причём дело не в моих предыдущих правках). Посмотрев ещё маленько на поисковый запрос понял, что в нём должно быть обращение к p.product_name где алиас p указывает на «новую» таблицу. Стало понятно, что необходимо вклиниться в процесс формирования запроса и сделать так, чтобы на выходе тот оказался правильным. А ещё лучше отрегулировать настройки, но это увы мне не удалось (я просто их не нашёл), потому пошёл по пути правки процесса формирования запроса. Согласен вариант не лучший, но рабочий.

Вернёмся к редактированию функции sortSearchListQuery. Как я уже сказал она использует для получения полей поиска свойство valid_search_fields. Нас интересует его нулевой элемент, именно в нём содержится наше «неправильное» поле.

Ещё одно небольшое отступление: в процессе изучения функции было выяснено, что значение в указанном массиве должно быть не p.product_name а `p`.product_name (символ ` — это не апостроф а символ находящийся на одной кнопке с «тильдой» и буквой ё), и именно так иначе в процессе разных преобразований и передаче значений между переменными получается то же самое, что было до исправления т.е. «неправильный» запрос.

Итак для того, чтобы завершить наш «мерзкий и коварный план взлома запроса», необходимо разместить конструкцию $this->valid_search_fields[0] = ‘`p`.product_name’ внутри функции sortSearchListQuery упомянутого скрипта. Я не увидел для этого лучшего места чем перед циклом который отправляет этот массив дальше по цепочке переменных. Если быть точным то непосредственно перед строкой: foreach($this->valid_search_fields as $searchField). Таким образом задуманный «мерзкий план» был осуществлён и поиск заработал так как нужно.

P.S. Описанный случай касается ситуации когда поиск происходит по множеству полей включающему в себя поле «Название товара» (product_name) иначе все эти изменения бессмысленны. Список включённых для поиска полей можно найти зайдя в админку сайта, выбрав в меню Настройки VirtueMart и пройдя по пути Настройки -> Вкладка «Настройки сортировки» -> группа «доступные поля для поиска», там же этот список можно и изменить.

P.S.S. Я описал случай для версии 2.6.0 магазина VirtueMart, на другой версии возможно всё совсем иначе, а скорее всего этой ошибки нет вообще.

UPD.: Как водиться: «Хорошая мысля приходи апасля». Во избежание того, что вдруг кто-то исключил поле product_name из множества полей поиска и для добавления, тем самым, гибкости скрипту, лучше использовать конструкцию:

if (strcmp($this->valid_search_fields[0], 'product_name')
{
$this->valid_search_fields[0] = '`p`.product_name';
}

вместо:

$this->valid_search_fields[0] = '`p`.product_name';

Запись опубликована в рубрике Joomla с метками , , , . Добавьте в закладки постоянную ссылку.

Добавить комментарий