Вывод ТВ со своим оформлением

Есть задача: сделать раздел вакансий, в котором у каждой вакансии 3 списка: требования, ответственность, условия. Конечно, менеджеру должно быть удобно и html теги он писать не собирается.
Использовать для этого TinyMCE не хочется - слишком просто в нем сломать верстку. Поэтому я решил использовать ТВ и выводить их в нужном мне виде простым сниппетом.
Сниппет getTVlist
<?php
// Получаем или готовый текст, или достаем указанный ТВ у ресурса
$tv = !empty($input) ? trim($input) : trim($modx->resource->getTVValue($tv));
if (empty($tv)) {return '';}

// Стандартные чанки, можно переопределить
if (empty($tpl)) {$tpl = '@INLINE <li>[[+value]]</li>';}
if (empty($tplOuter)) {$tplOuter = '@INLINE <ul>[[+rows]]</ul>';}

// Подключаем pdoTools для работы с инлайновыми чанками
$pdo = $modx->getService('pdoTools');

// Разбиваем текст по символу переноса строки
$rows = '';
$tmp = array_map('trim', explode("\n", $tv));
foreach ($tmp as $value) {
    if (empty($value)) {continue;}
    $rows .= $pdo->getChunk($tpl, array('value' => $value));
}

// Если есть, что выводить - выводим
if (!empty($rows)) {
    return $pdo->getChunk($tplOuter, array('rows' => $rows));
}
Хочется отметить ровно одну инновацию (возможно, только для меня) - отказ от разделителя в ТВ. Работа ведется по символу переноса строки "\n". Конечно, менеджеру гораздо удобнее нажать enter, чем вспоминать про "||".
Ну и понятно, что если ТВ не заполнен, то чанк-обертка выводиться не будет. Использовать такой сниппет значительно удобнее и быстрее, чем фильтр [[+tv.requirements:notempty=...]].
Вызываем в чанке pdoResources:
[[getTVlist?
    &input=`[[+tv.requirements]]`
    &tplOuter=`@INLINE <h4>Требования</h4><ul>[[+rows]]</ul>`
]]
На странице вакансии:
[[getTVlist?
    &tv=`requirements`
    &tplOuter=`@INLINE <h4>Требования</h4><ul>[[+rows]]</ul>`
]]
Конечно, можно заранее прописать наборы параметров и вызывать вот так:
[[getTVlist@Req]]
Вот такой маленький и удобный сниппет.
БонусПолучение ТВ с оборачиванием в чанк. Это просто замена фильтру notempty, сниппет getTV:
<?php
$tv = !empty($input) ? trim($input) : trim($modx->resource->getTVValue($tv));

if (empty($tplOuter)) {$tplOuter = '<b>Название параметра</b>[[+value]]';}
if (!empty($tv)) {
    $pdo = $modx->getService('pdoTools');
    return $pdo->getChunk($tplOuter, array('value' => $tv));
}

9 комментариев

Только на днях сделал примерно такой же сниппит, правда получилось более уродливо и без чанков, использовал его для одного из полей в minishop2.

<?php
$tracks =  $scriptProperties['tracks'];
$tracks_array = explode("\n", $tracks);
if(count($tracks_array) == 1 && empty($tracks_array[0])) return;
$result = '<ol>';
foreach($tracks_array as $track) {
    $result .= '<li>'.$track.'</li>';
}
$result .= '</ol>';

return $result;
Ну и понятно, что если ТВ не заполнен, то чанк-обертка выводиться не будет. Использовать такой сниппет значительно удобнее и быстрее, чем фильтр [[+tv.requirements:notempty=...]].
Я думаю что удобнее сделать так
[[*mytv1:notempty=`<h4>Требования</h4><ul>[[*mytv1:nl2br]]</ul>`]]
[[*mytv2:notempty=`<h4>Ответственность</h4><ul>[[*mytv2:nl2br]]</ul>`]]
[[*mytv3:notempty=`<h4>Условия</h4><ul>[[*mytv3:nl2br]]</ul>`]]
А быстрее сниппетом. Ради эксперимента попробовал оба варианта - у меня выигрыш в 5 тысячных секунды. По моему несущественно.
Василий Наумкин
nl2br - это замена переноса строк на br, а не на li.
Вывести фильтрами с таким оформлением, как мне было нужно, просто не получится.
можно сделать свой фильтр nl2li, мне просто было лень делать. :) что то типа такого:
$li = explode("\n", $input);
foreach ($li as $value) {
    if (empty($value)) {continue;}
    $li .= '<li>'.$value.'</li>';
}
return $li;
Василий Наумкин
И в чем теперь отличие от сниппета?
В том, что нельзя поменять оформление прямо при вызове? Не могу назвать это удобством, учитывая, что у меня много где нужно так выводить данные.
К примеру, вот:
Ну и мой сниппет тоже можно использовать как фильтр - он смотрит в input.
Отличия - вызывать сниппет или фильтр. На самом деле все зависит от стоящей задачи. Для единоразового решения мне удобнее использовать фильтры, и просто лень писать больше кода чем это необходимо,
Кстати Василий, есть еще вариант сделать Custom TV Output Type, в котором можно сразу задавать оформление. Это наверное будет самым универсальным и удобным способом.
Василий Наумкин
Обрати внимание на вот эту строку:
$tv = !empty($input) ? trim($input) : trim($modx->resource->getTVValue($tv));
Видишь, сниппет проверяет $input - а значит, может работать как фильтр.
Custom TV Output Type - не мое. Сниппет на php умеет больше и работает быстрее.
$tmp = array_map('trim', explode("\\n", $tv));
В этой строке ошибка с двойным слешем.
Ганин Роман
Сделал то же самое, используя Jevix:

[[Jevix?
   &input=`[[*ваш_TV]]`
   &cfgAllowTags=`a,sup`
   &cfgSetAutoBrMode=`0`
   &cfgSetTagNoAutoBr=`li`
   &cfgSetTagBlockType=`li`
   &cfgSetAutoPregReplace=`[["/^[-*]?(.+)$/im"],["<li>$1"]]`
   &logErrors=`0`
]]
Новая строка обозначает элемент списка (li) и может начинаться с дефиса или звёздочки — они будут вырезаны, а на выходе оформлены через css (list-style-image: url(…);): http://www.bvmedia.ru/vacancy/4869
bezumkin.ru
Личный сайт Василия Наумкина
Прямой эфир
Александр Наумов
23.07.2024, 00:20:37
Василий, спасибо большое!!
Василий Наумкин
01.07.2024, 11:56:41
Да, верно, именно так. А в контроллере, скорее всего, ловить данные методом post.
Василий Наумкин
26.06.2024, 09:38:15
О, точно, вылезает если не залогинен. Спасибо, исправил!
Василий Наумкин
09.04.2024, 04:45:01
> Ошибка 500 Это не похоже на ошибку Nginx, это скорее всего ошибка PHP - надо смотреть его логи. ...
Василий Наумкин
20.03.2024, 21:21:52
Volledig!
Андрей
14.03.2024, 13:47:10
Василий! Как всегда очень круто! Моё почтение!
russel gal
09.03.2024, 20:17:18
> А этот стоило написать хотя бы затем, чтобы получить комментарий от юзера, который ничего не писал...
Александр Наумов
27.01.2024, 03:06:18
Василий, спасибо! Извини, тупанул.
Василий Наумкин
22.01.2024, 07:43:20
Давай-давай!
Василий Наумкин
24.12.2023, 14:26:13
Спасибо!