• Блог
  • Меняем механизм парсинга

С выходом MODX версии 2.7.0, в котором был принят мой PR, появилась возможность менять механизм парсинга документов. В статье я указал один из возможных примеров использования — для сайтов, использующих шаблонизатор Fenom, отключить стандартный парсинг MODX. Это позволит избежать коллизий работы двух парсеров. Давайте на простом примере разберём, как это можно сделать.

Первый вариант — это создать свой кастомный класс. Как это сделать описано в документации. Там несколько шагов — создать класс, настроить поведение в админке, создать процессоры и контроллеры. Задача достаточно трудоёмкая. Но если хочется иметь возможность выбирать тип документа в дереве ресурсов (например, в контекстном меню), то придётся заморочится. В том случае, если нужно всего лишь изменить правила парсинга на сайте для всех документов, рассмотрим упрощенный вариант.

Давайте в плагине при загрузке документа просто подменять класс. Всего несколько строчек, которые меняют всё! Но перед созданием плагина давайте создадим наш новый класс. Назовём его fenomDocument. Файл можно разместить в любом месте. В нашем случае положим его в core/classes/fenomdocument.php.

<?php
class fenomDocument extends modResource {
    /**
     * Overrides modResource::__construct to set the class key for this Resource type
     * @param xPDO $xpdo A reference to the xPDO|modX instance
     */
    function __construct(& $xpdo) {
        parent :: __construct($xpdo);
        $this->set('class_key','fenomDocument');
    }

    public function parseContent($data = array())
    {
        $oldResource = $this->xpdo->resource;
        $this->xpdo->resource = $this;
        if (!empty($data)) {
            $scope = $this->xpdo->toPlaceholders($data, '', '.', true);
        }
        $this->_output = $this->_content;
        $this->_output = $this->xpdo->getParser()->pdoTools->fenom($this->_output, $this->xpdo->placeholders);
        $this->xpdo->resource = $oldResource;
        if (isset($scope['keys'])) $this->xpdo->unsetPlaceholders($scope['keys']);
        if (isset($scope['restore'])) $this->xpdo->toPlaceholders($scope['restore']);
        $this->_processed= true;
        return $this->_output;
    }
}

/**
 * Class fenomDocument_mysql
 */
class fenomDocument_mysql extends fenomDocument {}

Для простоты сюда же добавил класс для mySql. Чтобы обойтись одним инклюдом.

Теперь нужно подключить класс. Создаём плагин fenomDocument и отмечаем для него события «OnWebPageInit» и «OnLoadWebDocument».

<?php
switch ($modx->event->name) {
    case 'OnWebPageInit':
        include_once MODX_CORE_PATH . 'classes/fenomdocument.php';
    	// Добавляем в карту классов.
    	$modx->map['fenomDocument'] = [
            'extends' => 'modResource',
            'fields' => [],
            'fieldMeta' => [],
        ];
        break;
    case 'OnLoadWebDocument':
        $data = $modx->resource->toArray();
        $modx->resource = $modx->newObject('fenomDocument');
        $modx->resource->fromArray($data, '', true, true);

        /*
        // Если нужно работать только с ресурсами класса modDocument, то используем соответствующее условие.
        if ($modx->resource instanceof modDocument) {
            ....
        }
        */
        break;
}

Пришла очередь протестировать полученное. Создайте страницу с тегами MODX и Fenom и откройте её на фронте. В результате должно получится, что первые остались нетронутыми, а вторые замечательно распарсились. И всё работает по правилам шаблонизатора — контент парсится один раз. А значит и пресловутый тег ignore будет работать на любом уровне вложенности.

Тут надо ещё отметить, что данный механизм парсинга предназначен только для контента ресурса. Т.е. шаблон MODX не учитывается. Чтобы оставить парсинг шаблона, раскомментируйте код в методе fenomDocument::prepare(). Правда в этом случае парсить шаблон будет парсер MODX. Ну а в следующей статье мы рассмотрим возможность работать с шаблонами Fenom.

Данное решение работает так:

  • Если есть шаблон, то парсятся только кэшируемые теги MODX. Если есть теги Fenom, то они будут распарсены на следующем шаге.
  • В подготовленном контенте ресурса парсятся только теги Fenom.
  • Заключение

    Описанное выше решение является демонстрацией возможностей. Аналогично можно реализовать парсинг и для парсеров Smarty и Twig.

    Кстати, не все знают, что админка использует шаблонизатор Smarty и в ней не работает парсер MODX.

    Update 01.12.2018

    Чтобы не путаться, оставил вариант с парсингом шаблона. Таким образом, если в шаблоне указать кэшируемые теги MODX, они будут распарсены. А следующей статье откажемся и от шаблонов MODX, а соответственно и полностью от его парсера.

    Update 05.12.2018

    С прискорбием сообщаю, что всё-таки специфика MODX не позволяет использовать только парсер Fenom. Если с чанками и сниппетами ещё можно как-то работать (в компилированный файл попадает результат modX::getChunk() и modX::runSnippet()), то конструкции типа $_modx->resource.content так и компилируются. И, соответственно, выводится только контент ресурса без обработки парсером. А если дополнительно парсить такие конструкции, то вернёмся опять к тому, что было. Вот такой получается результат исследований.

    30 ноября 2018, 17:51   285     3

    Комментарии ()

    1. shock 02 декабря 2018, 14:15 # 0
      Спасибо за пример. Ждём следующей статьи.
      И ещё вопрос. Как быть с документами имеющими отличный от modResource, например с ресурсами Минишопа?
      1. Сергей Шлоков 02 декабря 2018, 17:17 # 0
        Пожалуйста!

        В примере я специально указал класс modDocument для демонстрации возможности фильтрации ресурсов. Для полноценного отказа от парсера MODX фильтрацию нужно убрать. Т.е. обрабатывать все документы без исключения.
      2. Alex 11 декабря 2018, 11:34 # 0
        А что со скоростью? каков прирост? было бы неплохо посмотреть результаты -) потому как если даже на 50мс будет быстрее, я сразу буду разбираться как внедрить-)

        Вы должны авторизоваться, чтобы оставлять комментарии.

        Выделите опечатку и нажмите Ctrl + Enter, чтобы отправить сообщение об ошибке.