Доработки магазина Simpla: сортировка товаров
Дата: 27 Фев ' 11 Автор: mart Рубрики: Программирование
Продолжаем модифицировать купленный нами за очень дорого магазин Симпла (http://simp.la). На сей раз добавим столько необходимый для магазина функционал, как сортировка товаров по цене и названию в обе стороны (по возрастанию и убыванию). Можно еще добавить в этот список сортировку по дате поступления, но поскольку это в большинстве случаев не публикуемые данные, то ограничимся наиболее популярным набором. Итак, поехали…
Те, у кого не было правок в классе Storefront (да и просто для примера вставки кода) могут скачать базовый класс Storefront с сортировкой. Далее же будет расписано что и как сделано по правкам.
Первым шагом стоит сделать выбор этой самой сортировки. Можно сделать либо списком, либо ссылками, что лично мне больше нравится, т.к. визуально понятнее.
<div class="order_by"> Сортировать по цене <a href="{if $category}catalog/{$category->url}/{elseif $brand}brands/{/if}{if $brand}{$brand->url}/{/if}{if $filter_params}{$filter_params}&{else}?{/if}order=price">возр</a> | <a href="{if $category}catalog/{$category->url}/{elseif $brand}brands/{/if}{if $brand}{$brand->url}/{/if}{if $filter_params}{$filter_params}&{else}?{/if}order=price_desc">убыв</a>, по названию <a href="{if $category}catalog/{$category->url}/{elseif $brand}brands/{/if}{if $brand}{$brand->url}/{/if}{if $filter_params}{$filter_params}&{else}?{/if}order=name">возр</a> | <a href="{if $category}catalog/{$category->url}/{elseif $brand}brands/{/if}{if $brand}{$brand->url}/{/if}{if $filter_params}{$filter_params}&{else}?{/if}order=name_desc">убыв</a></div> |
Теперь нам надо обработать входные параметры запроса на наличие признака сортировки и выполнить саму сортировку.
Открываем файл Storefront.class.php в корне сайта. Вознокла необходимость вынести отправку данных по фильтрам $this->smarty->assign(‘filter_params’, $this->form_get(array())); за пределы проверки свойств товара, а именно находим условие (примерно 144 строка).
if($properties = $this->db->results()) { ... } |
И в конце условия удаляем строку отправки данных. Вместо нее за пределами условия добавляем нашу расширенную конструкцию:
$extra_params = array(); if($this->add_param('order')) $extra_params['order'] = $this->param('order'); $this->smarty->assign('filter_params', $this->form_get($extra_params)); |
Дело в том, что разработчик предусмотрел возможности передачи дополнительных параметров в метод form_get, поэтому мы без проблем передадим данные по сортировки. Передача filter_params надо, например, для постраничной навигации. Правильнее было бы формировать для каждого типа фильтра свой URL через метод form_get ,т.к. возможно дублирование параметров с разными значениями, но это усложнит задачу из-за количества переменных, а на работу все-равно не повлияет — поэтому работаем по упрощенной схеме.
далее находим вызов списка товаров $this->get_products — по идее сразу после нашего нового кода параметров. И в конец вызова добавляем null, $this->param(‘order’), т.е. null — это значения для параметра hit и далее мы передаем еще 1 параметр в метод получения списка товаров с указанием типа сортировки. Должно получиться
$products = $this->get_products(null, (array)$category->category_id, isset($brand->brand_id)?$brand->brand_id:null, $start_item, $filter, NULL, $this->param('order')); |
Теперь правим сам метод get_products. Находим function get_products в районе 475 строки и заменяем объявление функции на
function get_products($ids = null, $categories = null, $brand_id = null, $start_item=null, $filter=null, $hit=null, $order = false) |
Т.е. мы тут получили наш параметр order и по-умолчанию присвоили ему false.
Теперь обработаем входные данные по сортировке и допишем наш запрос к базе. После объявления переменной $hit_filter добавим наш блок обработки
// Выбираем сортировку if($order) switch ($order) { case 'name_desc': $order_filter = "products.model DESC"; $variant = ""; break; case 'price': $order_filter = "products_variants.price"; $variant = " LEFT JOIN products_variants ON products_variants.product_id = products.product_id"; break; case 'price_desc': $order_filter = "products_variants.price DESC"; $variant = " LEFT JOIN products_variants ON products_variants.product_id = products.product_id"; break; default: $order_filter = is_null($hit) ? "products.model" : "rand(), products.model"; $variant = ""; } else { $order_filter = is_null($hit) ? "products.model" : "rand(), products.model"; $variant = ""; } |
Тут мы добавили 2 переменных:
- $order_filter — непосредственна сама сортировка
- $variant — по-умолчанию таблица вариантов у нас не подключена (а именно в ней хранятся цены), мы тоже будет ее подключать по мере необходимости. Это усложнит немного логику, но сэкономит процессорное время и следовательно и скорость загрузки страницы
Вот и добрались до самого интересного — самого запроса к базе товаров… Заменяем запрос после объявления переменной $category_filter на наш
$query = "SELECT products.product_id, products.url, products.category_id, products.brand_id, products.tara, products.model, products.description, products.body, products.hit, products.order_num, products.small_image, products.large_image, DATE_FORMAT(products.created, '%Y-%m-%d') as created, DATE_FORMAT(products.modified, '%Y-%m-%d') as modified, products.enabled, brands.name as brand, brands.url as brand_url, categories.single_name as category, categories.url as category_url, categories.image as category_image FROM products LEFT JOIN categories ON categories.category_id = products.category_id LEFT JOIN brands ON products.brand_id = brands.brand_id LEFT JOIN products_categories ON products.product_id = products_categories.product_id $variant WHERE categories.enabled=1 and products.enabled=1 $id_filter $category_filter $brand_filter $properties_filter $hit_filter GROUP BY products.product_id ORDER BY $order_filter $limit"; |
Вот и вся практическая магия.
Всегда рад помочь, особенно, если это вознаграждается 🙂 Всем удачи!
16 комментариев
-
Денис
28|Фев|2011 1отлично! давно хотел! блог супер!
как можно сделать подписку по email на ваш блог? -
Дмитрий
02|Мар|2011 2а вот у меня не сортирует 🙁
-
02|Мар|2011
3
Виноват, ошибся в переменной в шаблоне — надо не sortby=name, а order=name и т.д.
-
Виталий
16|Мар|2011 4А в каком шаблоне? У меня почему-то после изменений товар исчезает. Возможно я здесь что-то не так прописал?
if($properties = $this->db->results())
$extra_params = array();
if($this->add_param(‘order’)) $extra_params[‘order’] = $this->param(‘order’);
$this->smarty->assign(‘filter_params’, $this->form_get($extra_params)); -
Noxter
27|Мар|2011 5Все бы хорошо но сортировка работает глючно!
Если у товара 1-й вариант стоит 300$ а последний 500$, то при сортировке по возрастанию цены этот товар будет выводится между товарами по цене 400$ и 600$, и при этом отображать цену первого варианта, тобишь 300$.
Глюк 100% похожий глюк наблюдается здесь: http://simpla.com.ua/catalog/usb-gadgets поиграйтесь с сортировкой и обращайте внимание на цены, а также на вариации цен.
Скрин: http://piccy.info/view3/1284680/5cc01f517a053280f1000d63fa858fac/orig/
Март исправьте пожалуйста, и статью о «звездном рейтинге» тоже! -
11|Апр|2011
6
Сортировка по цене глючит, т.к. нет однозначного вариант. Для единичной связи товар-цена все работает корректно. Делать обработчик для мультивариантов большой гемморой как по запросам, так и по коду. Момент конечно неприятный, но это скорее уже не хак будет, а новый функционал и с ним стоит обратиться к разработчику движка.
-
e11e
28|Мар|2011 7Спасибо, работает, но…
если то одну, то другую сортировку выбрать в урле получается бред:
?order=price_desc&order=price
как будете исправлять?
заодно спрошу, как проверить в весьма урезанном в симпле smarty, вхождение в урл вот этой самой order=price к примеру.. (нужно для нормального оформления ссылок в шаблоне)
модификаторы strpos , substr, и php код запрещены… -
11|Апр|2011
8
Да, действительно есть накладка по параметра, но на второй странице она исчезает. Можно поступить как это сделано для самих параметров — написать метод генерации УРЛа, но я не стал заморачиваться — особой проблемы по этому поводу нету, а для поисковиков фильтры закрыты.
-
e11e
31|Мар|2011 9предыдущий свой вопрос решила, парсю $filter_params ))
а вот в брендах не работает сортировка по цене, т.е. когда сначала выбираешь бренд (а не в каталоге)… -
Noxter
12|Апр|2011 10Ну в общем как то так работает:
case ‘price’:
$order_filter = «pv.price»;
$variant = » LEFT JOIN (SELECT price, product_id FROM products_variants ORDER BY position) pv ON pv.product_id = products.product_id»;
break;
case ‘price_desc’:
$order_filter = «pv.price DESC»;
$variant = » LEFT JOIN (SELECT price, product_id FROM products_variants ORDER BY position) pv ON pv.product_id = products.product_id»; -
12|Апр|2011
11
Согласен, но без кеширования лучше не делать 🙂 Загнется!
-
Noxter
05|Май|2011 12Как кешировать?
-
Noxter
25|Июн|2011 13mart я проверил свой вариант по внутренним запросам с 8к позиций + множество вариантов этих позиций и ничего не загнулось!
Конечно же с кешированием было бы вообще замечательно, но увы я не знаю как сделать кеширование, даже представления не имею как оно работать должно! -
25|Июн|2011
14
Модуль кеширования скорее всего будет платным.
Да, Ваш запрос имеет право на жизнь, но я рассматриваю всегда на будущее. При достаточно большой нагрузке формирование страницы в 20-40 запросов — это уже нехорошо, так глядишь и до показателей Джумлы дойдет… -
Александр
13|Апр|2012 15Может кто-то подскажет — вот если реализовал эту сортировку — отсортировал по цене, но также реализована постраничная навигация в шаблоне, как сделать так чтобы при переключении странички сортировка по цене оставалась???
Заранее благодарен за помощь. -
Юрий
11|Май|2012 16Здравствуйте! А можно сделать, чтоб кроме выбора сортировки, по-умолчанию товары сразу стояли по возрастанию цены.