[tvSuperSelect] 1.2.2 Кастомайз по полной программе!


Новый функционал позволяет навесить свой процессор на получение значений для любого ТВ с типом tvSuperSelect. Теперь мы можем вывести абсолютно любые значения в этом ТВ, которые передадим через наш процессор. Предлагаю рассмотреть подробнее, как это делается и что это нам даст.

Что это даёт


  • Можно выдавать любые значения на выбор. Например, список ресурсов или опции miniShop2.
  • Можно ограничить пользователя только значениями из нашего списка, не давая добавить ничего нового.

Кейс


Допустим, нам нужно вывести список ресурсов в ТВ поле, чтобы менеджер мог выбрать несколько из них. Выглядеть это дело у нас будет вот так:


Шаг 1
Создаём ТВ поле с типом tvSuperSelect и указываем такие настройки:
  • Connector URL
    /assets/custom/tvssconnector.php
  • Процессор
    tvss/getresources
Шаг 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
Создаём процессор, в котором будет происходить вся магия выборка ресурсов и формирование массива для отображения в списке ComboBox.
<?php
class customTvssComboGetResourcesProcessor extends modObjectGetListProcessor
{
    public $classKey = 'modResource';
    public $languageTopics = array('resource');
    public $defaultSortField = 'menuindex';
    public $defaultSortDirection = 'ASC';

    /**
     * @param xPDOQuery $c
     *
     * @return xPDOQuery
     */
    public function prepareQueryBeforeCount(xPDOQuery $c)
    {
        if ($context_key = $this->getProperty('context_key')) {
            $c->where(array('context_key' => $context_key));
        }
        if ($resource_id = (int)$this->getProperty('resource_id', 0)) {
            $c->where(array('id:!=' => $resource_id));
        }
        if ($query = trim($this->getProperty('query'))) {
            $c->where(array(
                'id:LIKE' => "{$query}%",
                'OR:pagetitle:LIKE' => "%{$query}%",
                'OR:longtitle:LIKE' => "%{$query}%",
            ));
        }

        return $c;
    }

    /**
     * @param xPDOObject $obj
     *
     * @return array
     */
    public function prepareRow(xPDOObject $obj)
    {
        $array = $obj->toArray();
        $array['parents'] = array();
        $parents = $this->modx->getParentIds($array['id'], 4, array('context' => $array['context_key']));
        if ($parents[count($parents) - 1] == 0) {
            unset($parents[count($parents) - 1]);
        }
        if (!empty($parents) && is_array($parents)) {
            $q = $this->modx->newQuery($this->classKey, array('id:IN' => $parents));
            $q->select('id,pagetitle');
            if ($q->prepare() && $q->stmt->execute()) {
                while ($row = $q->stmt->fetch(PDO::FETCH_ASSOC)) {
                    $key = array_search($row['id'], $parents);
                    if ($key !== false) {
                        $parents[$key] = $row['pagetitle'];
                    }
                }
            }
            $array['parents'] = array_reverse($parents);
        }
        unset($parents, $q, $row, $key);
        
        $data = array(
            'display' => "<div><small>({$array['id']})</small> <b>{$array['pagetitle']}</b></div>",
            'value' => $array['id'],
        );
        if (!empty($array['parents'])) {
            $data['display'] = '<div class="parents"><small>' . join(' / ', $array['parents']) . '</small></div>' . $data['display'];
        }

        return $data;
    }
}

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

Итого
Вот и всё! На фронте у нас будет список ресурсов в виде JSON массива, который мы сможем декодировать и делать с ними всё, что угодно!
{var $resources = ($_modx->resource['our_tv'] | fromJSON)}
{foreach $resources as $v}
    {$v | resource : 'pagetitle'}
{/foreach}
Павел Гвоздь
13 сентября 2018, 10:54
modx.pro
20
2 963
+23
Поблагодарить автора Отправить деньги

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

