pdoTools 1.2.0

Обновил мега-библиотеку для создания быстрых сниппетов. Это интересно только разработчикам, юзерам
специально обновляться не нужно — компонент загрузится при установке свежих Tickets или MS2.
Ну а если обновляетесь вручную — то не забудьте обновить и их, иначе будут небольшие косячки.

Итак, что нового?

Поддержка ТВ параметров

Теперь сниппету pdoTools можно указывать &includeTVs=`tv1,tvname2,mytv` и эти ТВ параметры будут выбраны автоматически.

Имейте в виду, что каждый ТВ — это джоин таблицы. Вроде тормозов не даёт, но вдруг? Заодно есть и параметр tvPrefix, для легкого переезда с getResources. По умолчанию — пустой.

Поддержка специальных плейсхолдеров

Саму идею специальных плейсхолдеров я описывал тут. В новой версии она доведена до ума и теперь, чтобы пользоваться проверкой на пустой плейсхолдер, в чанке нужно написать вот так:
[[+placeholder]]

<!--pdotools_placeholder Этот плейсхолдер имеет значение: [[+placeholder]]-->

Если placeholder не пуст — вы увидите его значение с припиской. Зачем это нужно?
1. Это немного быстрее, чем
[[+placeholder:notempty=`[[+placeholder]]`]]
2. Это работает при включенном fastMode.

Такой странный формат записи выбран не случайно: если вы будете рендерить чанк не в pdoTools — то ничего лишнего не покажется.

Новый метод setConfig()

Как известно, MODX кэширует загруженные классы, помещая их в массив modX::services сразу после инициализации.

Таким образом, когда вы делаете два раза modX::getService('pdoTools', 'путь до компонента', $scriptProperties); — класс инициализируется только один раз. Это значит, что во второй раз до него не доходят новые параметры.

Есть минимум 2 варианта решения проблема. Принудительно обновить настройки:
$pdoTools->config = array_merge($pdoTools->config, $scriptProperties);
или удалить класс их кэша перед инициализацией
if (!empty($modx->service['pdofetch'])) {unset($modx->services['pdofetch']);}

Ну а теперь появился и третий способ:
$pdoFetch = $modx->getService('pdofetch','pdoFetch', MODX_CORE_PATH . 'components/pdotools/model/pdotools/',$scriptProperties);
$pdoFetch->setConfig($scriptProperties);

Это загрузит стандартные настройки класса и добавит к ним ваши собственные. Таким образом, в любой момент можно «сбросить» работу сниппета.
Да, лог работы с таймингами при этом тоже очищается, а не как раньше, склеивался.

Улучшен метод makePlaceholders()

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

$pdoFetch = $modx->getService('pdofetch','pdoFetch', MODX_CORE_PATH . 'components/pdotools/model/pdotools/',$scriptProperties);

$arr = array(
	'var1' => 'value1'
	,'var2' => array(
		'subvar1' => 'subvalue1'
		,'subvar2' => 'subvalue2'
	)
);

print_r($pdoFetch->makePlaceholders($arr));die;

В ответ получим такую картину:
Array (
    [pl] => Array (
            [var1] => [[+var1]]
            [var2.subvar1] => [[+var2.subvar1]]
            [var2.subvar2] => [[+var2.subvar2]]
        )

    [vl] => Array (
            [var1] => value1
            [var2.subvar1] => subvalue1
            [var2.subvar2] => subvalue2
        )
)

Заключение

Новые изменения позволят вам работать с pdoTools еще быстрее и продуктивнее. Лично я уже обновил Tickets и MS2, выкинув ненужные теперь куски кода из сниппетов. Ну, там где была выборка ТВ и специальные плейсхолдеры.

Следующая заметка
Компонент Extras


