Skip to content
  1. Компоненты
  2. mSearch2
  3. Расширение
  4. Пример фильтрации товаров

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

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

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

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

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

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

Добавляем новое поле в модель товара по пути: /core/components/minishop2/plugins/availability/model/

php
<?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/

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'}}
    }
  }
};

Связываем это вместе индексным файлом, который включит плагин по пути: /core/components/minishop2/plugins/availability/

php
<?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.

То есть, включить мы его можем очень просто:

modx
[[!mFilter?
  &filters=`ms|availability:availability`
]]

Только это выведет нам чекбоксы, где будут указаны цифрами разные варианты наличия товаров. 0, 5, 10 и т.д. Слайдер с диапазоном цен тут тоже не подходит, явно просится радиокнопка.

modx
[[!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
<?php
class myCustomFilter extends mse2FiltersHandler {}

Указываем его в системной настройке mse2_filters_handler_class.

С этого момента mSearch2 использует для работы ваш класс фильтрации, в котором вы можете писать новые методы, или переопределять стандартные.

Для получения данных используются методы getИмяМетодаValues(), для подготовки фильтра — buildИмяМетодаFilter(), а для фильтрации filterИмяМетода. Можно посмотреть, как работают эти 3 типа методов в filters.class.php.

Добавляем новый фильтр availability

Нам нужно написать свои методы подготовки и фильтрации данных, чтобы разложить все товары 2 массива:

html
<ul>
  <li>Поле availability <= 0</li>
  <li>Поле availability > 0</li>
</ul>

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

Пишем методы buildAvailabilityFilter и filterAvailability:

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

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