Получение всех TV полей ресурса из конкретной категории и вывод в чанк
Всем привет. Хочу поделиться сниппетом, который позволяет получить все TV поля ресурса из определённой категории и оформить вывод в чанк. Задача по сути простая, но те решения которые находил в интернете (например тут или тут или тут) немного не о том и мне не подходят, тоесть готового кажется нет.
Да, её можно решить с помощью MIGX, но это мне тоже не совсем подходило (об этом ниже). Поэтому решил написать этот сниппет. Единственная сложность была сформировать запрос в БД, так как опыта небыло от слова совсем, поэтому воспользовался gpt чатом, ну а дальше отправить результаты в чанк проблем не составило. Возможно кому-то будет полезно.
Код сниппета следующий:
Вызов в шаблоне:
Тут стоит сказать, что если в вызов сниппета вписать ID категории из админки, работать не будет, так как в базе данных у нужной мне группы TV полей идентификатор другой. Чтобы всё работало нужен тот, который в БД, в столбце category.
Ну и код чанка для полноты картины:
В результате я получил нужную мне группу TV полей и оформил вывод в чанк.
Вот так это выглядит в админке (просто список полей):
И вот так выглядит на сайте:
Хочу сразу ответить на некоторые вопросы.
1. По сути я мог бы просто напрямую вывести каждое TV в шаблон и забыть, но потом это было бы неудобно структурировать и стилизовать, учитывая что полей 19 и потенциально их может быть больше (поэтому и захотелось сделать вывод в чанк).
2. Я мог бы воспользоваться MIGX и тут было бы 2 сценария:
Да, её можно решить с помощью MIGX, но это мне тоже не совсем подходило (об этом ниже). Поэтому решил написать этот сниппет. Единственная сложность была сформировать запрос в БД, так как опыта небыло от слова совсем, поэтому воспользовался gpt чатом, ну а дальше отправить результаты в чанк проблем не составило. Возможно кому-то будет полезно.
$q = $modx->newQuery('modTemplateVar');
$q->select($modx->getSelectColumns('modTemplateVar', 'modTemplateVar'));
$q->select('IF(tvc.value != "", tvc.value, tvv.value) AS tv_value');
$q->leftJoin('modTemplateVarResource', 'tvr', 'modTemplateVar.id = tvr.tmplvarid');
$q->leftJoin('modTemplateVarTemplate', 'tvtt', 'modTemplateVar.id = tvtt.tmplvarid');
$q->leftJoin('modTemplateVarResource', 'tvv', 'tvr.contentid = tvv.contentid AND tvr.tmplvarid = tvv.tmplvarid AND tvv.value != ""');
$q->leftJoin('modTemplateVarResource', 'tvc', 'tvr.contentid = tvc.contentid AND tvr.tmplvarid = tvc.tmplvarid');
$q->where([
'tvr.contentid' => $id, // id ресурса у которого запрашиваем TV
'modTemplateVar.category' => $category, // id категории, по которой сгруппированы наши TV
]);
$q->sortby('rank', 'ASC');
$resources = $modx->getCollection('modTemplateVar', $q);
foreach($resources as $resource){
$out .= $modx->getChunk($tpl, [
'caption'=> $resource->get('caption'),
'rating'=> $resource->get('tv_value')
]);
}
return $out;
Вызов в шаблоне:
[[!tvGroup?
&id=`[[*id]]`
&tpl=`tvGroupTpl`
&category=`45`
]]
Тут стоит сказать, что если в вызов сниппета вписать ID категории из админки, работать не будет, так как в базе данных у нужной мне группы TV полей идентификатор другой. Чтобы всё работало нужен тот, который в БД, в столбце category.
Ну и код чанка для полноты картины:
<div class="item-parent">
<div class="row">
<div class="col-9 pr-0">
<span class="caption">[[+caption]]:</span>
<div class="item-bg" data-rating="[[+rating]]"></div>
</div>
<div class="col-3">
<span class="rating">[[+rating]]/10</span>
</div>
</div>
</div>
В результате я получил нужную мне группу TV полей и оформил вывод в чанк.
Вот так это выглядит в админке (просто список полей):
И вот так выглядит на сайте:
Хочу сразу ответить на некоторые вопросы.
1. По сути я мог бы просто напрямую вывести каждое TV в шаблон и забыть, но потом это было бы неудобно структурировать и стилизовать, учитывая что полей 19 и потенциально их может быть больше (поэтому и захотелось сделать вывод в чанк).
2. Я мог бы воспользоваться MIGX и тут было бы 2 сценария:
- Заказчику для каждого ресурса (ресурсов пока 314) пришлось бы 19 раз нажимать на кнопку «Добавить характеристику» — что точно не вариант.
- Я мог бы сделать json разметку по принципу:
и заказчику оставалось бы только наполнить эти поля, но мне не хотелось чтобы тот, кто будет наполнять в какой-то момент «затроил» и насоздавал дополнительные экземпляры этих полей в одном ресурсе.{"caption":"Характеристики шкалой","fields":[ {"field":"helth","caption":"Здоровье"}, {"field":"intel","caption":"Интеллект"}, {"field":"grooming","caption":"Потребность в груминге"}, ... ]} ]
Комментарии: 2
Так вроде, пошустрее будет ):
В чанке [[+caption]] и [[+value]]:
Кстати, верный ID категории можно узнать в Элементы » Категории.
$sql = "
SELECT tvr.value, tv.caption
FROM {$modx->getTableName('modTemplateVarResource')} tvr
LEFT JOIN {$modx->getTableName('modTemplateVar')} tv
ON tv.id = tvr.tmplvarid
WHERE tvr.contentid = {$id} AND tv.category = {$category}
";
$q = $modx->prepare($sql);
$q->execute();
$resources = $q->fetchAll(PDO::FETCH_ASSOC);
foreach($resources as $resource){
$out .= $modx->getChunk($tpl, $resource);
}
return $out;
В чанке [[+caption]] и [[+value]]:
<div class="item-parent">
<div class="row">
<div class="col-9 pr-0">
<span class="caption">[[+caption]]:</span>
<div class="item-bg" data-rating="[[+value]]"></div>
</div>
<div class="col-3">
<span class="rating">[[+value]]/10</span>
</div>
</div>
</div>
Кстати, верный ID категории можно узнать в Элементы » Категории.
Примерно тоже самое, только при помощи mmxDatabase:
Получается 3 простых выборки, без join.
Сначала выбирается ресурс, потом значения его ТВ из нужной категории, а затем добираются основные свойства этих ТВ.
Eloquent собирает все данные вложенными массивами в итоговый результат:
Дальше можно перебирать результат на Fenom со всеми проверками на пустоту и прочее.
$id = $modx->getOption('id', $scriptProperties);
$category = $modx->getOption('category', $scriptProperties, '1', true);
$resource = \MMX\Database\Models\Resource::query()
->select('id', 'pagetitle')
->with('TvValues', static function($c) use ($category) {
$c->select('value', 'contentid', 'tmplvarid');
$c->whereHas('Tv', static function($c) use ($category) {
$c->where('category', $category);
});
$c->with('Tv:id,name,caption,default_text');
})
->find($id);
return $resource ? print_r($resource->toArray(), true) : 'Not found';
Получается 3 простых выборки, без join.
Сначала выбирается ресурс, потом значения его ТВ из нужной категории, а затем добираются основные свойства этих ТВ.
Eloquent собирает все данные вложенными массивами в итоговый результат:
Дальше можно перебирать результат на Fenom со всеми проверками на пустоту и прочее.
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.