Процессоры в MODX

В MODX есть файлы-процессоры, это php скрипты, которые выполняют определенные функции. Загляните в /core/model/modx/processors, и вы увидите, как их много.

Работать с процессорами можно из любого сниппета или плагина при помощи метода runProcessor:
$response = $modx->runProcessor('action/path/to/processor',$arrayOfProperties,$otherOptions);
В ответ мы получаем объект modProcessorResponse, со всеми его методами.

Стандартные процессоры


К примеру, в директории security есть процессоры login и logout, которые управляют авторизацией юзеров. Вот как мы можем авторизовать юзера:
$username = 'bezumkin';
$password = '*********';
$data = array(
    'username' => $username,
    'password' => $password,
    'rememberme' => 1,
    'login_context' => 'web',
);    
$response = $modx->runProcessor('/security/login', $data);
if ($response->isError()) {
    $modx->log(modX::LOG_LEVEL_ERROR, 'login error. Username: '.$username.', Message: '.$response->getMessage());
}
Выход с сайта и того проще:
$response = $modx->runProcessor('/security/logout');
if ($response->isError()) {
    $modx->log(modX::LOG_LEVEL_ERROR, 'Logout error. Username: '.$modx->user->get('username').', uid: '.$modx->user->get('id').'. Message: '.$response->getMessage());
}
Именно так и сделана авторизация в моем компоненте Loginza.
Это очень удобно и гарантирует, что компонент будет работать во всех версиях MODX. Поэтому, если возможно, всегда нужно использовать стандартные процессоры.

Конечно, стандартные процессоры не умеют работать с вашими расширениями.

Собственные процессоры


Использование своих процессоров отличается от стандартных только тем, что нужно указать директорию, откуда их брать. Смотрим пример из miniShop:
// Массив, который мы передадим в процессор, там его ловить в $scriptProperties
$processorProps = array(
    'id' => 55
);
// Массив опций для метода runProcessor
$otherProps = array(
    // Здесь указываем где лежат наши процессоры
    'processors_path' => $modx->getOption('core_path') . 'components/minishop/processors/'
);
// Запускаем
$response = $modx->runProcessor('web/orders/getlist', $processorProps, $otherProps);
// И возвращаем ответ от процессора
return $response->response;
Это чуть измененный пример из сниппета miniShop, где он обрабатывает запросы личного кабинета.

Как вы видите, процессор для запуска указывается без расширения, путем от директории процессоров. Если мы не указываем свою директорию, то это будет /core/model/modx/processors/, по умолчанию. В моем примере — мы ее меняем на директории внутри компонента miniShop.

Стандартный процессор внутри собственного


Вот и сладкое! Смотрим пример:
$response = $modx->runProcessor('resource/create', $_POST);
if ($response->isError()) {
    return $modx->error->failure($response->getMessage());
}

$id = $response->response['object']['id'];
В этом примере мы создаем стандартным процессором новый ресурс из присланных данных, и получаем из ответа id этого ресурса, для дальнейшей работы. Потом уже мой процессор добавляет свойства товара к этому ресурсу.
Вот исходный код всего процессора miniShop для создания нового товара.

При таком подходе, опять же, мы гарантируем, что независимо от будущих изменений в MODX наш процессор будет работать во всех версиях. И, что очень важно, будет работать плагины, которые должны работать при создании новых ресурсов. Также будет сгенерирован alias (если вы их используете), причем как это указано в настройках, через транслитерацию, или нет.
Таким же образом работает и обновление товаров, а другой мой компонент mSearch, ловит событие OnDocFormSave и индексирует этот ресурс.

Конечно, можно не использовать в таких случаях runProcessor, а работать через newObject — но тогда нужно самостоятельно генерировать события для плагинов, определять незаданные поля нового ресурса, генерировать alias и еще много чего.
Зачем, если авторы MODX все для нас уже предусмотрели?

Заключение


