Передача переменных в Fenom
В этой статье мы рассуждали о способах передачи переменных в шаблонизатор. Возможные варианты — через сессию, плейсхолдеры, контейнер. Но всё это вызывает ощущение костыльности. Т.е. чтобы передать какую-то вещь кому-то, вы не курьера посылаете по конкретному адресу, а ловите попутку и просите водителя передать. Тем более, что у других шаблонизаторов возможность передачи переменных есть из коробки — у Smarty через метод assign()
, у Blade через share()
. Покопавшись в документации я обнаружил, что и у Fenom есть такая возможность. Для этого нужно установить специальный add-on. В pdoTools стандартным способом это сделать нельзя. Поэтому я покажу, как это можно сделать самостоятельно.
Для этого нужно расширить классы pdoTools и FenomX. И так как в компоненте pdoTools предусмотрен механизм расширения, сделать это будет не сложно. Поехали.
Расширение класса pdoTools
В папке core/components/pdotools/model/pdotools/
создаём файл pdotoolsext.class.php
с таким содержимым:
<?php require_once 'pdotools.class.php'; class pdoToolsExt extends pdoTools { /** * Loads template engine * * @return bool|Fenom */ public function getFenom() { if (!$this->fenom) { try { if (!class_exists('StorageFenom')) { require '_fenom_storage.php'; } $this->fenom = new StorageFenom($this); } catch (Exception $e) { $this->modx->log(xPDO::LOG_LEVEL_ERROR, $e->getMessage()); return false; } } return $this->fenom; } /** * @param string|array $chunk * @param array $properties * * @return mixed|string */ public function fenom($chunk, array $properties = array()) { $content = is_array($chunk) ? trim($chunk['content']) : trim($chunk); if (empty($this->config['useFenom']) || !preg_match($this->config['fenomSyntax'], $content)) { return $content; } if ($fenom = $this->getFenom()) { $name = ''; if (is_array($chunk)) { if (!empty($chunk['binding'])) { $name = $chunk['binding'] . '/'; } if (!empty($chunk['id'])) { $name .= $chunk['id']; } elseif (!empty($chunk['name'])) { $name .= $chunk['name']; } else { $name .= md5($content); } } else { $name = md5($content); } /** @var Fenom\Template $tpl */ if (!$tpl = $this->getStore($name, 'fenom')) { if (!empty($this->config['useFenomCache'])) { $cache_options = array( 'cache_key' => 'pdotools/' . $name, ); if (!$cache = $this->getCache($cache_options)) { if ($tpl = $this->_compileChunk($content, $name)) { $this->setCache($tpl->getTemplateCode(), $cache_options); } } else { $cache = preg_replace('#^<\?php#', '', $cache); $tpl = eval($cache); } } else { $tpl = $this->_compileChunk($content, $name); } if ($tpl) { $this->setStore($name, $tpl, 'fenom'); } } if ($tpl instanceof Fenom\Render) { // Add system variables if (!$microMODX = $this->getStore('microMODX')) { if (!class_exists('microMODX')) { require '_micromodx.php'; } $microMODX = new microMODX($this); $this->setStore('microMODX', $microMODX); } $properties['_modx'] = $microMODX; $properties['_pls'] = $properties; // Add system objects if (!empty($this->config['useFenomMODX'])) { $properties['modx'] = $this->modx; $properties['pdoTools'] = $this; } try { $content = $fenom->fetch($tpl, $properties); } catch (Exception $e) { $this->modx->log(modX::LOG_LEVEL_ERROR, $e->getMessage()); $this->modx->log(modX::LOG_LEVEL_INFO, $tpl->getTemplateCode()); } } } return $content; } }
В нём мы изменили 2 метода.
Расширяем класс FenomX
В этой же папке создаём файл _fenom_storage.php
:
<?php require_once '_fenom.php'; require_once dirname(dirname(__FILE__)) . '/fenom/StorageTrait.php'; class StorageFenom extends FenomX { use Fenom\StorageTrait; }
Как мы видим, этот новый класс StorageFenom
нужен только для подключения трейта Fenom\StorageTrait
, в котором заложен функционал работы с переменными. Его тоже нужно добавить.
Добавляем трейт
Я взял его из официального пакета . Но пришлось сделать маленькую правку для адаптации к MODX. Доработанную версию можно взять тут. Копируем и вставляем в файл core/components/pdotools/model/fenom/StorageTrait.php
, который вам нужно предварительно создать.
Подключаем класс pdoToolsExt
Ну и последнее, что нужно сделать — указать в системной настройке pdoTools.class
наш новый класс «pdotools.pdotoolsext».
Использование
Теперь можно легко передавать переменные без каких-либо костылей. Для примера. У вас есть сниппет, который вычисляет какие-то значения, а затем передаёт их в чанк. Раньше можно было использовать в чанке только плейсхолдеры MODX. Теперь вы можете использовать переменные фенома.
# Пример сниппета // Инициализируем pdoTools $pdoTools = $modx->getService('pdoTools', 'pdoToolsExt'); // или получаем уже инициализированный в парсере // $pdoTools = $modx->getParser()->pdoTools; // Определяем переменные $str = 'string'; $names = ['Jonh', 'Mary','Mickael', 'Lisa']; // Передаем их в Fenom $fenom = $pdoTools->getFenom(); $fenom->assign('str', $str); $fenom->assign('names', $names); // Или через массив $fenom->assignAll(['str' => $str, 'names' => $names]); return $pdoTools->getChunk('chunk1');
В чанке будут доступны переменные $str
и $names
.
// Чанк chunk1 <p>Переменная Fenom: {$str}</p> <p>Цикл:</p> <ul> {foreach $names as $name} <li>{$name}</li> {/foreach} </ul>
На странице мы получим такой результат:

Точно также переменные можно передавать и в шаблоны. Правда только из плагинов. В трейте вы найдёте ещё методы для работы с переменными. Попробуйте разобраться.
П.С. Думаю, было бы неплохо иметь такой функционал в pdoTools из коробки. А вы как думаете?
П.П.С. Василий пояснил, что Fenom видит переменные, переданные в чанк. Поэтому достаточно сделать так:
... // Определяем переменные $str = 'string'; $names = ['Jonh', 'Mary','Mickael', 'Lisa']; return $pdoTools->getChunk('chunk1', ['str' => $str, 'names' => $names]);
Значит описанный мной функционал пригодится для передачи переменных из плагинов или для сохранения глобальных переменных, которые будут доступны в любом месте.
Комментарии ()
Вы должны авторизоваться, чтобы оставлять комментарии.
Не подскажете, как организовать следующую логику с помощью переменных на феном?
Есть несколько чанков в файлах (1.tpl, 2.tpl, 3.tpl) Есть необходимость один из них подключать их в шаблоне, в зависимости от настройки ClientConfig в поле 'chunk' (base==1||business==2||church==3)
Путь к чанкам core/elements/chunks. Если не совпадает, то нужно указать свой.