Очень хитрые TV параметры

У любого ресурса MODX есть ограниченное число полей, таких как pagetitle, content, introtext. Чтобы расширить этот функционал, и добавить, например, картинку к заметке - нужны дополнительные поля.
В MODX они называются Template Variables, то есть, TV.
Это очень мощная система, и тэвэшки можно создавать бесконечно много, с разными свойствами и наворотами. Чем многие и злоупотребляют.
Объясняю почему. Один TV - это одна строка в таблице modTemplateVarResource. Если нужно получить 10 TV - это обычно 10 запросов в базу. Если нужно отсортировать по ним - еще сложнее и дольше.
Вот и выходит, что "MODX тормозит", когда на один ресурс навешано штук 20 ТВ и они выводятся на каждой странице с getResources.
Лично я стараюсь их вообще не использовать, но на ум пришла интересная идея. Нужно дублировать TV в поле properties ресурса, которое хранит json строку с любой информацией.
Вот плагин, для дублирования:
<?php
if ($modx->event->name == 'OnBeforeDocFormSave') {
    $tvs = array();

    foreach ($_POST as $k => $v) {
        if (preg_match('/^tv[0-9]+$/', $k)) {
            $tvs[$k] = $v;
        }
    }

    $properties = $resource->get('properties');
    ksort($tvs);
    $properties['tvs'] = $tvs;
    $resource->set('properties', $properties);
}
Он смотрит в $_POST при сохранении ресурса, и копирует TV куда надо. Обратите внимание, что используются id параметров с префиксом tv. Можно, конечно, и получать имена TV, но это лишняя работа при сохранении ресурса. К тому же, если вы переименуете параметр - эта инфа не обновится самостоятельно. Поэтому, тэвэшки будут просто tv1, tv2, tv3 в массиве tvs.
Отдельный массив tvs нужен, чтобы не затереть что-то нужное, так как поле properties используют и компоненты, например Articles и Tickets. Ключи перед сохранением сортируются, так что TV в поле будут всегда по возрастанию id.
А дальше мы можем выводить их обычным getResources, используя плейсхолдеры. Парсер разбирает массивы в ресурсе и склеивает ключи через точку.
[[+properties.tvs.tv1]]
[[+properties.tvs.tv2]]
[[+properties.tvs.tv3]]
и т.д.
То есть, значения TV параметров будут выводиться без лишних запросов в БД. Конечно, &processTVs работать не будет - ну и фиг с ним.
В любом случае, это легко можно использовать на загруженный сайтах, для ускорения вывода ресурсов. Теоретически, можно даже криво фильтровать по полю properties, но мне так и не удалось передать подходящий вызов в параметр &where.
Можно написать сниппет на pdoTools и он должен нормально выбирать, но я не проверял. В любом случае, эта фильтрация будет очень ограниченной, просто поиск по
`parameters` LIKE '%"tv1":"string"%'

Обновлено 05.02.13

В комментариях был километровый срач, который пришлось почистить, но для любопытных остался скриншот.

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

