Пример фильтрации товаров

10 ноября 2016, 10:26

miniShop2 умеет работать с любыми столбцами таблицы свойств товара, а mSearch2 умеет получать любые столбцы из таблиц и генерировать по ним фильтры.

Давайте соединим эти 2 возможности, и напишем фильтр по наличию товара. Заодно научимся добавлять собственные поля в товар и строить по нему необычный фильтр.

Расширение свойств товара: новое поле availability

Первым делом читаем про расширение товаров miniShop2.

Затем создаём в таблице msProductData новую колонку availability INT(10).

Добавляем новое поле в модель товара:

<?php
// Файл /core/components/minishop2/plugins/availability/model/msproductdata.map.inc.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/msproductdata.js
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'}}
        }
    }
};

Связываем это вместе индексным файлом, который включит плагин:

<?php
// /core/components/minishop2/plugins/availability/index.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 массива:

  • Поле availability
  • Поле availability > 0

То есть, все товары делим на группы "в наличии" и "отсутствуют".

Пишем методы 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 и получаем нужный нам фильтр:

Конечно, можно оформить это чекбоксами, поменять текст в словарях и т.д. Принцип останется прежним.


Наверх, в раздел
Расширение
Следующий документ
Методы фильтрации