Pdotools modx: pdoTools / Компоненты / docs.modx.pro

pdoTools в MODX — замена стандартных сниппетов

Категория: Разработка сайтов

«pdoTools» — это пакет, содержащий инструменты для быстрой разработки сниппетов в MODX Revolution, а так же набор готовых сниппетов для повседневной работы. Именно о этих сниппетах и пойдёт речь в статье, а точнее о том, как я заменял ими стандартные «сниппеты» и для чего это делал.

Так чем же хорош компонент «pdoTools»? А тем, что позволяет создавать сниппеты без использования xPDO — MODX’овской надстройки над PHP расширением — PDO. Небольшое пояснение по этому поводу. Изначально все запросы к базе данных осуществлялись на SQL (структурированный язык запросов), и все бы хорошо, но вот синтаксис этих запросов к различным СУБД (MySQL, MSSQL, Oracle, FireBird…) зачастую отличается. Приходилось затачивать код под определенную СУБД и переписывать его при использовании с другой СУБД. Чтобы избежать данного неудобства для PHP было написано расширение PDO, которое позволило создать универсальный интерфейс для работы с базами данных. В MODX пошли дальше и для удобства разработки написали надстройку над PDO, которую назвали xPDO. Эта надстройка делает работу с БД из под MODX (а мы помним, что MODX, это не просто CMS, это CMF) ещё более удобной и безопасной, но за всё надо платить и в нашем случае это скорость работы. xPDO в качестве результата запроса возвращает объекты и при большом количестве возвращаемых объектов (тысячи) время генерации страницы значительно возрастает. Поэтому наш соотечественник Василий Наумкин решил разработать собственный инструмент для создания сниппетов, которые работают через PDO, а не через xPDO. Как вы поняли, инструмент этот и есть «pdoTools».

Далее последуют примеры, как я производил замены всем привычных сниппетов на аналоги из «pdoTools». Описывать все их параметры не вижу смысла, так как они уже есть на сайте разработчика, но на некоторых моментах я все же заострю внимание.

Замена getResources на pdoResources

Сниппеты для вывода ресурсов. Про эту замену я писал отдельную статью, она получилась не слишком содержательной, но кому-то может и пригодилась. Пример замены сниппета «getRecources» на «pdoRecources» с привязкой к «pdoPage» чуть ниже.

Замена getPage на pdoPage

Сниппеты для постраничного вывода ресурсов в MODX Revolution.

Как было:


[[!getPage@articlePaging?
    &elementClass=`modSnippet`
    &element=`getResources`
    &parents=`36,37,38,39,40`
    &depth=`1`
    &limit=`5`
    &includeTVs=`1`
    &tpl=`articleTpl`
]]

«articlePaging» — это набор параметров, где хранится содержимое чанков сниппета для оформления вывода. Для «pdoPage» я приведу их содержимое, так как оно несколько отличается от имеющихся в «getPage».

Как стало:


[[!pdoPage?
    &parents=`36,37,38,39,40`
    &depth=`1`
    &limit=`5`
    &includeTVs=`img-news,tags,HitsPage`
    &tpl=`articleTpl`
    &tplPageWrapper=`@INLINE [[+prev]][[+first]][[+pages]][[+last]][[+next]]`
    &tplPage=`@INLINE <a href="[[+href]]" title="[[+pageNo]]">[[+pageNo]]</a>`
    &tplPageActive=`@INLINE <span>[[+pageNo]]</span>`
    &tplPageFirst=`@INLINE <a href="[[+href]]">First</a>`
    &tplPageLast=`@INLINE <a href="[[+href]]">Last</a>`
    &tplPagePrev=`@INLINE <a href="[[+href]]">«</a>`
    &tplPageNext=`@INLINE <a href="[[+href]]">»</a>`
    &tplPageFirstEmpty=``
    &tplPageLastEmpty=``
    &tplPagePrevEmpty=``
    &tplPageNextEmpty=``
]]