Aleksandr Huz
13 сентября 2018, 13:00
+1
Очень круто.
Отдельное спасибо за примеры.
    Sergey Leleko
    13 сентября 2018, 15:33
    +1
    Очень крутое обновление! Спасибо большое!
    Хоть я только недавно познакомился с этим компонентом, но очень нравится. А тут еще и обновление такое! Еще раз спасибо Павел!
      Pavel Zarubin
      15 сентября 2018, 14:49
      +1
      А чем это отличается от @EVAL $modx->runSnippet в обычном множественном выборе тв? Я не ерничаю, просто интересно
        Павел Гвоздь
        15 сентября 2018, 15:38
        0
        Не знаю, я его не использовал. Вообще не знал о существовании оного. :)
        У меня tvSuperSelect много где используется, поэтому реализовал этот функционал для него.
          Владимир
          18 января 2019, 06:02
          0
          Как сделать выборку из определённого родителя?
          Aleksandr Huz
          15 сентября 2018, 15:42
          0
          я вижу только одно отличие, что можно еще добавлять свои произвольные значения на ходу.

          но, если
          Можно ограничить пользователя только значениями из нашего списка, не давая добавить ничего нового
          то тогда нет отличий.
            Pavel Zarubin
            15 сентября 2018, 18:06
            +1
            Понятно, спасибо!
              Илья Уткин
              16 сентября 2018, 11:31
              +2
              Блин, как так нет отличий — даже обидно за автора такого полезного дополнения.

              Основное преимущество tvSuperSelect в том, что теги хранятся в отдельной таблице — при выборке не нужно использовать LIKE и городить всякие велосипеды.

              mngatoff
              15 сентября 2018, 18:16
              +1
              отличие в способе хранения данных, и это важное отличие на мой взгляд. в обычном тв строка с разделителями, а тут json-массив
                mngatoff
                15 сентября 2018, 18:18
                0
                ну и плюс @EVAL это 1. костыль и 2. небезопасно. а тут всё по феншую, через коннектор
                  Aleksandr Huz
                  16 сентября 2018, 11:20
                  +1
                  Кстати, в MODX3 @EVAL будет удален, поэтому tvSuperSelect будет более востребован.
                  Андрей Минаков
                  18 ноября 2020, 15:29
                  0
                  Представленный пример почему-то отказывается работать в modx 2.8.1.

                  Не сталкивался ли кто-то еще с подобной проблемой?
                    Андрей Минаков
                    19 ноября 2020, 17:08
                    0
                    Забыл добавить: версия компонента 1.3.1-beta.
                    Голову сломал: код, очевидно, рабочий, но поле выбора не загружается.
                      Павел Гвоздь
                      19 ноября 2020, 18:23
                      0
                      Только в 2.8.1? Что в логах PHP? Что в консоли браузера?
                        Андрей Минаков
                        20 ноября 2020, 11:11
                        0
                        На другие сборки не ставил, просто тестировал фичу.
                        Консоль браузера:
                        ext-base.js:21 POST http://censored/assets/custom/tvssconnector.php 404 (Not Found)
                        modx.window.js:100 Uncaught TypeError: Cannot read property 'removeClass' of undefined
                            at S.onHide (modx.window.js:100)
                            at S.afterHide (ext-all.js:21)
                            at S.hide (ext-all.js:21)
                            at Object.hide (ext-all.js:21)
                            at Object.show (ext-all.js:21)
                            at MODx.onAjaxException (modx.js?v=10320b99:122)
                            at h.Event.fire (ext-all.js:21)
                            at Ext.data.Connection.fireEvent (ext-all.js:21)
                            at Ext.data.Connection.handleFailure (ext-all.js:21)
                            at f (ext-base.js:21)
                        Журнал ошибок пуст.

                        UPD. Адреса — как в примере. Сборка локальная. Прочая функциональность компонента — выше всяких похвал.
                          Андрей Минаков
                          20 ноября 2020, 13:31
                          0
                          UPD. Та же ошибка воспроизводится на чистой установке Modhost.
                          Андрей Минаков
                          20 ноября 2020, 18:24
                          0
                          Решение: проверить и выставить разрешения вновь создаваемых папок в assets/ (что вытекает из наличия 404 в логах при достоверно правильных путях, и что я сразу не...).
                          Очевидно, в новых версиях Modx, разрешения при создании папок не наследуются.

                          P.S. Извините за беспокойство, Павел. И спасибо за компонент.
                            Андрей Минаков
                            20 ноября 2020, 18:35
                            0
                            P.P.S. Кстати, любопытно, что на локальной сборке проблема воспроизводится и с верными правами. В любом случае, это проблема настройки разрешений, а не компонента.
                      Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
                      18