Николай Ланец
29 июля 2013 г., 12:25

Еще одна фишка с кешированием в Smarty

Буквально вчера обнаружил еще одну классную фишку в Smarty…
А было дело так. На сайте был довольно тяжелый подвал, в котором было сразу несколько нагруженных моментов (пара Wayfinder-ов, getResources с набивкой в шаблоны с использованием phpthumbOf-а и т.п.). При этом подвал был одинаковый для всех страниц сайта. Конечно подвал был кешируемый, но все мы знаем, что кеш в MODX-е создается отдельно для каждой страницы. То есть при первом заходе на каждую страницу в отдельности, все равно подвал выполнялся полностью.
Ну я как обычно решил это дело оптимизировать, заменив подвал на кешируемый сниппет, в котором уже подгружал шаблон подвала, и кешировал его с помощью $modx->cacheManager. В таком случае шаблон выполнялся только один раз после полного сброса кеша, а во всех остальных случаях даже при первом заходе на страницу, подвал уже не выполнялся с нуля, а возвращался его код из кеша.
Конечно это позволяет значительно снизить нагрузку, но все равно имеется сразу несколько минусов: 1. Это все-таки сниппет. А как мы знаем, даже если это кешируемый элемент, MODX-парсер все равно будет тратить на него усилия при разборе кеша страницы. 2. Это просто не удобно. Создай сниппет, пропиши в нем код, подгрузи Smarty-шаблон и т.п. (да, я знаю про getCache и прочие кеш-акселераторы, но смотрим пункт 1). 3. Хотелось бы вообще исключить всякие сниппеты и т.п.
И вот тут я сначала подумал написать краткий плагин для Smarty, а потом подумал «а может в Smarty есть встроенные механизмы для этих задач?». И как оказалось, есть! Оказывается, если вызывать подшаблон с указанием ключа кеша, то для этого подшаблона будет создан индивидуальный кеш, и в дальнейшем при всех вызовах этого подшаблона, результат будет браться из кеша, если он есть. Пример вызова:
{include file="my_template.tpl" cache="my_cache_key"}
Вот и все. Не надо никаких сниппетов и т.п. Просто вызывали с указанием ключа кеша, и шаблон будет выполнен только один раз для всего сайта!
Я сразу объясню, почему я так долго тупил и не нашел это решение раньше. Дело в том, что в Smarty есть включение и отключение кеширования (и в modxSmarty это имеется в виде системной настройки). Но при включенном полном кешировании надо очень внимательно писать шаблоны, с указанием nocache во всех элементах, которые не должны кешироваться. Лично мне это не очень удобно, потому я отключаю кеширование Smarty, рассчитывая на кеширование самим MODX-ом (хотя с включенным Smarty-кешированием нагрузка реально резко падает). Но за это удобство (простые шаблоны) приходится платить цену — нагрузка при первом заходе на страницу. Вот я и думал, мол, отключил Смарти-кеширование и все, на Смарти рассчитывать уже не приходится. А вот как оказалось, что этот финт с указанием кеш-ключа работает даже тогда, когда глобальное кеширование Smarty отключено. И это офигенно! Распилили основной Smarty-шаблон на кешируемые блоки, указали для них кеш-ключи и все, не паримся — даже при первом заходе на новые страницы код будет браться из кеша. А в некешируемой части оставим только то, что действительно должно быть не кешироемо. Нагрузка упадет значительно.
И вот здесь мне приходит две мысли в голову:
1. Эти кеш-ключи можно динамически указывать. К примеру:
{include file="my_template.tpl" cache="cache_key_{$modx->resource->parent}"}
То есть здесь мы будем иметь различный кеш для различных родительских разделов.
Или вот так:
{include file="my_template.tpl" cache="cache_key_page_{$smarty.get.page}"}
А это кеш для постраничности (само собой это простой пример. В более сложном варианте можно использовать параметры поиска и т.п.).
2. Единое меню с использованием javascript. Эта тема вообще уже не раз всплывала. Особенно очень близкий по смыслу был вот этот топик. Просто даже если брать во внимание вот это решение (смотрите 2. Замена Wayfinder), все равно не круто получается, что для каждой страницы надо пробегаться по всему массиву и собирать конечное меню. А ведь можно просто выдать голое меню и средствами javascript уже пробежаться и собрать его в конечный вид. Для этого просто в шаблоне передает ID текущего документа, чтобы можно было в менюшке определить текущий документ и раздел.
В общем, вот такие мысли…
Натолкнул я тебя на мысль посмотреть на смарти и ты нашел там совсем другую плюшку -) Спасибо, не знал.
Нет, это не твоя мысль совсем, не присваивай :-) Если ты про {php}, то я ее даже и не смотрел. А историю того, как я к этому пришел, я написал в топике.
Да я тролю в силу того, что две мысли о смарти в один день появились. И, кстати, {php} не пашет, погляди на досуге, плиз. Возможно не пашет в силу того, что сам шаблон в modx тоже с PHP. И получается, по первому мнению, эдакая рекурсия, что апач нагружается на 100% и вылетает по «бесконечному циклу».
Ребята, включайте вывод ошибок на дев-серверах. Как вы так работаете без отладки? Вслепую? Пишет же четко:
Fatal error: Uncaught exception 'SmartyException' with message '{php} is deprecated, set allow_php_tag = true to enable
В контроллере или в плагине пропишите $modx->smarty->allow_php_tag = true; и будет вам счастье.
В слепую, на высоком уровне доверия к разработчикам. А затем начинается гадание: кто виноват, мля??? =) Спасибо. Пойду включать неэстетичный вывод ошибок.
Неэстетичный — это к дизайнерам. А для программиста отладка — его всё.
А где ты видел отдельно дизайнера отладочных интерфейсов? Вызов принят, надо эстетики навесить на вывод ошибок.
Ну, я вот вообще далекий от эстетики человек. А к примеру artdevue — он и программер хороший, и с дизайном дружит.
У меня такой вопрос, беря во внимание эту статью, первый пункт, мы можем добавлять идентификатор cache только в {include file}? Тогда все таки придется шаблон распилить на файлы? или можно воспользоваться блоком? что то типо этого:
{block name=header cache="header"}
То есть вот так:
{* Header *} {block name=header cache="header"} <a id="logo" title="{$site_name}" href="/"></a> <nav id="menu"> {assign var=params value=[ "startId" => 0 ,"level" => 1 ,"cacheable" => true ,"id" => "mainMenu" ]} {processor action="web/menu/getcatalogmenu" ns="hamster" params=$params assign=result} {assign var=items value=$result.object} {include file="inc/menu/catalog/outer. </nav> <div id="phone_order"> Заказ по телефону:<br />+7 (495) 221-90-21<br />+7 (495) 221-90-23<br />+7 (925) 092-28-33 </div> <div id="user_panel"> <a id="cartLink" href="{link id=4}" title="Корзина">Корзина</a> <span class="uLogin">[[!uLogin? &providers="vkontakte,facebook,odnoklassniki,twitter,mailru,google" &hidden="" &userGroups="Authorized" ]]</span> </div> {/block} {* Eof Header *}
или можно воспользоваться блоком? что то типо этого:
Нет. Судя по документации в блоке можно указать nocache. Это надо только при включенном глобальном кешировании Smarty. Но нельзя как подшаблону указать cache_id. А что тебе не нравится закинуть это в отдельный файл? Если это кешируемый подшаблон, то все равно он не будет каждый раз подгружаться (файл подшаблона). Будет вызываться метод Smarty, который будет проверять наличие кеша, и возвращать его, если он есть.

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