Во-первых, пропали параметры «&elementClass» и «&element». Указывать их есть смысл только если в качестве источника постраничного вывода используется не «pdoRecources». Вместо «&includeTVs=`1`» пришлось указать имена всех tv параметров, участвующих в выводе. Остальные изменения связаны исключительно с чанками. В этом примере я специально отказался от использования набора параметров, чтобы вы увидели какие плейсхолдеры в каких чанках используются.

Замена getResourcesTag на pdoResources

В состав компонента getRecources входит так же сниппет getResourcesTag, предназначенный для вывода ресурсов, привязанных к определенному тегу. Этот сниппет так же можно заменить на pdoResources. Как было:

[[!getResourcesTag?
    &parents=`36,37,38,39,40`
    &depth=`1`
    &tpl=`articleTpl`
    &limit=`6`
    &includeTVs=`1`
]]
Как стало:

[[!pdoResources?
    &parents=`36,37,38,39,40`
    &depth=`1`
    &tpl=`articleTpl`
    &limit=`6`
    &includeTVs=`img-news,tags,HitsPage`
    &where=`{"tags:LIKE":"%[[!getUrlParam? &name=`tag`]]%"}`
]]

Сразу обращаем внимание на параметр — &where=`{«tags:LIKE»:»%[[!getUrlParam? &name=`tag`]]%»}` В нём мы указываем критерий выборки ресурсов. Если простыми словами, то выбираем все ресурсы, у которых в TV параметре «tags» встречается слово, передаваемое в GET параметре «tag». А его, в свою очередь, мы вытаскиваем из URL с помощью сниппета getUrlParam, который вы можете установить из репозитория

Кстати, возможно есть и какие-то другие способы, если знаете, то поделитесь.

Замена breadCrumbs на pdoCrumbs

Как было:


[[Breadcrumbs? &amphomeCrumbTitle=`Главная`]]

Как стало:


[[pdoCrumbs?
    &showHome=`1`
    &outputSeparator=` » `
    &tplHome=`@INLINE Главная`
]]
После замены пришлось немного подредактировать CSS оформление выводимых хлебных крошек, так как «pdoCrumbs» в отличии от «BreadCrumbs» на выходе дает не список li, а просто набор ссылок, разделенных сепаратором, указанным в сниппете.

Замена Wayfinder на pdoMenu

Сниппеты предназначены для генерации меню на сайте. Здесь писать нечего, так как кроме замены названия сниппета менять ничего не пришлось. Выводимый результат остался тот же самый. Особого прироста в скорости генерации страницы я не заметил, но у меня небольшой сайт, поэтому это не удивительно.
[[pdoMenu? &startId=`0` &level=`2`]]

Замена GoogleSitemap на pdoSitemap

Сниппеты для генерации карты сайта. Заменяется только название. У меня на сайте есть отдельная статья по созданию карты сайта в modx revolution при помощи сниппета «GoogleSitemap» — Карта сайта в MODX Revolution (GoogleSiteMap). Для «pdoSitemap» делается всё аналогичным образом.


[[!pdoSitemap]]

Остальные сниппеты

В состав «pdoTools» входит ещё 2 сниппета. Я не применял их пока на практике, поэтому ничего писать про них не буду. Это сниппеты «pdoUsers» для вывода списка польователей сайта и «pdoNeighbors» для вывода соседних ресурсов.

На этом всё. Возможно, к тому моменту когда вы будете читать эту статью, появятся ещё статьи, связанные с пакетом «pdoTools». Найти их можно перейдя по соответствующему тегу. Про неточности в статье пишите в комментариях — буду исправлять.

Оптимизация pdoTools | Зона разработки

  • Оптимизация
  • pdoTools
  • Разработка
  • MODX