Процессоры — отличная вещь и нужно использовать их по-максимуму, везде, во всех своих сниппетах. Если вы хотите сделать что-то с ресурсом или другим элементом — посмотрите, нет ли для этого готового процессора в системе?
Если есть — используйте его. Это оградит вас от лишней головной боли, и позволит другим расширениям и плагинам взаимодействовать с вашим кодом. Кстати, так и писать выходит меньше — запустил runProcessor, получил ответ и делай, что хочешь.
Василий Наумкин
20 июня 2012, 04:13
modx.pro
24
16 874
0

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

20 июня 2012, 09:37
0
Перевод нужен. Сам все никак не сяду перевести. Новые процессоры на классах основаны и работают на самом деле очень круто, так как унаследовал класс и только самое необходимое переопределяешь.
    Василий Наумкин
    20 июня 2012, 09:59
    0
    Да, мне тоже очень понравилось =)
    Сегодня вечером или завтра утром постараюсь сделать перевод.
    Valentin Rasulov
    20 июня 2012, 14:50
    0
    Молодец Василий! Так как у Вас опыт есть по ресурсам, написали бы топик по созданию ресурса через runProcessor — а то на форумах смотрю, такое городят (хотя и сам такое городил) :)… Думаю новичкам будет полезен топик!
    Удачи.
      Василий Наумкин
      20 июня 2012, 14:59
      0
      Да на целый топик тут никак не тянет. В тексте есть ссылка на процессор miniShop, который создает ресурс и дальше с ним работает.

      Если нужно просто создать ресурс — вот простейший код:

      $data = array('pagetitle' => 'Название', 'content' => 'Текст страницы');
      $modx->runProcessor('resource/create', $data);

      Все.
      В массив $data можно пихать любые свойства ресурса MODX, если их нет — будут дефолтные. Можно даже пустой массив отправить, тогда появится «Ресурс без названия».

      Считаете, нужно это добавить в заметку?
        Valentin Rasulov
        20 июня 2012, 15:33
        0
        Хи. Это всё понятно, для некоторых хватит выражения «есть runProcessor», а для многих нужно по полочкам разлаживать.
        Я имел в виду простоу топик-урок, как с фронта создать ресурс по правильному (модексовски). Думаю это как отдельная тема уже.
        Хотя гнать коня не нужно наверное, если будет нужно кому, то попросят!
          Василий Наумкин
          20 июня 2012, 15:37
          0
          Чтобы что-то с фронта делать, надо сначала права юзера освоить.

          Да и вообще, непростая это тема, много заморочек.

          Но на будущее оставим этот вопрос. Может и напишу, если буду что-то такое делать.
            20 июня 2012, 23:26
            0
            >>Я имел ­в виду простоу топик-урок, как с фронта создать ресурс по правильному ­(модексовски)
            да, это было бы здорово!
              Василий Наумкин
              20 июня 2012, 23:54
              0
              Права доступа уже освоили?

              community.modx-cms.ru/blog/documentation/869.html
                21 июня 2012, 11:00
                0
                да, не могу сказать, что полностью освоил всю гибкость настройки прав доступа, но создать группу пользователей, предоставить политику, доступ к контекстам, связать с пользователями и др. настойки — это можно.
                  Василий Наумкин
                  21 июня 2012, 11:05
                  0
                  Окей.

                  Будет время — напишу про создание ресурсов с фронтенда — добавляйте rss блога себе в ридер.
                    Bluetenstadt
                    07 июля 2016, 20:26
                    0
                    Статья была уже?
        20 июня 2012, 23:24
        0
        Спасибо, что еще шире раскрыли тему про runProcessor. Конечно, пока не попробуешь в боевых условиях, не сможешь оценить и понять весь «механизм» работы, будем пробовать :)
          Евгений Тимочкин
          29 октября 2012, 16:26
          0
          Здравствуйте.
          Тема очень интересна. Сейчас рассматриваю возможность использования процессоров для создания контента из front-end'a сайта (ну не хочу я пускать всех в mgr, да и конечному пользователю будет удобно из front-end'a работать). Конкретно пытаюсь сделать добавление статей в блог. Может я конечно изобретаю велосипед, и все уже написано за меня? Не поможете советом по этому вопросу?
            Андрей Ятин
            10 мая 2013, 17:23
            0
            В общем процессоры это действительно круто. Если будет время напишите пожалуйста краткую заметку, или внесите пару строк в текущую, я не сразу, думаю как и многие, понял что они могут работать с любыми типами (надо указывать class_key).
              Alexey Barsukov
              10 октября 2013, 12:34
              0
              Наткнулся на одну особенность функции runProcessor, после нее лог переводится в обычный error-лог modx. Если пишете свой компонент, который работает с консолью через регистры, может сложиться впечатление, что функция runProcessor просто не работает, но это не так. Просто лог из регистров после ее вызова переводится в error-лог. Чтобы вернуть его обратно в регистры, нашел такой способ: нужно после runProcessor писать:
              $this->modx->request->registerLogging($_POST);
              . Как я понял, эта функция смотрит наличие ключей регистров в массиве (в данном случае $_POST) и если информации хватает (присутствуют ключи topic и т.д.), снова переводит лог в регистры.
                Константин Ильин
                29 сентября 2016, 23:09
                0
                Никак не могу понять как получить id ресурса в функции prepareQueryBeforeCount для процессора modObjectGetListProcessor

                public function prepareQueryBeforeCount(xPDOQuery $c)
                    {
                        $resource_id = intval($this->getProperty('resource_id'));
                        $c->where(array('id' => $resource_id));
                        return $c;
                    }
                причем если указать явно $resource_id = 1 работает.

                И сразу еще вопрос только для процессора modObjectGetProcessor
                Подскажите как там получать и возвращать данные, немного не понял его.
                  but1head
                  30 сентября 2016, 02:52
                  0
                  Обычно параметр (поиск) внутри query, у вас точно resource_id передается?
                  public function prepareQueryBeforeCount(xPDOQuery $c)
                      {
                          $query = trim($this->getProperty('query'));
                          if ($query) {
                              $c->where(array(
                                  'name:LIKE' => "%{$query}%",
                                  'OR:description:LIKE' => "%{$query}%",
                              ));
                          }
                          return $c;
                      }
                    Константин Ильин
                    30 сентября 2016, 10:58
                    0
                    модель такая:
                    <object class="trItem" extends="modResource">
                            <composite alias="Trans" class="trItemData" local="id" foreign="id_res" cardinality="many" owner="local" />
                        </object>
                    
                        <object class="trItemData" table="translator_data" extends="xPDOSimpleObject">
                            <field key="id_res" dbtype="int" precision="10" phptype="integer" null="false" default=""/>
                    	/***еще поля***/
                    	<aggregate alias="TranMain" class="trItem" local="id_res" foreign="id" cardinality="one" owner="foreign" />
                        </object>
                    теперь запускается процессор на панели ресурса(modx-resource-tabs) getlist — trItemData, в котором получаю объекты trItemData, но проблема в том, что получаю все объекты всех ресурсов. Отсюда становится понятно, что надо указывать id текущего ресурса для выборки объектов trItemData(собственно поле id_res для этого и делал), но вот как получить для where id текущего ресурса никак не пойму.
                    Проще говоря как получить объекты trItemData только текущего ресурса(trItem)?
                      Сергей Шлоков
                      30 сентября 2016, 11:34
                      +1
                      В вызове getlist процессора нужно добавить параметр с id текущего ресурса, а уже в процессоре его ловить. В вашем примере вы в процессоре ловите параметр resource_id
                      $this->getProperty('resource_id')
                      А вы его передаёте в процессор?
                        Константин Ильин
                        30 сентября 2016, 12:07
                        1
                        0
                        Это мой первый компонент и я думал под танцы с бубном он передается автоматически))

                        Спасибо большое Сергей! все получилось, подсмотрел в других компонентах

                        Сделал так:
                        В плагине создал запись
                        $modx->controller->addHtml('<script type="text/javascript">
                                	Trans.config = ' . $modx->toJSON($Trans->config) . ';
                                	Trans.config.res_id = "'.$resource->get('id').'";
                                	
                        		Trans.config.connector_url = "' . $Trans>config['connectorUrl'] . '";
                        			'.$trConfig.'
                        			</script>
                                ');
                        в js
                        Trans.grid.Items = function (config) {
                            Ext.applyIf(config, {
                                url: Trans.config.connector_url,
                              	*****
                                baseParams: {
                                    action: 'mgr/transitems/getlist' ,
                                    res_id: Trans.config.res_id
                                }, 
                        	*****
                          Сергей Шлоков
                          30 сентября 2016, 12:53
                          +1
                          Пожалуйста!
                          В плагине 2 последние строчки конфига можно убрать. Так как res_id можно получить в js. А Trans.config.connector_url дублирует Trans.config.connectorUrl.
                          Js будет выглядеть так
                          Trans.grid.Items = function (config) {
                              Ext.applyIf(config, {
                                  url: Trans.config.connectorUrl,
                                	*****
                                  baseParams: {
                                      action: 'mgr/transitems/getlist',
                                      res_id: MODx.request.id //id текущего документа
                                  }, 
                          	*****
                            Константин Ильин
                            30 сентября 2016, 13:52
                            0
                            О как) Посмотрел MODx.request, получается из get берется. Вот по extJs modx'а мало что-то доков или я плохо ищу, посоветуешь что нибудь?
                            Насчет connectorUrl проглядел) вот что значит не подумав скопировать)
                            Еще раз спасибо Сергей!
                              Сергей Шлоков
                              01 октября 2016, 09:00
                              1
                              0
                              Вот по extJs modx'а мало что-то доков или я плохо ищу, посоветуешь что нибудь?
                              Копать исходники. Вот тут есть немного.
                  Андрей
                  26 февраля 2017, 15:21
                  0
                  Подскажите пожалуйста мою ошибку. Мой код процессора
                  <?php
                  class MyCompCreateProcessor extends modObjectCreateProcessor
                  {
                      public $objectType = 'MyComp';
                      public $classKey = 'MyComp';
                      public $languageTopics = array('myc');
                      //public $permission = 'create';
                  
                  
                  
                      /**
                       * @return bool
                       */
                      public function beforeSet()
                      {
                          $name = trim($this->getProperty('name'));
                          if (empty($name)) {
                              $this->modx->error->addField('name', $this->modx->lexicon('myc_err_name'));
                          } elseif ($this->modx->getCount($this->classKey, array('name' => $name))) {
                              $this->modx->error->addField('name', $this->modx->lexicon('myc_err_ae'));
                          }
                  
                          return parent::beforeSet();
                      }
                  
                      $response = $modx->runProcessor('browser/file/upload', $_FILES);
                      if ($response->isError()) {
                      return $modx->error->failure($response->getMessage());
                      }
                  
                  }
                  
                  return 'MyCompCreateProcessor';
                  Вышибает с 500 ошибкой

                  Parse error: syntax error, unexpected '$response' (T_VARIABLE), expecting function (T_FUNCTION) or const (T_CONST) in /core/components/myc/processors/web/create.class.php on line 27
                    Воеводский Михаил
                    27 февраля 2017, 02:49
                    0
                    $response = $modx->runProcessor('browser/file/upload', $_FILES);
                        if ($response->isError()) {
                        return $modx->error->failure($response->getMessage());
                        }
                    Эта часть за пределами функции, непосредственно в теле класса. Такое недопустимо.
                    Сергей Малышев
                    06 января 2020, 15:51
                    0
                    Существует-ли какая либо документация по процессорам и их использованию кроме bobsguides.com/modx-processor-list.html?
                      Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
                      26