Собственные модификаторы Fenom
Продолжаю разработку новой версии modstore.pro и хочу поделиться простым способом подключения своих модификаторов.
Обычный способ все знают: нужно создать сниппет, который будет принимать переменные $input и $options и вызвать его в чанке вот так:
Создаём плагин для события pdoToolsOnFenomInit, и пишем в нём:
Таким образом ссылка на страницу дополнения становится гораздо аккуратнее.
Если вы разрабатываете свой пакет, которому нужны собственные модификаторы, то лучше не захламлять плагин и вызывать метод из основного класса:
Кстати говоря, таким образом можно включить еще много чего — смотрите документацию Fenom. За добавление события pdoToolsOnFenomInit благодарим Володю Володина.
Обычный способ все знают: нужно создать сниппет, который будет принимать переменные $input и $options и вызвать его в чанке вот так:
{$variable | snippet}
Но- Сниппеты бывают совсем небольшие и создавать их на каждый чих не хочется
- Вызов сниппета, это всё-таки дополнительная нагрузка
- Лично я уже полностью перешел на файлы, и создавать запись в БД для сниппета, только ради его связи с файлом мне совсем не хочется
Создаём плагин для события pdoToolsOnFenomInit, и пишем в нём:
<?php
/** @var modX $modx */
switch ($modx->event->name) {
case 'pdoToolsOnFenomInit':
/** @var Fenom $fenom
Мы получаем переменную $fenom при его первой инициализации и можем вызывать его методы.
Например, добавим модификатор вывода имени домена сайта из произвольной ссылки.
*/
$fenom->addModifier('website', function ($input) {
if (!$url = parse_url($input)) {
return $input;
}
$output = str_replace('www.', '', $url['host']);
return strtolower($output);
});
break;
}
Теперь в любом чанке можно вызывать модификатор website. Так как этот модификатор является внутренним методом Fenom и загружается один раз при его инициализации — работает он быстрее любого сниппета.<div class="site">
<span>Сайт дополнения</span>
<a href="{$package.link}" target="blank">{$package.link | website}</a>
</div>
Таким образом ссылка на страницу дополнения становится гораздо аккуратнее.
Если вы разрабатываете свой пакет, которому нужны собственные модификаторы, то лучше не захламлять плагин и вызывать метод из основного класса:
switch ($modx->event->name) {
case 'pdoToolsOnFenomInit':
$Extras = $modx->getService('Extras', 'Extras', MODX_CORE_PATH . 'components/extras/model/');
if ($Extras) {
/** @var Fenom $fenom */
$Extras->addFenomModifiers($fenom);
}
break;
}
Если модификаторов много и вам они нужны в отдельных файлах — можно прописать в своём методе логику загрузки их оттуда. Это в любом случае, гораздо удобнее, чем создавать кучу сниппетов.Кстати говоря, таким образом можно включить еще много чего — смотрите документацию Fenom. За добавление события pdoToolsOnFenomInit благодарим Володю Володина.
Комментарии: 23
Лично я уже полностью перешел на файлы, и создавать запись в БД для сниппета, только ради его связи с файлом мне совсем не хочетсяВасилий, я кажется чего-то не понимаю… Можно же создавать сниппеты без записи в БД…
Это как, покажи?
Сниппет — в любом случае запись в таблице modSnippet.
Сниппет — в любом случае запись в таблице modSnippet.
Эмм… Ну, как-то так:
{$_modx->runSnippet('@FILE:snippets/getRating.php',[
'id' => $_modx->resource.id,
'from' => 1,
'to' => 5,
'tpl' => '@FILE:chunks/infocenter/rating.row.tpl',
'tplOuter' => '@FILE:chunks/infocenter/rating.outer.tpl'
])}
Код сниппета: <?php
if ($page = $modx->getObject('modResource',$id)){
//всякая магия
return $output
}
else {
return;
}
В таблице ничего похожего на getRating нет…
Ну а теперь вызови этот файл в качестве модификатора.
что-то упало все. Даже с измененными параметрами…
Но это не важно. Я просто хотел обратить внимание на неточность о БД и сниппетах. Ведь сниппет не всегда модификатор, поэтому можно спокойно хранить в файлах свои сниппеты… Разве нет?
Но это не важно. Я просто хотел обратить внимание на неточность о БД и сниппетах. Ведь сниппет не всегда модификатор, поэтому можно спокойно хранить в файлах свои сниппеты… Разве нет?
Сам ты неточность.
Сниппет — это объект modSnippet, он хранится в БД, наследуется от modScript и имеет массу особенностей, которых нет у php файла. Например, при запуске его код кэшируется в директорию core/cache/includes/elements/modsnippet/.
То, что pdoTools умеет динамически создавать сниппеты из файлов, не делает эти файлы сниппетами.
Давай ты теорию сначала подучишь, а потом будешь поправлять, окей?
Сниппет — это объект modSnippet, он хранится в БД, наследуется от modScript и имеет массу особенностей, которых нет у php файла. Например, при запуске его код кэшируется в директорию core/cache/includes/elements/modsnippet/.
То, что pdoTools умеет динамически создавать сниппеты из файлов, не делает эти файлы сниппетами.
Давай ты теорию сначала подучишь, а потом будешь поправлять, окей?
ок. Говорил же, что кажется чего-то не понимаю.
На самом деле у сниппетов одна очень важная отличительная особенность — это параметры по умолчанию. Поэтому сниппеты можно вызвать без параметров. А вот вызывать файловый «сниппет» нужно всегда с параметрами. В остальном различия несущественные. Ну и понятно, что кэшировать файл нет необходимости.
Кстати, сниппеты кэшируются в 2 директории — core/cache/includes/elements/modsnippet/ и core/cache/scripts/elements/modsnippet/.
Кстати, сниппеты кэшируются в 2 директории — core/cache/includes/elements/modsnippet/ и core/cache/scripts/elements/modsnippet/.
Было бы классно подхватывать все сниппеты-модификаторы из директории, к примеру из core/components/pdotools/modifiers/*.php автоматом.
Об этом написано в заметке, в плагине такая загрузка делается в 3-5 строк. Считайте домашним заданием ;)
Вот тоже интересно. Хотелось бы хранить код модификаторов в файловой системе, причем не прибегая к штатной возможности создания статических файлов.
Почему-то конструкция предлагаемая Василием для вызова плагинов из файловой системы, в случае с модификаторами не работает.
Почему-то конструкция предлагаемая Василием для вызова плагинов из файловой системы, в случае с модификаторами не работает.
if ($pdoTools = $modx->getService('pdoTools')) {
$pdoTools->runSnippet('@FILE plugins/my_plugin.php', $scriptProperties);
}
Подозреваю, что дело в событии на которое навешивается плагин, но не уверен. Подскажите пожалуйста, как правильно подтягивать код модификаторов из файлов
Мне очень часто требуются различные модификаторы — писал все в сниппеты, в основном одна строка — return блабла, и складываю в одну категорию. Это несомненно поможет, спасибо
Подскажите, как в таких модификаторах можно работать с $modx?
В примере ниже модификатор mTest работает.
А использование модификатора ch1Count или ch2Count прерывает парсинг, и оставшаяся часть страницы не выводится.
В то же время, всё работает, если использовать в качестве модификатора сниппет, например chCount
В примере ниже модификатор mTest работает.
А использование модификатора ch1Count или ch2Count прерывает парсинг, и оставшаяся часть страницы не выводится.
<?php
/** @var modx $modx */
switch ($modx->event->name) {
case 'pdoToolsOnFenomInit':
/** @var Fenom $fenom */
$fenom->addModifier('ch1Count', function ($input) {
/** @var modx $modx */
$ids = $modx->getChildIds($input);
return count($ids);
});
$fenom->addModifier('ch2Count', function ($input) {
/** @var modx $modx */
$modx = $this->modx;
$ids = $modx->getChildIds($input);
return count($ids);
});
$fenom->addModifier('mTest', function ($input, $props) {
return serialize($props);
});
break;
}
В логах вебсервера тишина.В то же время, всё работает, если использовать в качестве модификатора сниппет, например chCount
<?php
/** @var modx $modx */
$ids = $modx->getChildIds($input);
return count($ids);
Как-то сразу не сообразил. Вот решение:
<?php
/** @var modx $modx */
switch ($modx->event->name) {
case 'pdoToolsOnFenomInit':
/** @var Fenom $fenom */
$fenom->addModifier('chCount', function ($input) use ($modx) {
/** @var modx $modx */
$ids = $modx->getChildIds($input);
return count($ids);
});
break;
}
Прошу не кидать в меня чем попало, я новичок в MODX
Может реализация для знающих понятна, но могли бы Вы по полочкам расписать реализацию для самых новичков.
Например, у меня есть снипет «lcfirst»:
Заранее, благодарю!
Может реализация для знающих понятна, но могли бы Вы по полочкам расписать реализацию для самых новичков.
Например, у меня есть снипет «lcfirst»:
<?php
$str = $input;
echo mb_lcfirst($str); // какой-То Текст
function mb_lcfirst($str) {
return mb_strtolower(mb_substr($str, 0, 1)) . mb_substr($str, 1);
}
Я вызвать его в чанке вот так:{$variable | lcfirst}
Как переделать, где и какие создавать файлы и тд.? В общем прошу все подробнее расписать на моем примере.Заранее, благодарю!
1. Создаёте плагин с любым именем и следующим содержанием
3. Сохраняете.
4. Пользуетесь.
<?php
switch ($modx->event->name) {
case 'pdoToolsOnFenomInit':
/** @var Fenom $fenom */
$fenom->addModifier('lcfirst', function ($input) {
return mb_strtolower(mb_substr($input, 0, 1)) . mb_substr($input, 1);
});
break;
}
2. Отмечаете событие «pdoToolsOnFenomInit» на второй вкладке.3. Сохраняете.
4. Пользуетесь.
Благодарю, все получилось.
на опенсервере все работало нормально, но при переносе на хостинг получил ошибку
php 7.2 fpm nginx
tack trace:
#0 /home/mh/mh/www/core/components/pdotools/model/pdotools/pdotools.class.php(552) : eval()'d code(11): modScript->{closure}('size')
#1 /home/mh/mh/www/core/components/pdotools/vendor/fenom/fenom/src/Fenom/Render.php(215): pdoTools->{closure}(Array, Object(Fenom\Render))
#2 /home/mh/mh/www/core/components/pdotools/vendor/fenom/fenom/src/Fenom/Render.php(215): Closure->__invoke(Array, Object(Fenom\Render))
#3 /home/mh/mh/www/core/components/pdotools/vendor/fenom/fenom/src/Fenom/Render.php(229): Fenom\Render->display(Array)
#4 /home/mh/mh/www/core/components/pdotools/model/pdotools/pdotools.class.php(580): Fenom\Render->fetch(Array)
#5 /home/mh/mh/www/core/components/pdotools/model/pdotools/pdopar in /home/mh/mh/www/core/cache/includes/elements/modplugin/32.include.cache.php on line 48
[11-Mar-2020 12:17:24 Europe/Moscow] PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function modScript::{closure}(), 1 passed in /home/mh/mh/www/core/components/pdotools/vendor/fenom/fenom/src/Fenom/Template.php(487) : eval()'d code on line 360 and exactly 2 expected in /home/mh/mh/www/core/cache/includes/elements/modplugin/37.include.cache.php:5
Stack trace:
#0 /home/mh/mh/www/core/components/pdotools/vendor/fenom/fenom/src/Fenom/Template.php(487) : eval()'d code(360): modScript->{closure}(Array)
#1 /home/mh/mh/www/core/components/pdotools/vendor/fenom/fenom/src/Fenom/Render.php(215): Fenom\Template->{closure}(Array, Object(Fenom\Template))
#2 /home/mh/mh/www/core/components/pdotools/vendor/fenom/fenom/src/Fenom/Render.php(215): Closure->__invoke(Array, Object(Fenom\Template))
#3 /home/mh/mh/www/core/components/pdotools/vendor/fenom/fenom/src/Fenom/Template.php(492): Fenom\Render->display(Array)
#4 /home/mh/mh/www/core/components/pdotools/vendor/fenom/fenom/src/Fenom/Template.php(487) : eval()'d code(7): Fenom\Template->display(Array)
#5 /ho in /home/mh/mh/www/core/cache/includes/elements/modplugin/37.include.cache.php on line 5
php 7.2 fpm nginx
Разобрался, дело в несоблюдении сигнатуры, если модификатор определен с двумя параметрами,
$fenom->addModifier('toflat', function ($input, $key) {
то и вызов должен быть как {$input | toflat:'key'} иначе если вызвать {$var1 | toflat} то получим ошибку выше.
Мне понравилось лёгкость использования. Например если редактируемый кусок html очень длинный в разработке и надо на выходе в браузер уже отдать сдутый html, как вариант использовать блочный модификатор {deflate}{/deflate}, что даёт легкость в читаемости кода и облегчает прогруз на фронтенде.
$fenom->addBlockFunction('deflate', function (array $params, $content) use ($modx) {
$filters = [
'/<!--([\s\S]*?)-->/' => '', // Remove HTML Comments (breaks with HTML5 Boilerplate)
'/(?<!\S)\/\/\s*[^\r\n]*/' => '', // Remove comments in the form /* */
'/\>[^\S ]+/s' => '>',
'/[^\S ]+\</s' => '<',
'/([\t ])+/s' => ' ',
'/^([\t ])+/m' => '',
'/([\t ])+$/m' => '',
'~//[a-zA-Z0-9 ]+$~m' => '',
'/[\r\n]+([\t ]?[\r\n]+)+/s' => "\n",
'/\>[\r\n\t ]+\</s' => '><',
'/}[\r\n\t ]+/s' => '}',
'/}[\r\n\t ]+,[\r\n\t ]+/s' => '},',
'/\)[\r\n\t ]?{[\r\n\t ]+/s' => '){',
'/,[\r\n\t ]?{[\r\n\t ]+/s' => ',{',
'/\),[\r\n\t ]+/s' => '),',
'/<!--(.*)-->/isU' => '',
'/\r/' => '',
'/\n/' => '',
'/\>\s+/' => '>',
'~([\r\n\t ])?([a-zA-Z0-9]+)=\"([a-zA-Z0-9_\\-]+)\"([\r\n\t ])?~s' => '$1$2=$3$4',
];
$content = preg_replace(array_keys($filters), array_values($filters), $content);
return $content;
});
дабы не плодить тему по пустякам, помогите разобраться в модификаторе not in
а то конструкция
{if $key | notin : $array} {* не выбивает синтаксическую ошибку, но не работает*}
{if $key | not in : $array} {* выбивает синтаксическую ошибку*}
Как правильно??а то конструкция
{if $key | in : $array}{else}выполняем{/if} {*ну такое*}
Попробуй так
{if !($key | in : $array)} ... {/if}
Работает!) Спасибо)
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.