Сегодня поговорим о популярной библиотеке pdoTools. Она предоставляет полный набор необходимых для разработки сайта сниппетов. Для их использования не нужны знания программирования. Если возможностей этих сниппетов не хватает, то можно создать своё решение, используя готовые классы pdoTools и pdoFetch. Библиотека позволяет решить практически все задачи. Но и у неё есть ограничения. Для использования на больших сайтах с высокой посещаемостью её необходимо оптимизировать.

Основные задачи, с которыми вы можете столкнуться —

  • Оптимизация SQL запроса.
  • Компиляция файлов шаблонизатора Fenom на каждый запрос.

Оптимизация SQL запроса

Так как карта ресурсов теперь неполная или вообще отключена, то основные сниппеты не смогут выводить ресурсы указанных родителей. Причина в том, что pdoTools использует метод modX::getChildIds(), который получает id дочерних ресурсов из карты ресурсов. А она неполная. Чтобы выкрутиться из этой ситуации, придётся изменить SQL запрос. Сделать это можно двумя способами.

Предупреждение!

К сожалению, оба способа имеют ограничения по уровню вложенности. Они эффективны только для первых двух уровней. Первый уровень — это непосредственные дочерние ресурсы указанных родителей. Второй уровень — это дочерние ресурсы первых дочерних ресурсов.

1 способ

Этот способ самый простой. Нужно добавить джойн таблицы ресурсов, в котором определить родителей. Причём указать их нужно в самом джойне, а в параметре parents нужно оставить 0.


// Один уровень вложенности
{'!pdoResources' | snippet : [
    'parents'=>'0',
    'innerJoin' => [
        "Parents" => [
            "class" => "modResource",
            "on" => "`modResource`.`parent` = `Parents`.`id` AND `Parents`.`id` IN (1,2,3,4,5)",
        ]
    ],
    'tpl'=>'@INLINE <p>{$pagetitle}</p>',
    ...
]}
// Два уровня вложенности
{set $table = $modx->getTableName('modResource')} 
{'!pdoResources' | snippet : [
    'parents'=>'0',
    'innerJoin' => [
        "Parents" => [
            "class" => "modResource",
            "on" => "`modResource`.`parent` = `Parents`.`id` AND `Parents`.`id` IN (SELECT `id` FROM {$table} WHERE `id` IN (1,2,3,4,5) OR `parent` IN (1,2,3,4,5))",
        ]
    ],
    'tpl'=>'@INLINE <p>{$pagetitle}</p>',
    ...
]}

Если вы не меняете периодически префикс таблиц, то в подзапросе для двух уровней можно сразу указать имя таблицы ресурсов.

В большинстве случае этого способа хватает. Но если хотите выжать из оптимизации максимум, то придётся задействовать второй способ.

2 способ

Этот способ повышает производительность примерно на 15%. Замеры производились на сложных запросах, в которых использовались TV. А значит было много джойнов. Возможно на простых запросах эффективность этого способа будет не так заметна.

В данном случае работы будет больше. Необходимо изменить механизм формирования SQL запроса. А значит нужно создать свой класс, расширяющий класс pdoFetch, ответственный за этот самый SQL запрос. У меня он получился такой. Создать его можно прямо рядом с исходным классом pdoFetch.

Далее его нужно подключить. В системных настройках pdoTools находим настройку pdoFetch.class и указываем в ней значение «pdotools.pdofetchopt». Теперь можно использовать дополнительный параметр from у сниппетов.


{'!pdoResources' | snippet : [
    'parents'=>'0',
    'from' => '(SELECT * FROM modx_site_content WHERE parent IN (1,2,3,4,5))',
    'limit' => 10,
    'tpl'=>'@INLINE <p>{$pagetitle}</p>',
]}

Получается вот такой лог


