Пример фильтрации товаров
miniShop2 умеет работать с любыми столбцами таблицы свойств товара, а mSearch2 умеет получать любые столбцы из таблиц и генерировать по ним фильтры.
Давайте соединим эти 2 возможности, и напишем фильтр по наличию товара. Заодно научимся добавлять собственные поля в товар и строить по нему необычный фильтр.
Расширение свойств товара: новое поле availability
Первым делом читаем про расширение товаров miniShop2.
Затем создаём в таблице msProductData новую колонку availability INT(10).
Добавляем новое поле в модель товара по пути: /core/components/minishop2/plugins/availability/model/
<?php
return array(
'fields' => array(
'availability' => 0
),
'fieldMeta' => array(
'availability' => array(
'dbtype' => 'integer',
'precision' => '10',
'phptype' => 'integer',
'null' => true,
'default' => 0
)
)
);
Добавляем виджеты ExtJS для этого поля в админку по пути: /assets/components/minishop2/plugins/availability/
miniShop2.plugin.pluginname = {
getFields: function (config) {
return {
availability: { xtype: 'numberfield', description: _('ms2_product_availability_help') }
}
},
getColumns: function () {
return {
availability: {width:50, sortable:true, editor: {xtype:'numberfield'}}
}
}
};
Связываем это вместе индексным файлом, который включит плагин по пути: /core/components/minishop2/plugins/availability/
<?php
//
return array(
'xpdo_meta_map' => array(
'msProductData' => require_once dirname(__FILE__) .'/model/msproductdata.map.inc.php'
),
'manager' => array(
'msProductData' => MODX_ASSETS_URL . 'components/minishop2/plugins/availability/msproductdata.js'
)
);
И добавляем запись в лексикон:
Тщательно чистим кэш и пробуем включить новое поле в настройках.
Если не получилось - внимательно повторяем вся заново. У меня заработало с первого раза:
Добавление фильтра по новому полю
Поле availability теперь точно такое же родное поле товара, как и price, weight и остальные поля msProductData.
То есть, включить мы его можем очень просто:
[[!mFilter?
&filters=`ms|availability:availability`
]]
Только это выведет нам чекбоксы, где будут указаны цифрами разные варианты наличия товаров. 0, 5, 10 и т.д. Слайдер с диапазоном цен тут тоже не подходит, явно просится радиокнопка.
[[!mFilter?
&filters=`ms|availability:availability`
&suggestionsRadio=`ms|availability`
&tplFilter.row.ms|availability=`tpl.mFilter2.filter.radio`
]]
Упс! Добавляем запись в словари mSearch2, чистим кэш и обновляем:
Прописываем наличие в товары, чистим кэш и видим вполне ожидаемую картину - столбик значений:
Нам нужно написать свой метод фильтрации, который будет выдавать: есть товар в наличии, или нет?
Расширяем класс фильтрации
Все стандартные фильтры mSearch2 находятся в файле /core/components/msearch2/model/msearch2/filters.class.php
. Нам нужно унаследовать его, расширить и указать новый класс в системных настройках.
Создаём новый файл в /core/components/msearch2/custom/filters/custom.class.php
и пишем в него:
<?php
class myCustomFilter extends mse2FiltersHandler {}
Указываем его в системной настройке mse2_filters_handler_class.
С этого момента mSearch2 использует для работы ваш класс фильтрации, в котором вы можете писать новые методы, или переопределять стандартные.
Для получения данных используются методы getИмяМетодаValues(), для подготовки фильтра — buildИмяМетодаFilter(), а для фильтрации filterИмяМетода. Можно посмотреть, как работают эти 3 типа методов в filters.class.php.
Добавляем новый фильтр availability
Нам нужно написать свои методы подготовки и фильтрации данных, чтобы разложить все товары 2 массива:
<ul>
<li>Поле availability <= 0</li>
<li>Поле availability > 0</li>
</ul>
То есть, все товары делим на группы "в наличии" и "отсутствуют".
Пишем методы buildAvailabilityFilter и filterAvailability:
<?php
class myCustomFilter extends mse2FiltersHandler {
// За образец берем стандартный buildBooleanFilter и немного его меняем
public function buildAvailabilityFilter(array $values) {
if (count($values) < 2 && empty($this->config['showEmptyFilters'])) {
return array();
}
$results = array();
foreach ($values as $value => $ids) {
$title = ($value <= 0)
? $this->modx->lexicon('mse2_filter_availability_no')
: $this->modx->lexicon('mse2_filter_availability_yes');
$value = $value <= 0 ? '0' : '1';
if (!isset($results[$value])) {
$results[$value] = array(
'title' => $title
,'value' => $value
,'type' => 'availability'
,'resource' => array()
);
}
foreach ($ids as $id) {
$results[$value]['resources'][] = $id;
}
}
ksort($results);
return $results;
}
// Собственно фильтрация, берём за основу filterNumber
public function filterAvailability(array $requested, array $values, array $ids) {
$matched = array();
$value = $requested[0];
$tmp = array_flip($ids);
foreach ($values as $number => $resources) {
if ($value && $number > 0) {
foreach ($resources as $id) {
if (isset($tmp[$id])) {
$matched[] = $id;
}
}
}
elseif (!$value && $number <= 0) {
foreach ($resources as $id) {
if (isset($tmp[$id])) {
$matched[] = $id;
}
}
}
}
return $matched;
}
}
Добавляем в лексикон записи mse2_filter_availability_no и mse2_filter_availability_yes и получаем нужный нам фильтр:
Конечно, можно оформить это чекбоксами, поменять текст в словарях и т.д. Принцип останется прежним.