Комментарии ()

  1. Василий 28 апреля 2013, 21:49 # 0
    Василий, доброго времени.
    Насколько близок показатель Total time в логах вывода к времени полной генерации страницы, если, скажем, это единственное, что на этой странице выводится?
    Цифры, которые показываются в логе — поражают, а реально страница генерируется намного дольше.
    0.3822520: Total time
    против
    2.4362 s
    1. Василий Наумкин 28 апреля 2013, 21:57 # 0
      Учитывается время именно на операции pdoTools. В классе есть переменная timings, куда складываются все операциии, а при вызове getTime() — суммируются и форматируются.

      Что выводится в шаблоне, и с какой скоростью — pdoTools не знает.

      Попробуй вызвать на странице в шаблоном 0, и вывести там плейсхолдер [^t^] сразу после вывода снипета с pdoTools — вот и сравнишь.

      У меня, например, вот так:


      Всё что можно — из кэша, время тратится только на вывод тикетов.
      1. Василий 28 апреля 2013, 22:08 # 0
        Собственно на пустом шаблоне и сравниваю.
        Согласно логам: 0.0269321: Total time
        Согласно [^t^]: 0.8124 s
        Хочется выяснить, нормальное ли это явление, или реальное время загрузки страницы должно быть близко к показателю Total time.
        Спасибо
        1. Василий Наумкин 28 апреля 2013, 22:25 # 0
          Проверил на тестовом сайте.

          Вообще без ничего, нулевой шаблон: 0.0612 s

          Вызов сниппета с pdoTools:
          Общий рендер 0.0992 s, при этом лог pdoTools выдаёт 0.0154259, а значит разница 0,08377 s, что очень близко к пустому шаблону.

          Возможно, у тебя мешается какой-то плагин. Советую сделать чистый сайт на modx-test.com и поэксперементировать там.
          1. Василий Наумкин 28 апреля 2013, 22:29 # 0
            Забыл уточнить: для таких точных цифр нужно запускать pdoTools либо вообще без чанка (&tpl=``), либо с &fastMode=`1`.
            Иначе при выводе чанков могут остаться необработанные плейсхолдеры, которые парсер будет пытаться отрендерить.

            Отсюда будут дополнительные тормоза, и большая разница во времени.
            1. Василий 28 апреля 2013, 22:50 # 0
              Бомба.
              Не подозревал до сегодняшнего вечера, что плагин fastField настолько тормозит страницу.
              Большое спасибо за «наводку»!
      2. Виталий Батушев 30 апреля 2013, 04:56 # 0
        Возник вопрос. Решил использовать includeTVs.
        Код вызова сниппета на странице:
        [[getCourses?&tpl=`course.item`&parent=`2`&includeTVs=`price`]]
        Выдача:
        0.0005391: xPDO query object created
        0.0007410: Added where condition: published=1, deleted=0, parent=2
        0.0008590: Included list of tvs: price.
        0.0006471: Added selection of modResource: SQL_CALC_FOUND_ROWS `modResource`.`id`, `modResource`.`type`, `modResource`.`contentType`, `modResource`.`pagetitle`, `modResource`.`longtitle`, `modResource`.`description`, `modResource`.`alias`, `modResource`.`link_attributes`, `modResource`.`published`, `modResource`.`pub_date`, `modResource`.`unpub_date`, `modResource`.`parent`, `modResource`.`isfolder`, `modResource`.`introtext`, `modResource`.`content`, `modResource`.`richtext`, `modResource`.`template`, `modResource`.`menuindex`, `modResource`.`searchable`, `modResource`.`cacheable`, `modResource`.`createdby`, `modResource`.`createdon`, `modResource`.`editedby`, `modResource`.`editedon`, `modResource`.`deleted`, `modResource`.`deletedon`, `modResource`.`deletedby`, `modResource`.`publishedon`, `modResource`.`publishedby`, `modResource`.`menutitle`, `modResource`.`donthit`, `modResource`.`privateweb`, `modResource`.`privatemgr`, `modResource`.`content_dispo`, `modResource`.`hidemenu`, `modResource`.`class_key`, `modResource`.`context_key`, `modResource`.`content_type`, `modResource`.`uri`, `modResource`.`uri_override`, `modResource`.`hide_children_in_tree`, `modResource`.`show_in_tree`, `modResource`.`properties`, `TVprice`.`value` as `price`
        0.0000248: Sorted by menuindex, asc. Limited to 10, offset 0
        0.0007582: SQL prepared "SELECT SQL_CALC_FOUND_ROWS `modResource`.`id`, `modResource`.`type`, `modResource`.`contentType`, `modResource`.`pagetitle`, `modResource`.`longtitle`, `modResource`.`description`, `modResource`.`alias`, `modResource`.`link_attributes`, `modResource`.`published`, `modResource`.`pub_date`, `modResource`.`unpub_date`, `modResource`.`parent`, `modResource`.`isfolder`, `modResource`.`introtext`, `modResource`.`content`, `modResource`.`richtext`, `modResource`.`template`, `modResource`.`menuindex`, `modResource`.`searchable`, `modResource`.`cacheable`, `modResource`.`createdby`, `modResource`.`createdon`, `modResource`.`editedby`, `modResource`.`editedon`, `modResource`.`deleted`, `modResource`.`deletedon`, `modResource`.`deletedby`, `modResource`.`publishedon`, `modResource`.`publishedby`, `modResource`.`menutitle`, `modResource`.`donthit`, `modResource`.`privateweb`, `modResource`.`privatemgr`, `modResource`.`content_dispo`, `modResource`.`hidemenu`, `modResource`.`class_key`, `modResource`.`context_key`, `modResource`.`content_type`, `modResource`.`uri`, `modResource`.`uri_override`, `modResource`.`hide_children_in_tree`, `modResource`.`show_in_tree`, `modResource`.`properties`, `TVprice`.`value` as `price` FROM `modx_site_content` AS `modResource` WHERE  ( `modResource`.`published` = 1 AND `modResource`.`deleted` = 0 AND `modResource`.`parent` = 2 )  ORDER BY menuindex asc LIMIT 10 "
        0.0035692: Total time
        Без includeTVs сниппет работает, чанк парсится. С includeTVs только вышеуказанное сообщение. Глядя в него, не вижу там никакого джойна с modTemplateVarResource, все пытается вытянуться из modResource.
        ОК, полез в код смотреть и вижу, что слияние tvsJoin происходит только при наличии непустого leftJoin (функция addJoins). Что странно, ведь заявлено: «Теперь сниппету pdoTools можно указывать &includeTVs=`tv1,tvname2,mytv` и эти ТВ параметры будут выбраны автоматически
        И это бы ладно. Но если я добавлю джойн с modTemplateVarResource, то не получится ли дублирование джойнов? Ведь он уже сформирован в tvsJoin.
        Или я чего-то недопонимаю?
        1. Василий Наумкин 30 апреля 2013, 06:03 # 0
          Ну вот, уже и ошибиться нельзя.

          Обновляйся, версия 1.2.1
          — Fixed not working «includeTVs» when «leftJoin» is empty.

          P.S. Логи лучше в code оформлять, а не в blockquote. Исправил.
          1. Виталий Батушев 30 апреля 2013, 06:06 # 0
            ¡Qué buena noticia! :)

            Лог пытался оформить в code, но был эстетически неудовлетворен оформлением и поставил blockquote.

            P.S. Обновился, проверил — всё как надо. Спасибо!
            1. Василий Наумкин 30 апреля 2013, 06:13 # 0
              На вкус и цвет, конечно, но в blockquote портянка выходит, а в code все понятно.

              A su salud!
              1. Виталий Батушев 30 апреля 2013, 06:26 # 0
                Su — это «ваше». «Tu» es más correcto.
                1. Василий Наумкин 30 апреля 2013, 07:05 # 0
                  Gracias, но вообще, это гугла косяк!
        2. Мордынский Николай 30 апреля 2013, 10:40 # 0
          Добрый день.
          Подскажите как в модх хранятся плейсхолдеры.
          Нужно собрать плейсхолдеры ресурса которые установлены?
          1. Василий Наумкин 30 апреля 2013, 10:43 # 0
            Плейсхолдер — это специальное слово в чанке, которое потом заменяется на значение при выводе этого чанка через php.

            Так и хранятся, в чанках.
            1. Мордынский Николай 30 апреля 2013, 11:03 # 0
              Но как то чанки распознают откуда брать значение плейсхолдера. я так понимаю где то должен быть массив

              (name=>value) в который помещаются значения плейсхолдеров. Можно как то этот массив для 1 ресурса вывести?
              1. Василий Наумкин 30 апреля 2013, 11:46 # 0
                Чанки никак не распознают.

                Php берет значения из ресурса, потом берет чанк, потом заменяет плейсхолдеры на значения.

                Поля одного ресурса можно получить так
                // Получаем объект ресурса
                if ($res = $modx->getObject('modResource', $idресурса)) {
                	// получаем массив значений из объекта
                	$array = $res->toArray();
                
                	// печатаем массив значений
                	print_r($array);
                
                	// или выводим произвольный чанк с заменой плейсхолдеров на значения
                	echo $modx->getChunk($имячанка, $array);
                }
                1. Мордынский Николай 30 апреля 2013, 13:31 # 0
                  огромное спасибо все понял
          2. Андрей Иванов 13 мая 2013, 14:24 # 0
            Василий, А пот ТВ данный снипет может фильтровать, как &tvFilters в Getresources?
            1. Василий Наумкин 13 мая 2013, 15:16 # 0
              Можно, смотри
              [[!pdoSnippet?
              	&includeTVs=`action,discount`
              	&sortby=`TVaction.value`
              	&where=`{"TVdiscount":"1"}`
              ]]
              1. Андрей Иванов 14 мая 2013, 17:07 # 0
                понятно, спасибо, осталась одна проблема в работе по замене getresource)… Нужно вывести товары от $pricen до $pricev. выполняю такой запрос
                'sortby' => 'TVprice.value',
                		    'sortdir' => 'ASC',
                		    'where1'=> '{"template":2,"price.value:>=":'.$pricen.', "AND:TVprice.value:<=":'.$pricev.'}'
                Данная выборка проходит странным образом, считает походу ТВ параметры текстовыми. как сделать чтобы нормально выводилось?)

                1. Василий Наумкин 14 мая 2013, 17:51 # 0
                  ТВ и есть текстовые. Если хочешь их сравнивать в циферками, то нужно приводить тип, как то так:
                  AND:CAST(TVprice.value as INTEGER):<=
                  Подробнее можно тут почитать.
                  1. Андрей Иванов 14 мая 2013, 19:49 # 0
                    вызываю так:
                    'where=> '{"template":2,"CAST(TVprice.value AS SIGNED INTEGER):>=":'.$pricen.', "AND:CAST(TVprice.value AS SIGNED INTEGER):<=":'.$pricev.'}'
                    — не работает,

                    пробовал добавлять следующую строку в pdofetch.class.php, то же не запустилось(

                    $this->config['tvsSelect'][$alias] = 'CAST(`'.$alias.'`.`value` AS UNSIGNED INTEGER ) AS `'.$tvPrefix.$tv['name'].'`';
                    1. Андрей Иванов 14 мая 2013, 19:57 # 0
                      Сортировка работает:
                      'sortby' => 'CAST(TVprice.value AS SIGNED INTEGER)'
              Добавление новых комментариев отключено.