0. 0000000: pdoTools loaded
0.0000000: xPDO query object created
0.0050001: Added selection of modResource: `id`, `type`, `contentType`, `pagetitle`, `longtitle`, `description`, `alias`, `alias_visible`, `link_attributes`, `published`, `pub_date`, `unpub_date`, `parent`, `isfolder`, `introtext`, `richtext`, `template`, `menuindex`, `searchable`, `cacheable`, `createdby`, `createdon`, `editedby`, `editedon`, `deleted`, `deletedon`, `deletedby`, `publishedon`, `publishedby`, `menutitle`, `donthit`, `privateweb`, `privatemgr`, `content_dispo`, `hidemenu`, `class_key`, `context_key`, `content_type`, `uri`, `uri_override`, `hide_children_in_tree`, `show_in_tree`, `properties`
0.0000000: Added FROM data: (SELECT * FROM modx_site_content WHERE parent IN (1,2,3,4,5))
0.0000000: Processed additional conditions
0.0000000: Added where condition: modResource.published=1, modResource.deleted=0
0.0000000: Sorted by modResource.publishedon, DESC
0.0000000: Limited to 10, offset 0
0. 0000000: SQL prepared "SELECT `modResource`.`id`, `modResource`.`type`, `modResource`.`contentType`, `modResource`.`pagetitle`, `modResource`.`longtitle`, `modResource`.`description`, `modResource`.`alias`, `modResource`.`alias_visible`, `modResource`.`link_attributes`, `modResource`.`published`, `modResource`.`pub_date`, `modResource`.`unpub_date`, `modResource`.`parent`, `modResource`.`isfolder`, `modResource`.`introtext`, `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` FROM (SELECT * FROM modx_site_content WHERE parent IN (1,2,3,4,5)) AS `modResource` WHERE  ( `modResource`.`published` = 1 AND `modResource`.`deleted` = 0 )  ORDER BY modResource.publishedon DESC LIMIT 10 "
0.0000000: SQL executed
0.0000000: Rows fetched
0.0000000: Created inline "modChunk" with name "294ced7c63d3421f4f42aef9c0108b40"
0.0000000: Retrieved data from cache "default/pdotools/modchunk/294ced7c63d3421f4f42aef9c0108b40"
0.0049999: Returning processed chunks
0.0100000: Total time
2 097 152: Memory usage

Какой из способов выбрать нужно решать в зависимости от задачи и сложности запросов.

Проблема карты ресурсов

Если вы решили всё-таки не трогать карту ресурсов, то у вас может возникнуть другая проблема. Представьте сайт, у которого несколько главных разделов, и уровень вложенности дочерних ресурсов у них разный. Например, для новостей используются подразделы (Интересное, Политика, Проишествия, Спорт, Музыка и т.д.), а в разделах «Статьи» и «Культурные мероприятия» лишний уровень не нужен. Таким образом, сами новости находятся на третьем уровне, а статьи и культурные мероприятия на втором. Когда на главной странице нужно вывести в одну ленту событий данные из этих разделов, то, как правило, используют сниппет pdoResources, у которого в параметре parents перечисляют id нужных разделов. И обычно их единицы. Но если посмотреть готовый SQL запрос, то окажется, что количество id родителей значительно выросло.

Это происходит потому, что сниппет не ограничивается только указанными родителями. Он выводит все дочерние ресурсы на указанную глубину, которая по-умолчанию имеет значение 10. Для небольших и средних сайтов решение вполне безобидное. Но для больших сайтов это чревато тем, что перечень этих id будет содержать десятки, а может и сотни тысяч единиц. MySql придётся дробить запросы, а потом склеивать полученные результаты. Это, как вы понимаете, отрицательно влияет на производительность. Оба вышеописанных способа позволяют решить и эту проблему.

Параметр «depth» сниппетов pdoTools

Я выделил это в отдельный пункт по причине значимости. Этот параметр используется в некоторых сниппетах pdoTools. Дело в том, что им не всегда пользуются правильно. В описании про него написано следующее:

Глубина поиска дочерних ресурсов от родителя.