Илья Уткин
Оу, даже не задумывался раньше о том, что можно использовать еще и это поле у ресурсов. Блин, классно, спасибо)
Виталий Киреев
Плохо, что без названий. Разве так упомнишь по номерам что куда вставлять...
Василий Наумкин
В дереве элементов есть id ТВ параметров. Так что, никаких проблем.
Алексей
Да, интересная идея! Возьмем на заметку! Вообще, производительность этих TV настолько слабая, что очень затрудняет их использование.
Иван Климчук
Слабая скорость из-за очень гибкой и мощной по возможностям структуры данных и двойного join (сначала джойним таблицу с самими TV, а затем еще и таблицу со значениями этих TV).
Евгений Борисов
начиная с версии Evolution идеология у TV параметров была другая. Их должны были использовать для формирования визуальных элементов при редактировании данных из других таблиц. А т.к. это сложный хинт и так делают редко, то пользуются ТВшками именно для хранения данных. Яркий пример иного использования TV - плагин TagSaver для Evo.
Евгений Борисов
Еще в ноябре 2011 писал такой плагин, когда Валентин рассказал мне про property. Я так понимаю вся эта возня из-за того, что про него никто не упомянул в этом топике. Да, общественность только сейчас про эти фишки узнает... Обидно(
А вот моя версия плагина.
<?php
if($modx->event->name=='OnDocFormSave'){
$template = $resource->get('template');
$templateObj=$modx->getObject('modTemplate', $template);
$tvList=$templateObj->getTemplateVarList();
$data=array();
foreach ($tvList['collection'] as $tv) {
    $name=$tv->get('name');
    $data[$name] =  $resource->getTVValue($tv->get('id'));
}
  $resource->setProperties($data);
  $resource->save();
}
Как видно, я тут работаю не POST данными, а с уже сохраненными значениями, т.к. могут быть и другие плагины которые модифицируют значения TV параметров. +1 SQL запрос в админке при сохранении документа я думаю это не страшно.
Евгений Борисов
ноябре 2012)) Не привык еще к 2013 году)))
Василий Наумкин
Как то сложно ты получаешь тэвэшки. Почему не через getMany?
$tvs = $resource->getMany('TemplateVars')
Будет коллекция объектов всех ТВ ресурса.
А вся возня оттого, что мне надоели комментарии Валентина, де он мне что-то рассказал, а я это присвоил и выдал за своё. Раньше как то терпел, а вот вчера тупо надоело и захотелось увидеть хоть одно подтверждение этих обвинений.
СикретНаме
Почитал, вспомнил, как улыбнули слова: "по семейным обстоятельствам, Валентин не сможет...", ещё раз улыбнуло :0)
Я видел этот Talk и не понимаю, зачем взрослые дяди огород разводят. Ну сделали Вы Hybrid, ну сделал Валентин Talk - ну так и развивали бы их каждый по своему. Кто-то из вас у другого что, почти весь код украл? Вроде нет. О чём сыр-бор - НЕ понятно...
Виталий Киреев
Я эти пропертис еще в прошлом июне в своем проекте активно использовал (поэтому сразу добавил их поддержку в свой fastField), причем примерно так же, как в варианте Евгения Борисова. Что мне теперь тоже трясти "авторскими правами"?)) Правда в итоге все переписал на собственные таблицы, потому что стали нужны выборки по этим твшкам. То есть в админке редактируются TV, а плагин их запоминают в кастомную таблицу. Практически прообраз кастомного ресурса)...
Василий Наумкин
Выходит, я и у тебя идею украл!
Вот я молодец!
Евгений Борисов
Согласен. Можно сократить
$template = $resource->get('template');
$templateObj=$modx->getObject('modTemplate', $template);
$tvList=$templateObj->getTemplateVarList();
до
$tvList = $resource->getMany('TemplateVars')
В ней все равно используется getTemplateVars(); Но непомню что меня смутило тогда. Скорее всего возникла мысль, что если без дополнительной инициализации доставать значения, то есть вероятность не получить еще не сохраненные данные. Т.е. вернутся те, которые были во время предыдущего сохранения, т.к. объект еще обновиться не успел. Проверять не стал и поэтому создал новый объект.
Владимир
Почему то не срабатывает плагин. Посмотрел в базе, в ячейку properties в таблице modx_site_content, не копируются туда значения из tv ... Что не так ?... не пойму...
Алексей
Видно, Василий, ваш код еще никто не пробовал) Или молчат все.
Ошибка здесь
$properties['tvs'] = ksort($tvs);
ksort не возвращает массив, она возвращает true или false, поэтому так:
ksort($tvs);
$properties['tvs'] = $tvs
Василий Наумкин
Поправил, спасибо!
bezumkin.ru
Личный сайт Василия Наумкина
Прямой эфир
Василий Наумкин
22.11.2024, 03:33:54
Спасибо!
inna
06.11.2024, 15:47:13
Да. Все работает. Спасибо.
Василий Наумкин
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
Давай-давай!