MODX. Дополнительные поля (TV)
Отредактировано: 24 Июля 2023
Дополнительные поля (Template Variables) — элементы для расширения стандартных полей ресурса.
Вкладка «Параметры ввода»
Параметры ввода — тот вид поля, который будет отображаться в админ панели, при редактировании ресурса. Есть несколько заранее предустановленных параметров, но если их не хватает, можно добавить разнообразия с помощью дополнительных компонентов, вроде MIGX.
Стандартные варианты параметров ввода:
- Авто-метка (auto-tag) (список элементов подобных тегам)
- Дата (date)
- Изображение (image)
- Переключатели (radio)
- Скрытый (hidden) (не отображается в админ. панели и на сайте)
- Список (одиночный выбор) / listbox (single-select)
- Список (множественный выбор) / listbox (multi-select)
- Список ресурсов (resource list) (из структуры сайта)
- Тег (tag)
- Текст (text) (обычная текстовая строка)
- Текстовая область (textares) (обычная текстовая область)
- Текстовый редактор (richtext) (текстовая область с визуальным редактором)
- Устаревший список множественного выбора (legasy multiple list)
- Файл (область для вставки файла)
- Флажки (checkbox) — если флаг не отмечен, не отправляется никакого значения. Стоит учитывать это при продумывании архитектуры, иногда, это становится проблемой.
- Число (number)
- Электронная почта (email)
Значения полей
Чтобы добавить в дополнительное поле значение, надо указать его в поле “Input Option Values”.
Если значений несколько, варианты записываются с разделителем: Значение1||Значение2||Значение3
Возможна запись формата ключ => значение: Значение1==cod1||Значение2==cod2||Значение3==cod3
Проще говоря, формат записи таков DISPLAY VALUE==VALUE
- DISPLAY VALUE — значение отображаемое на странице ресурса в админке;
- VALUE — значение которое будет записано в базе.
Варианты по умолчанию
Запись параметров по умолчанию делается с помощью поля “Default Value”, а формат записи зависит от типа поля.
- checkbox: наличие галки — cod1 (символьный код поля), отсутствие галки — ничего. Если значений несколько, варианты записываются через запятую — cod1, cod3;
- date: можно использовать текстовое обозначение, или привязку для полей, а можно указать слово:
- today — тогда будет отображаться сегодняшняя дата.
- now — текущая дата и время.
- yesterday — вчера.
- tomorrow — завтра.
- + / - (любое число)h — почему-то в перепутанном порядке, + 24h высчитывается как (сегодня - 24 часа), и наоборот со знаком минус.
Варианты привязок для полей (@binding)
При использовании дополнительных полей можно использовать привязки, т.е. если перевести на человеческий - можно указывать значения не только руками, но и брать их из базы, из файлов, чанков и т.п. Для этого в поле "варианты значений", или "значение по умолчанию" надо вставить конструкции следующего типа:
@CHUNK chunkName | список из чанка с указанным именем |
@RESOURCE id | список из ресурса с указанным id |
@DIRECTORY ./ | список файлов из указанной директории |
@FILE ../assets/test.txt | список из файла |
@SELECT pagetitle, id FROM [[+PREFIX]]site_content WHERE isfolder==0 | получение значений из базы данных |
@EVAL return $modx->runSnippet('snippetName') | получение списка посредством выполнения PHP кода (ходит слух что этой привязки в MODX 3 не будет). |
Примеры вывода дополнительных полей
С помощью тегов MODX и phx
Если у поля одно значение:
[[*tvName]]
Если у поля множество значений:
[[*tvName:contains=`value1`:then=``]]
Или напимер так:
{if $_modx->resource.tvValue == 1}
<p>Какой-то текст или код</p>
{/if}
Если у дополнительного поля установлен формат ввода «Список ресурсов», то результатом вывода будет установленный id ресурса. Для вывода какого-либо значения по id можно использовать FastField:
{$tvListRes | resource : 'pagetitle'}
Дополнительные поля в БД
- _site_tmplvars — параметры того или иного поля.
- _site_tmplvar_access — политика доступа того или иного поля.
- _site_tmplvar_contentvalues — контентное содержание доп полей.
- _site_tmplvar_templates — шаблоны для которых доступно то или иное доп поле.
Работа с доп. полями при помощи xPDO
Создание текстового доп. поля:
$name = 'any_tv'; // имя дополнительного поля
$tempID = '1,2'; // ID шаблонов, для которых поле будет доступно
// проверяем есть ли объект с таким именем, и создаем новый, если нет
if (!$tv = $modx->getObject('modTemplateVar', array('name' => $name))) {
$tv = $modx->newObject('modTemplateVar');
}
// определяем настройки будущего дополнительного поля
$tv->fromArray(array(
'name' => $name,
'type' => 'text',
'caption' => 'Имя ТВ',
'description' => 'Описание ТВ',
'category' => 0
));
// сохраняем
$tv->save();
// собираем в массив для дальнейшей модернизации
$tvs[] = $tv->get('id').'-'.$tempID;
У каждого типа поля свой набор настроек, соответственно, код местами будет отличаться:
TV с изображением
$name = 'image';
$tempID = '1';
$source = 2; // Id источника файлов для TV
if (!$tv = $modx->getObject('modTemplateVar', array('name' => $name))) {
$tv = $modx->newObject('modTemplateVar');
}
$tv->fromArray(array(
'name' => $name,
'type' => 'image',
'caption' => 'Изображение',
'description' => 'Описание ТВ',
'category' => 0
));
$tv->save();
$tvs[] = $tv->get('id').'-'.$tempID;
/* Источник файлов для TV */
$sourceElement = $modx->newObject('sources.modMediaSourceElement');
$sourceElement->fromArray(array(
'object' => $tv->get('id'),
'context_key' => 'web',
), '', true, true);
$sourceElement->set('source', $source);
$sourceElement->save();
/* end Источник файлов для TV */
TV списка одиночного выбора
$name = 'select';
$tempID = '2';
if (!$tv = $modx->getObject('modTemplateVar', array('name' => $name))) {
$tv = $modx->newObject('modTemplateVar');
}
$tv->fromArray(array(
'name' => $name,
'type' => 'listbox',
'caption' => 'Рейтинг отзыва',
'elements' => '1==1||2==2||3==3||4==4||4.5==4_5||5==5',
'category' => 0,
));
$tv->save();
$tvs[] = $tv->get('id').'-'.$tempID;
TV чекбокса множественного выбора
$name = 'category_main';
$tempID = $tempIDCategoryDop;
if (!$tv = $modx->getObject('modTemplateVar', array('name' => $name))) {
$tv = $modx->newObject('modTemplateVar');
}
$tv->fromArray(array(
'name' => $name,
'type' => 'checkbox',
'caption' => 'Показывать',
'elements' => 'Да==Да||Нет==Нет',
'category' => 0,
));
$tv->save();
$tvs[] = $tv->get('id').'-'.$tempID;
TV для компонента FastUploadTV
$name = 'fastImage';
$tempID = '17,6,9,14,12';
$source = 2; // Id источника файлов для TV
if (!$tv = $modx->getObject('modTemplateVar', array('name' => $name))) {
$tv = $modx->newObject('modTemplateVar');
}
$tv->fromArray(array(
'name' => $name,
'type' => 'fastuploadtv',
'caption' => 'Изображение',
'category' => 0,
'source' => $source,
'input_properties' => array(
"path" => "id/{id}/",
"prefix" => "",
"MIME" => "",
"showValue" => true,
"showPreview" => true
),
));
$tv->save();
$tvs[] = $tv->get('id').'-'.$tempID;
/* Источник файлов для TV */
$sourceElement = $modx->newObject('sources.modMediaSourceElement');
$sourceElement->fromArray(array(
'object' => $tv->get('id'),
'context_key' => 'web',
), '', true, true);
$sourceElement->set('source', $source);
$sourceElement->save();
/* end Источник файлов для TV */
TV для компонента MIGX
$name = 'slider';
$tempID = '2';
if (!$tv = $modx->getObject('modTemplateVar', array('name' => $name))) {
$tv = $modx->newObject('modTemplateVar');
}
$tv->fromArray(array(
'name' => $name,
'type' => 'migx',
'caption' => 'Слайдер',
'category' => 0,
'input_properties' => array(
"formtabs" => '[{"caption":"Gallery","fields": [{"field":"img","caption":"Картинка","inputTV":"image"},{"field":"link","caption":"Ссылка"]]}}',
"columns" => '[{"header": "Картинка","dataIndex": "img","renderer":"this.renderImage","width":"100"},{"header": "Ссылка","dataIndex": "link","width":"400"]}'
),
));
$tv->save();
$tvs[] = $tv->get('id').'-'.$tempID;
TV для компонента YandexMaps
$name = 'mapyandex';
$tempID = '2';
if (!$tv = $modx->getObject('modTemplateVar', array('name' => $name))) {
$tv = $modx->newObject('modTemplateVar');
}
$tv->fromArray(array(
'name' => $name,
'type' => 'yandexMaps',
'caption' => 'Метка компании на карте',
'category' => 0,
));
$tv->save();
$tvs[] = $tv->get('id').'-'.$tempID;
Назначение шаблонов доп полям (если создается несколько доп полей, данный блок кода должен идти последним):
foreach ($modx->getCollection('modTemplate') as $template)
{
$templateId = $template->id;
foreach ($tvs as $k => $tv) {
$tvOpt = explode("-", $tv);
$tvid = $tvOpt[0];
$tvTemps = explode(",",$tvOpt[1]);
foreach ($tvTemps as $tvTemp){
if($templateId == $tvTemp){
if (!$tvt = $modx->getObject('modTemplateVarTemplate', array('tmplvarid' => $tvid, 'templateid' => $templateId))) {
$record = array('tmplvarid' => $tvid, 'templateid' => $templateId);
$keys = array_keys($record);
$fields = '`' . implode('`,`', $keys) . '`';
$placeholders = substr(str_repeat('?,', count($keys)), 0, -1);
$sql = "INSERT INTO {$modx->getTableName('modTemplateVarTemplate')} ({$fields}) VALUES ({$placeholders});";
$modx->prepare($sql)->execute(array_values($record));
}
}
}
}
}
Заполнение дополнительного поля через xPDO:
// Выбираем ресурс
$page = $modx->getObject('modResource', 1);
// устанавливаем значение
if (!$page->setTVValue('any_tv', 'Какой-то текст')) {
$modx->log(1, 'Произошла ошибка при сохранении ТВ');
}
Получение значения дополнительного поля через xPDO:
// Выбираем ресурс
$page = $modx->getObject('modResource', 1);
// выводим значение
echo $page->getTVValue('any_tv');
Удаление дополнительного поля через xPDO:
$tv = $modx->getObject('modTemplateVar', array('name' => 'any_tv'));
$tv->remove();
Получение ID созданного доп поля:
// $tv->save();
$id = $tv->get('id');
Выборка ресурсов с TV-параметрами:
// запрашиваем ресурсы с указанными параметрами
$q = $modx->newQuery('modResource');
$q->leftJoin('modTemplateVarResource', 'Price', 'modResource.id = Price.contentid AND Price.tmplvarid = 10');
$q->leftJoin('modTemplateVarResource', 'Country', 'modResource.id = Country.contentid AND Country.tmplvarid = 11');
$q->groupby('modResource.id');
$q->select([
'modResource.*',
'`Price`.`id` AS `Price_id`, `Price`.`tmplvarid` AS `Price_tmplvarid`, `Price`.`contentid` AS `Price_contentid`, `Price`.`value` AS `Price_value`',
'`Country`.`id` AS `Country_id`, `Country`.`tmplvarid` AS `Country_tmplvarid`, `Country`.`contentid` AS `Country_contentid`, `Country`.`value` AS `Country_value`',
'IFNULL(`Price`.`value`, 0) AS `Price_value`',
'IFNULL(`Country`.`value`, "RUS") AS `Country_value`'
]);
$q->where([
[
'Price.value:!=' => 0,
'Price.value:IS NOT' => NULL
], [
'Country.value' => 'RUB',
'OR:Country.value:IS' => NULL
]
]);
$count = $modx->getCount('modResource', $q);
$q->limit(100);
if ($q->prepare() && $q->stmt->execute()) {
$resources = $q->stmt->fetchAll(PDO::FETCH_ASSOC);
}
echo "<p>Всего ресурсов найдено: {$count}</p><hr>";
foreach($resources as $resource) {
echo "<p><b>{$resource['pagetitle']} ({$resource['id']})</b> -
{$resource['Price_value']} {$resource['Country_value']}</p>";
}
За xPDO схемы спасибо Илье Уткину