Я встречал ситуации, когда глубину считали от уровня всего сайта, а не от указанных родителей. Но гораздо чаще сталкивался с нумерацией от родителей, где для вывода непосредственных дочерних элементов указывалось значениe 1, для следующего уровня значение 2, и т.д. Так вот, несмотря на очевидность, это решение неправильное, так как счёт идёт от нуля. Т.е. чтобы вывести 2 уровня ресурсов указанных родителей, нужно указать значение 1.

Компиляция файлов шаблонизатора Fenom на каждый запрос

Про недоработанный механизм кэширования элементов библиотеки pdoTools я уже много раз говорил. Повторяться не буду. Сейчас мы раскроем другую проблему, влияющую на производительность. Разговор пойдёт про компиляцию и кэширование самого шаблонизатора Fenom. В pdoTools кэшированием распарсенного контента управляет системная настройка pdotools_fenom_cache (Кэширование скомпилированных чанков). У многих она выключена, что заставляет Fenom на каждый запрос заново компилировать не только чанки, но и контент страницы (хотя в названии говорится только про чанки). А если её включить, то на больших сайтах можно получить сотни тысяч файлов в кэше. Т.е. практически на каждую страницу. Многие поэтому и отключают. Но такое возможно только при неправильной разметке, когда в контенте самого ресурса размещается логика Fenom. Если убрать всю логику в шаблон, а в контенте оставить только текст и теги MODX, то для Fenom все страницы с таким шаблоном будут выглядеть одинаково. А значит и файл кэша будет только один.

Заключение

Возможно данные решения пригодятся не всем. Возможно кто-то решит эти задачи по своему. Главное — знать о проблемах, с которыми вы можете столкнуться на больших сайтах. Но на этом тема про pdoTools ещё не закрыта. Есть ещё ряд задач, которые предстоит решить. Одна из них — пагинация. Но об этом поговорим в следующей статье.

0   2512

Последние дополнения MODX

ПРИМЕЧАНИЕ: эти дополнения не проверялись ни на безопасность, ни на надежность. Для Extras by Sepia River перейдите сюда.

Дата:

Расширение объектов modUser и modResource Посмотреть это дополнение на MODX.com.

Дата:

Удалите неприглядный жир на животе с вашего сайта MODX Посмотреть это дополнение на MODX.com.

Дата:

Плагин маршрутизации

, который обрабатывает запросы для разных контекстов Посмотреть это дополнение на MODX. com.

Дата:

Администрирование таблиц базы данных для MODX Revolution Посмотреть это дополнение на MODX.com.

Дата:

pdoTools для MODX 2.x Посмотреть это дополнение на MODX.com.

Дата:

Электронная коммерция Посмотреть это дополнение на MODX.com.

Дата:

Переключение шаблонов ресурсов на лету Посмотреть это дополнение на MODX.com.

Дата:

Набор инструментов CSS и JS для MODX CMS Посмотреть это дополнение на MODX. com.

Дата:

Альтернативный медиа-источник Amazon S3 для MODX Revolution Посмотреть это дополнение на MODX.com.

Дата:

Расширенная переменная шаблона изображения Посмотреть это дополнение на MODX.com.

Дата:

хук FormIt для отправки форм в виде вложения PDF Посмотреть это дополнение на MODX.com.

Дата:

Управляйте настройками разных контекстов в одном месте Посмотреть это дополнение на MODX.com.

Дата:

Помощник по быстрой разработке сайта Посмотреть это дополнение на MODX.com.

Дата:

Кнопка загрузки для загрузки нескольких файлов с индикатором выполнения Посмотреть это дополнение на MODX.com.

Как получить статьи на пользовательской странице в MODX CMS

Задавать вопрос

спросил

Изменено 3 года, 1 месяц назад

Просмотрено 158 раз

Я новичок в CMS MODX, поэтому я ничего не знаю об этой CMS. Я пытался получить статьи в пользовательском шаблоне, см. скриншот 01:-

Скриншот 01

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

Оставить комментарий

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *