[Twiggy] - шаблонизатор TWIG в MODX Revolution
Пакет Twiggy представляет из себя парсер расширяющий modParser.
Twiggy перехватывает обработку twig тегов на странице.
Подробнее ознакомится с TWIG можно на официальном сайте и на сайте сообщества TWIG.
При установке пакета в контексте web создаются две настройки:
настройки пакета
Настройки twig вынесены в отдельную секцию. Доступны следующие настройки:
Режиме песочницы. Добавляет изолированный режим в среду Twig, что делает его безопасным для оценки ненадежного кода.
По умолчанию twig запускается со следующими расширениями
Вы можете самостоятельно добавить нужные расширения, найдя их на гитхаб или написав самостоятельно. Расширение может определять тэги, фильтры, тесты, операторы, глобальные переменные и функции.
Тема расширений достаточно обширна и пока я ее опущу. На данный момент что необходимо знать
— файл расширения должен лежать по пути указанному в path_extensions
— имя класса расширения соответствует TwiggyExtensionимя
— имя расширения должно быть указано в настройке extensions
шаблоны twig
Twiggy автоматически подгружает шаблоны с таблицы modTemplate, а так же файловые шаблоны из папки указанной в настройке path_templates
Имена шаблонов соответствуют их названиям, например
создадим шаблон base в MODX
доступные переменные
Доступны следующие глобальные переменные
расширения Tools
Для большего удобства написано небольшое расширения Tools github.com/vgrish/twiggy/blob/master/core/components/twiggy/elements/extensions/tools.class.php
там описаны основные функции и фильтры для комфортной работы с MODX api.
Ниже несколько примеров:
вывести заголовок ресурса
получить объект modUserProfile и преобразовать в json
вывести почту авторизованного пользователя
подсчитать кол-во modUserProfile
вывести чанк
обратится к процессору и вывести результат работы
лексиконы
расширение Cache
Написано небольшое расширение для кэширования секций Cache github.com/vgrish/twiggy/blob/master/core/components/twiggy/elements/extensions/cache.class.php
пример, указываем ключ кэша и время
расширение DebugBar
phpdebugbar.com/
пример вывода
уницикация
Для большей унификации описаны методы getChunk и parseChunk аналогичные методам из пакета pdoTools Василия Наумкина.
Код на github, создавайте isuue
Готовый пакет пока можно установить из моего репозитория rstore.pro/extras/
PS. Не рекомендую к установке на рабочие проекты
Чтобы отключить работу Twiggy парсера достаточно удалить настройки из контекста
Twiggy перехватывает обработку twig тегов на странице.
Подробнее ознакомится с TWIG можно на официальном сайте и на сайте сообщества TWIG.
При установке пакета в контексте web создаются две настройки:
- parser_class — класс парсера
- parser_class_path — путь к классу парсера
настройки пакета
- twiggy_extensions — список активных расширений через запятую, для подключения в Twiggy.
- twiggy_path_extensions — путь для загрузки расширений Twiggy.
- twiggy_path_templates — путь для загрузки шаблонов Twiggy.
- sandbox — разрешить режим песочницы, при подключении шаблона в Twiggy.
Настройки twig вынесены в отдельную секцию. Доступны следующие настройки:
- debug: При установке в true, генерируемые шаблоны имеют__toString() метод, который можно использовать для отображения сгенерированных узлов (по умолчанию false).
- charset: Кодировка, используемая в шаблонах (по умолчанию в UTF-8)
- base_template_class: Шаблон базового класса, который используют для сгенерированных шаблонов (по умолчанию Twig_Template).
- cache: Абсолютный путь, где хранятся скомпилированные шаблоны или false чтобы отключить кэширование (который по умолчанию).
- auto_reload: При разработке с Twig, полезно повторно компилировать шаблон при изменении кода-исходника. Если вы не установили значение опции auto_reload, то она будет определена автоматически на основании переменной debug.
- strict_variables: Если установлено false, Twig будет по умолчанию игнорировать недействительные переменные (переменные и или атрибуты/методы, которые не существуют) и заменять их значением null. Когда устанавлено true, Twig генерирует исключение (по умолчанию false).
- autoescape: Если установить true, авто-сохранение будет разрешено по умолчанию для всех шаблонов (по умолчанию true). Начиная с Twig 1.8, вы можете выбрать какую методику сохранения использовать (html, js, false для блокировки). Начиная с Twig 1.9, вы можете выбрать какую методику сохранения использовать (css, url, html_attr, или обратный вызов PHP, который берет шаблон “имя файла” и должен вернуть методику сохранения для использования — обратный вызов не может быть названием функции, чтобы избежать конфликта (коллизии) со встроенными методами сохранения. optimizations: Флаг, который указывает, какие оптимизации применять (по умолчанию -1 — все оптимизации разрешены; установите его на 0 для отключения).
Режиме песочницы. Добавляет изолированный режим в среду Twig, что делает его безопасным для оценки ненадежного кода.
- sandbox_tags — список разрешенных тэгов через запятую, для подключения в режиме песочницы.
- sandbox_filters — список разрешенных фильтров через запятую, для подключения в режиме песочницы.
- sandbox_methods — строка, закодированная в JSON, с разрешенными методами для подключения в режиме песочницы.
- sandbox_properties — строка, закодированная в JSON, с разрешенными свойствами для подключения в режиме песочницы.
- sandbox_functions — Список разрешенных функций через запятую, для подключения в режиме песочницы.
По умолчанию twig запускается со следующими расширениями
- Twig_Extension_Core — определяет все основные возможности Twig.
- Twig_Extension_Escaper — добавляет автоматический вывод данных-сохранение, а также возможность сохранить/пропустить блоки кода
- Twig_Extension_Optimizer — оптимизирует древо узлов перед компиляцией
Вы можете самостоятельно добавить нужные расширения, найдя их на гитхаб или написав самостоятельно. Расширение может определять тэги, фильтры, тесты, операторы, глобальные переменные и функции.
Тема расширений достаточно обширна и пока я ее опущу. На данный момент что необходимо знать
— файл расширения должен лежать по пути указанному в path_extensions
— имя класса расширения соответствует TwiggyExtensionимя
— имя расширения должно быть указано в настройке extensions
шаблоны twig
Twiggy автоматически подгружает шаблоны с таблицы modTemplate, а так же файловые шаблоны из папки указанной в настройке path_templates
Имена шаблонов соответствуют их названиям, например
создадим шаблон base в MODX
<!DOCTYPE html>
<html>
<head>
{% block head %}
<link rel="stylesheet" href="style.css" />
<title>{% block title %}{% endblock %} - Мой сайт</title>
{% endblock %}
</head>
<body>
<div id="content">{% block content %}{% endblock %}</div>
<div id="footer">
{% block footer %}
© Copyright 2013 <a href="http://example.com/">Вы</a>.
{% endblock %}
</div>
</body>
</html>
создадим расширяющий шаблон{% extends "base" %}
{% block title %}Главная{% endblock %}
{% block head %}
{{ parent() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<h1>Главная</h1>
<p class="important">
Приветсвую на своем потрясном сайте!
</p>
{% endblock %}
доступные переменные
Доступны следующие глобальные переменные
- get — $_GET
- post — $_POST
- session — $_SESSION
- cookie — $_COOKIE
- request — $_REQUEST
- files — $_FILES
- server — $_SERVER
- modx — $modx
- pls — массив доступных плейсходеров
расширения Tools
Для большего удобства написано небольшое расширения Tools github.com/vgrish/twiggy/blob/master/core/components/twiggy/elements/extensions/tools.class.php
там описаны основные функции и фильтры для комфортной работы с MODX api.
Ниже несколько примеров:
вывести заголовок ресурса
{{ modx.resource.pagetitle }}
//или
{{ resource('pagetitle') }}
получить объект modUserProfile и преобразовать в json
{{ getObject('modUserProfile', {'email':'admin@vgrish.ru'})|toJson }}
вывести почту авторизованного пользователя
{{ profile('email') }}
подсчитать кол-во modUserProfile
{{ getCount('modUserProfile') }}
вывести чанк
{{ chunk('@INLINE {{ name }} - {{ fio }}', data) }}
обратится к процессору и вывести результат работы
{% set response = processor('mgr/valute/getlist',{'ns':'currencyrate', 'sortdir':'asc'}) %}
{# { dump(response) }#}
{% for result in response.response.results %}
<li>
{{ result.name }}
</li>
{% endfor %}
лексиконы
{{ loadLexicon('ru:core:default') }}
{{ _('access_denied') }}
и тд. Если вам интересны задавайте вопросы.расширение Cache
Написано небольшое расширение для кэширования секций Cache github.com/vgrish/twiggy/blob/master/core/components/twiggy/elements/extensions/cache.class.php
пример, указываем ключ кэша и время
{% cache 'neighbors' 3000 %}
{{ snippet('pdoNeighbors') }}
{% endcache %}
расширение DebugBar
phpdebugbar.com/
пример вывода
{% if hasSessionContext('mgr') %}
{{ dbgHead() }}
{{ dbgMessage(array) }}
{{ dbgRender() }}
{% endif %}
уницикация
Для большей унификации описаны методы getChunk и parseChunk аналогичные методам из пакета pdoTools Василия Наумкина.
$Twiggy->getChunk('twig', $row);
Код на github, создавайте isuue
Готовый пакет пока можно установить из моего репозитория rstore.pro/extras/
PS. Не рекомендую к установке на рабочие проекты
Чтобы отключить работу Twiggy парсера достаточно удалить настройки из контекста
Поблагодарить автора
Отправить деньги
Комментарии: 43
Twig уже пол года использую на фронте, шаблон собираю gulp'ом. Если кому интересно, могу в ближайший месяц статью написать как использовать это все в modx.
Вообще сборка шаблона на сервере, по-моему большая ошибка. Зачем сервер загружать тем, что должно делаться во фронте 1 раз при сборке проекта? А так каждый сброс кэша — сборка шаблона. Практически отказался по этой причине от Fenom (пусть он и очень быстрый), использую только для удобства написания условий.
Это мое мнение при всем уважении к Володе и Василию :)
Вообще сборка шаблона на сервере, по-моему большая ошибка. Зачем сервер загружать тем, что должно делаться во фронте 1 раз при сборке проекта? А так каждый сброс кэша — сборка шаблона. Практически отказался по этой причине от Fenom (пусть он и очень быстрый), использую только для удобства написания условий.
Это мое мнение при всем уважении к Володе и Василию :)
каждому свое…
По поводу вашей реализации с интересном бы прочел.
Спасибо!
По поводу вашей реализации с интересном бы прочел.
Спасибо!
Тоже с радостью прочту статью. Ждём. :)
Подскажите, а с кэшированием тут дела обстоят лучше чем в решении fenom+modx?
Нельзя сказать лучше или хуже, я бы сказал одинаково.
И тут и там компилируется шаблон/код и хранить его явно в html нет никакого смысла, иначе бы все это отрабатывало один раз, при первичной загрузке.
Вы можете использовать кэширование секций, указав ключ кэша и время
И тут и там компилируется шаблон/код и хранить его явно в html нет никакого смысла, иначе бы все это отрабатывало один раз, при первичной загрузке.
Вы можете использовать кэширование секций, указав ключ кэша и время
{% cache 'neighbors' 3000 %}
{{ snippet('pdoNeighbors') }}
{% endcache %}
данная секция сохранится в html
Второй вопрос как раз и задал человек комментарием выше. И совершенно не без основательно. Вот мы смотрим кеш документа с твоим шаблоном:
Еще раз: в MODX с точки зрения шаблонизации только два минуса:
1. нет компиляции в нормальный php (чтобы логика была)
2. нет расширения шаблонов.
В остальном она довольно продвинутая (особенно крут вложенный парсинг).
Ты добавляешь расширяемости и логики, но ломаешь родное кеширование.
'_content' => '{% extends "BaseTemplate" %}
{% block title %}Главная{% endblock %}
{% block head %}
{{ parent() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<h1>Главная</h1>
<p class="important">
Приветсвую на своем потрясном сайте!
</p>
{% endblock %}',
Он же не скомпилированный. Кеширование отдыхает тогда в принципе. Это то, что было долгое время в самом MODX (я раньше не однократно писал про его проблемы, из-за того, что он даже кешируемые теги в кеш пишет как есть, и потом все равно каждый раз реплейс делает), и что в MODX наконец-то поправилось (теперь он в кеш пишет сразу конечный HTML из кешируемых элементов), и теперь ты это достижение ломаешь. Шаблоны будут чуть более гибкие, но зато более тормознутые. И тут и там компилируется шаблон/код и хранить его явно в html нет никакого смысла, иначе бы все это отрабатывало один раз, при первичной загрузке.Хранить в конечном html очень даже есть смысл, в этом и есть смысл кеширования ресурсов. А вот то, что иначе не будет отрабатываться каждый раз — так вот для этого и были придуманы не кешируемые MODX-теги. Напиши один сниппет вида [[!twig?tpl=`some_tpl`]] и все. И где надо некешируемые блоки вставлять — там его и прописывать в шаблонах.
Еще раз: в MODX с точки зрения шаблонизации только два минуса:
1. нет компиляции в нормальный php (чтобы логика была)
2. нет расширения шаблонов.
В остальном она довольно продвинутая (особенно крут вложенный парсинг).
Ты добавляешь расширяемости и логики, но ломаешь родное кеширование.
спасибо! Есть над чем подумать.
Я чет так подумал, так если положим в кэш конечный html — то какой от этого смысл?
Тогда изначальна вся затея ни к чему. Вся гибкость шаблонизатора пропадает.
Или я не прав?
Тогда изначальна вся затея ни к чему. Вся гибкость шаблонизатора пропадает.
Или я не прав?
Таки да. При неправильном подходе. Я-то не раз уже говорил про необходимость наличия маленького сниппета для некешируемого вызова шаблончиков. У нас есть такой сниппет. Вызов простой [[!smarty?tpl=`inc/some.tpl`]]
При таком подходе и общий шаблон кешируется, и есть гибкость на динамических блоках.
При таком подходе и общий шаблон кешируется, и есть гибкость на динамических блоках.
понял, спасибо!
Не за что!
Николай привет.
Опять к вопросу о сниппете.
Создал ресурс, вызвал сниппет
Вопрос все тот же — чем это помогает кэшированию? В чем фишка я не пойму.
Спасибо!
Опять к вопросу о сниппете.
Создал ресурс, вызвал сниппет
[[!smarty?tpl=`tpl/test.tpl`]]
смотрю в кэш ресурса — логично там именно этот вызов сниппета. Вопрос все тот же — чем это помогает кэшированию? В чем фишка я не пойму.
Спасибо!
Привет.
Чтобы это помогало кешированию, надо вызов делать кешируемым. [[smarty?tpl=`tpl/test.tpl`]]
А некешируемые вызовы — это уже внутри самого шаблона, к примеру
Чтобы это помогало кешированию, надо вызов делать кешируемым. [[smarty?tpl=`tpl/test.tpl`]]
А некешируемые вызовы — это уже внутри самого шаблона, к примеру
<html>
<head></head>
<body>
<header>
[[smarty?tpl=`inc/menu.tpl`]]
[[!smarty?tpl=`inc/login.tpl`]]
</header>
<div>
[[*content]]
</div>
</body>
</html>
Здесь разъяснять же не надо?
то есть такую конструкцию имеет смысл применять только на блоках где не важна динамика. Спасибо за разьяснения, теперь окончательно ясно.
Так для этого кеширование в шаблонах (и кеширование элементов) и придумано. Конечно можешь весь код сразу вставить в шаблон как есть и там уже указать некешируемые элементы, но это сразу же дико будет походить на стандартные чанки. А общий элемент [[smarty?tpl=`tpl/test.tpl`]] для того и пишется, чтобы в базовом шаблоне можно было прописать расширение.
Вот у тебя MODX-шаблон «Основной»:
[[smarty?tpl=`tpl/index.tpl`]]
В tpl/index.tpl прописано:
[[smarty?tpl=`tpl/mainpage.tpl`]]
В tpl/mainpage.tpl прописано:
Вот у тебя MODX-шаблон «Основной»:
[[smarty?tpl=`tpl/index.tpl`]]
В tpl/index.tpl прописано:
<html>
<head></head>
<body>
<header>
[[smarty?tpl=`inc/menu.tpl`]]
[[!smarty?tpl=`inc/login.tpl`]]
</header>
<div>
{block content}[[*content]]{/block}
</div>
</body>
</html>
А вот у тебя MODX-шаблон «Главная страница»:[[smarty?tpl=`tpl/mainpage.tpl`]]
В tpl/mainpage.tpl прописано:
{extends "tpl/index.tpl"}
{block content prepend}
{include "inc/slider.tpl"}
{/block}
На выходе все кроме [[!smarty?tpl=`inc/login.tpl`]] у тебя будет кешируемым, на главной помимо контента еще и слайдер появится, и не придется дублировать код в MODX-шаблонах.
Владимир, сам знаешь, я приветствую начинания в области шаблонизации, но сорри, некоторые вопросы буду не очень удобные задавать. Просто в свое время и я шишек набил с подобными компонентами, так что есть от чего отталкиваться.
Вопрос первый: Зачем тебе вот это? Оно итак в modResponse::outputContent() отрабатывается. (на самом деле я предполагаю зачем оно тебе, но тут несколько вариантов, так что хотелось бы именно твой вариант услышать).
Вопрос первый: Зачем тебе вот это? Оно итак в modResponse::outputContent() отрабатывается. (на самом деле я предполагаю зачем оно тебе, но тут несколько вариантов, так что хотелось бы именно твой вариант услышать).
Затем же, зачем оно же и в pdoTools, у которого обработка тегов Fenom запускается после process() самого документа.
И если включена настройка pdotools_fenom_parser и сниппеты, регистрирующие скрипты и стили, вызываются прямо в контенте документа, то файлы от них в эти массивы они уже не попадают и приходится добавлять их вручную. Вот тут багрепорт.
И если включена настройка pdotools_fenom_parser и сниппеты, регистрирующие скрипты и стили, вызываются прямо в контенте документа, то файлы от них в эти массивы они уже не попадают и приходится добавлять их вручную. Вот тут багрепорт.
Такого ответа я и ожидал. Но вы изначально все не правильно делали. Эти скрипты известны документу еще на уровне получения его из кеша. Все, что вам нужно было — это плагин навесить на правильное событие и присвоить документу эти данные. И все бы у вас было ОК.
Почему я про этот кусок кода спросил? Во-первых, этот метод парсера в процессе отработки документам может быть вызван не один раз. Во-вторых, в разные стадии вызова его в массивах этих могут содержаться разные наборы скриптов (что не страшно, конечно же, ибо все равно они будут в шаблон подставлены только в одном месте, но как минимум бессмысленно).
Почему я про этот кусок кода спросил? Во-первых, этот метод парсера в процессе отработки документам может быть вызван не один раз. Во-вторых, в разные стадии вызова его в массивах этих могут содержаться разные наборы скриптов (что не страшно, конечно же, ибо все равно они будут в шаблон подставлены только в одном месте, но как минимум бессмысленно).
Ты чего меня на вы-то? Вроде уже лично познакомились.
А вообще, тут всё просто. Без этой правки скрипты и стили из кэшируемых сниппетов, вызванных через Fenom, не добавлялись на страницу. А с ней — добавляются.
Сделать так мне показалось просто и логично, но если ты считаешь, что MODX нужно делать дополнительный вызов плагина для этой операции — шли PR на GitHub, добавим.
А вообще, тут всё просто. Без этой правки скрипты и стили из кэшируемых сниппетов, вызванных через Fenom, не добавлялись на страницу. А с ней — добавляются.
Сделать так мне показалось просто и логично, но если ты считаешь, что MODX нужно делать дополнительный вызов плагина для этой операции — шли PR на GitHub, добавим.
Да не, вы — это я во множественном числе. Сначала ты, потом Володя, до него еще кто-нибудь (я же не очень пристально за вашими компонентами следил и не знаю кто когда еще подобный трюк выполнял). Это вот сейчас я стал больше интересоваться унификацией, вот и поглядываю иногда :)
А вообще, тут всё просто. Без этой правки скрипты и стили из кэшируемых сниппетов, вызванных через Fenom, не добавлялись на страницу. А с ней — добавляются.Тут ответ однозначный: где-то неверная последовательность вызова/вывода. Ты четко знаешь когда бага возникает. Если не лень, создай тестовый сайт с этой багой (феном + минифи), закомментируй этот свой хак и пришли доступ, я посмотрю. Уверен, найду суть проблемы.
Насколько я вижу, половина логики Twiggy скопирована из pdoTools, поэтому и отвечаю на твои вопросы =)
Но по моему, дело в том, что теги Fenom на странице отрабатывают после процессинга документа через MODX, и данные кэшированных сниппетов не попадают в массивы скриптов и стилей. То есть, сниппет кэшируется, а то что он регистрировал в первый раз — нет.
Вот тестовый сайт:
чанк с кэшированным вызовом MinifyX
класс pdoParser с закоментированным добавлением скриптов и стилей после обработки тегов Fenom
Логин s3914
Пароль UAChpcjgpO9r
Тут ответ однозначный: где-то неверная последовательность вызова/вывода.Может быть.
Но по моему, дело в том, что теги Fenom на странице отрабатывают после процессинга документа через MODX, и данные кэшированных сниппетов не попадают в массивы скриптов и стилей. То есть, сниппет кэшируется, а то что он регистрировал в первый раз — нет.
Вот тестовый сайт:
чанк с кэшированным вызовом MinifyX
класс pdoParser с закоментированным добавлением скриптов и стилей после обработки тегов Fenom
Логин s3914
Пароль UAChpcjgpO9r
Насколько я вижу, половина логики Twiggy скопирована из pdoTools, поэтому и отвечаю на твои вопросы =)Я так и понял :) Предполагаю, что тебе даже не очень-то и нравится такая объемная копируемость :)
Я пока не буду ничего отвечать. Мысли есть, но нужны факты. Щас поковыряю сайт и по результатам отпишусь.
На мой взгляд, если приходится много чего-то копировать, то лучше наследовать и расширять.
Тем более, что технически ничего не мешает написать сторонний парсер, который будет наследовать pdoTools со всеми его возможностями. А pdoParser просто отключить при установке и возвращать обратно при удалении.
Но это моё сугубо личное мнение, никому не навязываю.
Тем более, что технически ничего не мешает написать сторонний парсер, который будет наследовать pdoTools со всеми его возможностями. А pdoParser просто отключить при установке и возвращать обратно при удалении.
Но это моё сугубо личное мнение, никому не навязываю.
Да не, все верно. Я вообще отметил набирающую оборот тенденцию: много кто стал просто переделывать чужие пакеты. То есть не создавать что-то новое, а именно переделывать. ИМХО или PR, или что-то принципиально новое. К примеру, как ты меня когда-то обвинил в том, что я modSociety запулил, хотя есть Articles. Да, эти решения примерно направлены на одно и то же, но они принципиально разные. Это не копии, это абсолютно разные решения. А сейчас как делают? Скопируют Articles, назовут по другому, и скажут, что вот тут есть принципиальные улучшения. Ну ты понял.
Сорри за долгий ответ, отвлекся.
Решение: пишем плагин на событие OnBeforeSaveWebPageCache, простейший вид:
При чем это будет выполняться только при первом заходе на страницу. Когда документ уже закеширован будет, это не будет выполняться.
UPD: Может даже имеет смысл это в ядро запулить (то есть код кешманагера поправить), так как очень похоже на багу самого MODX-а. Какая-то глупость в двух отдельных сущностях хранить эти переменные и создавать/получать в разных местах на разных этапах.
Но по моему, дело в том, что теги Fenom на странице отрабатывают после процессинга документаВсе верно. Из-за этого и была проблема. Дело в том, что $modx->regClientStartupScript() и подобные методы работают со свойствами самого $modx, а вот при сохранении кеша используются свойства самого ресурса. А так, как в отработанных уже после процессинга тегах выполняется типа $modx->regClientStartupScript() (который устанавливает свойства для $modx, но не устанавливает их для $modx->resource), то при генерации кеша документа этих скриптов в кеше просто нет. joxi.ru/4Ak3wb9tMX8nGA
Решение: пишем плагин на событие OnBeforeSaveWebPageCache, простейший вид:
$modx->resource->_jscripts = $modx->jscripts;
$modx->resource->_sjscripts = $modx->sjscripts;
$modx->resource->_loadedjscripts = $modx->loadedjscripts;
И тогда при генерации кеша документа будут сохранены все скрипты. joxi.ru/LmGVQx0uRJN1XrПри чем это будет выполняться только при первом заходе на страницу. Когда документ уже закеширован будет, это не будет выполняться.
UPD: Может даже имеет смысл это в ядро запулить (то есть код кешманагера поправить), так как очень похоже на багу самого MODX-а. Какая-то глупость в двух отдельных сущностях хранить эти переменные и создавать/получать в разных местах на разных этапах.
Отличный анализ, спасибо!
Думаю, ничего страшного не случится, если я пока оставлю всё как есть.
Думаю, ничего страшного не случится, если я пока оставлю всё как есть.
Не за что!
Конечно нет))
Конечно нет))
Николай, подскажите, в Вашнй реализации шаблонизатора для modx (modxSmarty) с кэшированием все обстоит лучше?
PS: разрабатываю новый сайт, и вопрос опять встал ребром — какой шаблонизатор использовать. Благо для modx уже есть выбор-)
PS: разрабатываю новый сайт, и вопрос опять встал ребром — какой шаблонизатор использовать. Благо для modx уже есть выбор-)
Лучше. Сейчас и в самом MODX с кешированием все лучше стало, хотя бы потому что теперь MODX результат кешируемых элементов в кеш сохраняет как готовый HTML (раньше он этого не делал), из-за чего сейчас у меня даже отпадает необходимость использования компонента phpTemplates. Теперь я просто в обычный MODX-шаблон прописываю, например, [[smarty?tpl=`tpl/mainpage.tpl`]] и все ОК.
Замечательно! было бы классно сделать табличку сравнения быстродействия реализации 3 шаблонизаторов для модкс (fenom, twigg,smarty), в связи с чем вопрос: как правильно написать данный тест на modxSmarty?
Тестировал в консоли.
1. pdoResources
2. Smarty + getdata-процессор.
В консоли:
3. Smarty + чистый xPDO
В консоли:
Шаблон:
Разница очевидна.
P.S. наверняка феном + чистый xPDO тоже хороший результат покажет.
1. pdoResources
$output = $modx->runSnippet('pdoResources', array(
"parents" => 7,
"limit" => 4000,
"depth" => 0,
"showLog" => 0,
"tpl" => '@INLINE {{+id}}-{{+menuindex}}-{{+createdon}}-{{+publishedon}}',
));
2. Smarty + getdata-процессор.
В консоли:
$modx->invokeEvent('OnHandleRequest');
$modx->startTime = microtime(true);
$output = $modx->smarty->fetch('test/getdata.tpl');
Шаблон:{$params = [
"limit" => 4000
]}
{processor action="web/getdata" ns="modxsite" params=$params assign=result}
{foreach $result.object as $row}
<p>
{$row.id}-{$row.menuindex}-{$row.createdon}-{$row.publishedon}
</p>
{/foreach}
3. Smarty + чистый xPDO
В консоли:
$modx->invokeEvent('OnHandleRequest');
$modx->startTime = microtime(true);
$output = $modx->smarty->fetch('test/pure.tpl');
Шаблон:
{$q = $modx->newQuery('modResource')}
{$ok = $q->select(['modResource.*'])}
{$ok = $q->limit(4000)}
{$s = $q->prepare()}
{$ok = $s->execute()}
{while $row = $s->fetch(2)}
<p>
{$row.id}-{$row.menuindex}-{$row.createdon}-{$row.publishedon}
</p>
{/while}
Разница очевидна.
P.S. наверняка феном + чистый xPDO тоже хороший результат покажет.
наверняка феном + чистый xPDO тоже хороший результат покажет.Проверил не совсем в чистом виде, а вызовом через сниппет:
<?php
$pdo = $modx->getService('pdoTools');
return $pdo->getChunk($tpl);
При пустом шаблоне документа:
[[!Fenom?&tpl=`@INLINE {var $resources = $_modx->getResources([], ['limit' => 4000])} {foreach $resources as $resource} <p>{$resource.id} - {$resource.menuindex} - {$resource.createdon} - {$resource.publishedon}</p> {/foreach} <pre>{$_modx->getInfo()}</pre> `]]
Результат:
queries: 13
totalTime: 0.3718 s
queryTime: 0.0532 s
phpTime: 0.3186 s
source: database
На сколько я понимаю, @INLINE у тебя все равно отрабатывается как чанк? То есть типа такого
$chunk = $modx->newObject('modChunk');
$chunk->code = $inline_code;
$output = $chunk->process();
return $output;
Или я не прав? Если так, то все равно, хоть и не из базы данных, но все равно объект каждый раз создается. Так не может быстро работать. Вот если модифицировать в такое (упрощенно), то должно быстрее работать.$output = '';
$chunk = $modx->newObject('modChunk');
while($row = $s->fetch(2)){
$chunk->code = $inline_code;
$output .= $chunk->process();
}
return $output;
Все чанки кэшируются внутри pdoTools и стараются не выполняться через объекты. Там масса всяких оптимизаций.
Но и оверхеда всякого достаточно, хотя лично мне скорости вполне хватает, чтобы не морочиться дальше. Решение должно быть достаточно универсально и работать удобно из коробки, без танцев.
Сейчас заканчиваю один сайт, полностью построенный на Fenom и готовых дополнениях — все страницы открываются за 0.2 — 0.3 сек., может позже напишу заметку с подробностями.
Но и оверхеда всякого достаточно, хотя лично мне скорости вполне хватает, чтобы не морочиться дальше. Решение должно быть достаточно универсально и работать удобно из коробки, без танцев.
Сейчас заканчиваю один сайт, полностью построенный на Fenom и готовых дополнениях — все страницы открываются за 0.2 — 0.3 сек., может позже напишу заметку с подробностями.
Не, на счет адекватности задачам полностью согласен. В жизни выборка 4000 документов и набивка их в чанки крайне маловероятна. А на 10-20 документах разница практически не ощущаема и оверклокингом заниматься нет смысла.
в консоли сниппет pdoResources
gist.github.com/vgrish/8189582355782ec13394
totalTime: 1.3793 s
queryTime: 0.0526 s
phpTime: 1.3267 s
queries: 9
source: cache
в консоли xPDO
gist.github.com/vgrish/2530a0364bf49b05481f
queryTime: 0.0011 s
phpTime: 0.1898 s
queries: 3
source: cache
gist.github.com/vgrish/8189582355782ec13394
$modx->switchContext('web');
$modx->invokeEvent('OnHandleRequest');
if (!$twiggy = $modx->getService('twiggy', 'twiggy', $modx->getOption('twiggy_core_path', null, $modx->getOption('core_path') . 'components/twiggy/') . 'model/twiggy/')) {
return 'Could not load twiggy class!';
}
$tpl = '
{% set aaaa = snippet("!pdoResources", {
"parents":1,
"limit":4000,
"tpl": "@INLINE {{ pls[\"id\"] }}-{{ pls[\"menuindex\"] }}-{{ pls[\"createdon\"] }}-{{ pls[\"publishedon\"] }}"
}) %}
{{ getInfo() }}';
$output = $twiggy->process($tpl, array(), false);
print_r($output);
totalTime: 1.3793 s
queryTime: 0.0526 s
phpTime: 1.3267 s
queries: 9
source: cache
в консоли xPDO
gist.github.com/vgrish/2530a0364bf49b05481f
$modx->switchContext('web');
$modx->invokeEvent('OnHandleRequest');
if (!$twiggy = $modx->getService('twiggy', 'twiggy', $modx->getOption('twiggy_core_path', null, $modx->getOption('core_path') . 'components/twiggy/') . 'model/twiggy/')) {
return 'Could not load twiggy class!';
}
$tpl = "
{% set q = modx.newQuery('modResource') %}
{% set ok = q.select(['modResource.*']) %}
{% set ok = q.limit('4000') %}
{% set s = q.prepare() %}
{% set ok = s.execute() %}
{% for resource in s.fetchAll(2) %}
<p>{{ resource.id }} - {{ resource.menuindex }} - {{ resource.createdon }} - {{ resource.publishedon }}</p>
{% endfor %}
{{ getInfo() }}
";
$output = $twiggy->process($tpl, array(), false);
print_r($output);
totalTime: 0.1909 squeryTime: 0.0011 s
phpTime: 0.1898 s
queries: 3
source: cache
Володь, ты забросил эту тему? На феноме работаешь?
Давно забросил. Попробовав смарти, твиг, феном могу уверенно сказать что фен просто прекрасен.
Может, напишешь на досуге заметку со сравнением?
Думаю, не только мне будет интересно прочитать.
Думаю, не только мне будет интересно прочитать.
Возможно напишу.
Жаль. Феном конечно прекрасен, но на «коротких» дистанциях. А чуть дальше и он со своим односкобочным синтаксисом сдаётся перед специфическим механизмом парсинга MODX. Поэтому хочу попробовать Twig, чтобы забыть про подобные ошибки
П.П.С. А вообще, идея совмещать 2 механизма парсинга хреновая. Ни один нормально не работает. Это относится к любому стороннему шаблонизатору в MODX.
// Пример ошибки при выводе ресурса через функцию dump() из modHelpers.
Unexpected token '<' in expression in e4d771b3eb4eed60131330f50f7a360d line 2, near '{<' <- there
П.С. Подобные ошибки валятся и из некоторых других библиотек, с которыми я экспериментирую. Поэтому хотелось бы покончить с ними раз и навсегда. В других шаблонизаторах используется особый синтаксис типа {{ или {% или {!!. Что теоретически должно исключить данную проблему.П.П.С. А вообще, идея совмещать 2 механизма парсинга хреновая. Ни один нормально не работает. Это относится к любому стороннему шаблонизатору в MODX.
Поэтому хочу попробовать Twig, чтобы забыть про подобные ошибкиТак попробуй!) Все познается в сравнении.
односкобочным синтаксисом сдаётся перед специфическим механизмом парсинга MODXМне односкобочный синтаксис очень люб. Гибкость, быстрота и легкая расширяемость феном — что еще нужно?
Прямых конкурентов я не вижу…
забыть про подобные ошибкине сталкиваюсь с таким, потому и решать не приходилось.
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.