[tvSuperSelect] Кейс. Удобное указание опций для фильтрации в mFilter2


Часто интернет магазину требуется большое кол-во разделов каталога (500) и такое же большое кол-во опций (200). Заказчик хочет, чтобы:
— опции можно было легко выбирать при редактировании категории товаров,
— на фронте, если у категории не выбрано ни одной опции, брать эти опции из родительской категории, у которой они указаны.
С tvSuperSelect теперь сделать это не так уж сложно, как может показаться.

Подготовка
Нам потребуется miniShop2, mSearch2, tvSuperSelect, Fenom.
И даже не просите меня помочь сделать это без Fenom!

Шаг 1
Создаём ТВ поле mfilter_options с типом tvSuperSelect и указываем такие настройки:
  • Connector URL
    /assets/custom/tvssconnector.php
  • Процессор
    tvss/getms2options
Шаг 2
Создаём файл-коннектор.
<?php
require_once dirname(dirname(dirname(__FILE__))) . '/config.core.php';
require_once MODX_CORE_PATH . 'config/' . MODX_CONFIG_KEY . '.inc.php';
require_once MODX_CONNECTORS_PATH . 'index.php';
$modx->request->handleRequest(array(
    'processors_path' => MODX_CORE_PATH . 'custom/processors/',
    'location' => '',
));
Местонахождение: /assets/custom/tvssconnector.php

Шаг 3
Создаём процессор, в котором будет происходить выборка опций miniShop2 и формирование массива для отображения в списке ComboBox.
<?php
class customTvssComboGetMs2OptionsProcessor extends modObjectProcessor
{
    public $classKey = 'msOption';
    /** @var miniShop2 $ms2 */
    protected $ms2;
    /** @var tvSuperSelect $tvss */
    protected $tvss;

    /**
     * @return bool
     */
    public function initialize()
    {
        $this->ms2 = $this->modx->getService('minishop2', 'miniShop2', MODX_CORE_PATH . 'components/minishop2/model/minishop2/');
        $this->tvss = $this->modx->getService('tvsuperselect', 'tvSuperSelect',
            $this->modx->getOption('tvsuperselect_core_path', null, MODX_CORE_PATH . 'components/tvsuperselect/') . 'model/tvsuperselect/');

        return parent::initialize();
    }

    /**
     * @return string
     */
    public function process()
    {
        $query = trim($this->getProperty('query'));
        $limit = (int)$this->getProperty('limit', 0);
        $resource_id = (int)$this->getProperty('resource_id', 0);
        if (!$tv_id = (int)$this->getProperty('tv_id', 0)) {
            //
        }
        $q = $this->modx->newQuery($this->classKey);
        $q->select(array(
            "{$this->classKey}.key as `key`",
            "{$this->classKey}.caption as `caption`",
        ));
        if (!empty($query)) {
            $q->where(array(
                "{$this->classKey}.key:LIKE" => "%{$query}%",
                "OR:{$this->classKey}.caption:LIKE" => "%{$query}%"
            ));
        }
        $q->limit($limit);
        $q->sortby($this->classKey . '.key', 'ASC');
        
        $rows = array();
        if ($q->prepare() && $q->stmt->execute()) {
            if ($tmp = $q->stmt->fetchAll(PDO::FETCH_ASSOC)) {
                foreach ($tmp as $v) {
                    $rows[] = array(
                        'display' => '(' . $v['key'] . ') <b>' . $v['caption'] . '</b>',
                        'value' => $v['key'],
                    );
                }
            }
        }
        foreach ($rows as &$row) {
            if (empty($row['display'])) {
                $row['display'] = $row['value'];
            }
        }
        unset($row);

        return $this->outputArray($rows);
    }
}

return 'customTvssComboGetMs2OptionsProcessor';
Местонахождение: /core/custom/processors/tvss/getms2options.class.php

Шаг 4
Формирование списка опций пригодного для mFilter2 и вывод на фронте будет происходить при помощи Fenom.
У вас должно получиться, что-то вроде этого:
{var $filters = []}

{* Мы можем указать свойства фильтра, которые отобразятся до опций, выбранных нами *}
{var $filters[] = 'ms|price:number'}
{var $filters[] = 'parent:categories'}

{* Магия *}
{var $mfilter_options = $_modx->resource['mfilter_options']}
{if !is_array($mfilter_options)}
    {var $mfilter_options = ($mfilter_options | fromJSON)}
{/if}
{if $mfilter_options is empty}
    {foreach $_modx->getParentIds($_modx->resource['id']) as $parent_id}
        {if $parent_id == 0}
            {continue}
        {/if}
        {var $mfilter_options = ($parent_id | resource : 'mfilter_options')}
        {if !is_array($mfilter_options) AND $mfilter_options?}
            {var $mfilter_options = ($mfilter_options | fromJSON)}
        {/if}
        {if $mfilter_options?}
            {break}
        {/if}
        {unset $mfilter_options}
    {/foreach}
{/if}
{if $mfilter_options?}
    {foreach $mfilter_options as $v}
        {var $filters[] = ('msoption|' ~ $v)}
    {/foreach}
{/if}

{* Вывод mFilter2 *}
{'!mFilter2' | snippet : [
    ...
    'filters' => ($filters | join : ','),
    ...
]}

Итого
Как видите, всё довольно просто с новой версией tvSuperSelect. С этим функционалом теперь можно и не такое сделать!
Павел Гвоздь
20 сентября 2018, 11:07
16
306
+18

Комментарии: 5

Олег
20 сентября 2018, 11:27
+1
Павел, спасибо за примеры! Отличное дополнение
Дмитрий
20 сентября 2018, 12:18
+1
Годный кейс, спасибо!
Aleksandr Huz
20 сентября 2018, 20:14
0
Паша, за примеры, ОГРОМНОЕ спасибо.

Очень хочется, чтобы поле работало в migx таблице.