MisterN 11 января 2015 1 27
Возможно ли в смарти шабонах прервать отрабтку оног, как в сниппете die($res)? Объясню, что я хочу. Тем более, что пишу на половину, чтобы рассказать о удобном методе работы с ajax, пусть и не идеальном. Хотя все решаетцо наверняка очень просто и меня щас будут стыдить, что мало читал доки по смарти и т.д. )))
Есть старый добрый метод аджаксоделанья, когда на верх шаблона вставляешь сниппет

// если в заголовке XMLHttpRequest, как при ajax-запросах методом jquery, то работаем, нет - сниппет вырубаетцо.
if ($_SERVER['HTTP_X_REQUESTED_WITH'] != 'XMLHttpRequest') {return;}
// что-нибудь возвращаешь
$res = 'Hello World!';
// прерываешь работу шаблона
die($res);

Там в сниппете мы должны были отдать какой-то контент. А как мы получаем и отдаем контент в смарти-шаблонах? Ну получаем через $smarty.request/$smarty.post/$smarty.get соответствующим образом переданные параметры (или не принимаем), набиваем их в массив через assign, передаем в процессор и отображаем результат. И все это можно вынести в отдельный темплейт и отображать в шаблоне страницы как-то так {include file=«inc/shop/product.tpl»}
Ну и как можно модернизировать сниппет выше в смарти-виде?
{if $smarty.server.HTTP_X_REQUESTED_WITH == 'XMLHttpRequest'}
    {include file="inc/shop/product.tpl"}
{else}
    содержание шаблона.
{/if}

Теперь отправляем нужные параметры на страницу $.ajax — и понеслось. И заменяем полученный результат на тот, что в нашем (это метод $.ajax)

success: function (data) {
$('.ajax-block').replaceWith(data);
}

Собственно прелесть в том, что за отображение на сайте и возвращения аджаксом отвечает один шаблон и любые изменения в первом автоматически же отражаются и во-втором. Конечно, кто-то возразит, что дергать конечный html это не тру и трафика много тратится. Но это просто ооочень удобный метод, который с шаблонами смарти становится намного удобнее. Конечно, в сниппете это тоже можно было имитировать, но выводом аджакса и отображением на сайте нужно было заниматься отдельно.
Собственно в чем вопрос. В сниппете мы могли написать die($res); и отработка шаблона прекратилась, а нам бы вернулось то, что есть. В смарте же такое не канает? Шабоны в смарти наследуются, но такой блок, чтобы вверху было

{if $smarty.server.HTTP_X_REQUESTED_WITH == 'XMLHttpRequest'}
    {include file="inc/shop/product.tpl"}
// от здесь бы прерывать отрисовку шаблона
{else}
    содержание шаблона.
{/if}

неудобно. Может быть можно как-то похожем образом прервать выполнение шабона, чтобы он остановился? А то приходится в главном layout.tpl писать if-else конструкцию. А это не очень хорошо и не очень удобно.

UPD
Если для кому неудобно обертывать весь родительский лейаут в if, то можно сделать плагин на OnWebPageInit и условиями

if ($modx->event->name == 'OnWebPageInit' AND $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
// Получаем ресурс
    if (!is_object($modx->resource)) {
        $modx->resource = $modx->request->getResource($modx->resourceMethod, $modx->resourceIdentifier);
    }
..........

Ну, и конечно + определяем id и прочие ваши проверки. Но это не так удобно т.к. невозможно переопрделить отдаваемое содержимое в зависимости от шаблона. Зато понимаш, без обертки if :)
27 комментариев
Tramp13571
Tramp1357 11 января 2015г в 17:19 #
можно в контроллере прописать
$modx->smarty->allow_php_tag = true;

и в шаблоне тогда можно будет вставить
{php}
    die;
{/php}
Fi1osof1
Fi1osof 11 января 2015г в 17:27 #
Саш, а ты проверял на практике? Ведь здесь не все так просто. Частичный вывод контента и т.п. По-моему не проканает нормальной работы.
Tramp13571
Tramp1357 12 января 2015г в 01:19 #
да, правда только в верхнем layout. поставил перед футером — отсекает. правда, тоже нет — сейчас посмотрел :(
Fi1osof1
Fi1osof 12 января 2015г в 09:10 #
Надо просто учитывать, что в отличие от return где-нибудь в блоке присвоения значений в php-коде, в смарти это буквально в блоке вывода echo/print, из-за чего мы обламываем таким образом процесс вывода, а не процесс присвоения.
M
MisterN 11 января 2015г в 17:21 #
Спасибо. Попробую.
Fi1osof1
Fi1osof 11 января 2015г в 17:25 #
На сколько я знаю, нет в смарти ни exit, ни die, ни даже return. Поэтому хочется или нет, но придется юзать if/else.
Fi1osof1
Fi1osof 11 января 2015г в 17:31 #
Все-таки я пока остановился на таком механизме: modxclub.ru/topics/ajax-katalog-na-praktike-1258.html
Конечно и он не идеальный, но в целом очень даже работоспособный. Ведь не весь сайт нужен для подгрузки, а только какие-то определенные разделы. И вообще, в современных JS-либах подгружают весь контент страницы, просто из всего полученного контента выдергивают нужные Ajax-блоки и вставляют куда надо (реализуется просто на уровне таг-селекторов).
K
Kutuz27 11 января 2015г в 20:44 #
Интересная идея я сейчас с этим работаю. У меня задача при штатном переходе на сайт загружать страницу нормально шаблоном. А далее все переходы по ссылкам в внутри сайта перехватываются JS Ext и тот должен запросить по ссылке Json данные страницы и перестроить страницу.

Плагины не подходят?
M
MisterN 11 января 2015г в 23:08 #
Чет не получилось у меня вырвать конструкцию if/else с проверкой на HTTP_X_REQUESTED_WITH из основного, всеми наследуемого layout.tpl.
M
MisterN 11 января 2015г в 23:09 #
Просто хочется, чтобы в нем этой конструкции и проверки вообще небыло.
o
oobrun 12 января 2015г в 00:05 #
Пробуй наследовать другой (пустой) layout, на основании проверки на HTTP_X_REQUESTED_WITH…
Fi1osof1
Fi1osof 12 января 2015г в 00:10 #
Наследование прописывается в шапке файла. {extends ...}. Нельзя по условию наследовать. Но можно по условию инклюдить файлы-шаблоны.
Fi1osof1
Fi1osof 12 января 2015г в 00:17 #
В общем, я пробовал по всякому. Ничего нормального тут не получается.
Но поделюсь одним нестабильным элементом:

Весь главный шаблон оборачиваем в блок, к примеру resource.

Далее создаем новый промежуточный layout-wraper.tpl с таким содержимым
{extends "layout.tpl"}
{block name="resource"}
    {if $is_ajax}
        {block name=content}
            {$smarty.block.parent}
        {/block}
    {else}
        {$smarty.block.parent}
    {/if}
{/block}


Здесь важно, чтобы блока content не было в главном layout-шаблоне. Вот тогда при вызове какого-либо более глубокого расширяемого шаблона по условию выводился только блок content.
Но у меня это было очень не стабильно. Это скорее бага, чем фича. Если захочешь с этим поэкспериментировать, то до конечного шаблона создай еще один расширяющий шаблон, в котором будет только расширение прописано {extends ...} и все.
Мне сейчас совсем некогда ковырять глубоко Смарти, чтобы объяснить такое странное его поведение. Коммент оставляю, чтобы возможно на досуге вернуться к изучению этого интересного явления.
o
oobrun 12 января 2015г в 01:06 #
В Smarty в {extends ....} можно использовать переменную, примерно так:
{extends $modx->layout}

а $modx->layout можно где-нибудь определить

скажем в modxsmarty.class.php в конструкторе:



...
...

function __construct(modX &$modx, $params= array ()) {
        parent :: __construct();
        $this->modx= & $modx;
        
        $this->modx->layout= $_SERVER['HTTP_X_REQUESTED_WITH'] != 'XMLHttpRequest' ? "layout.tpl" : "<strong>empty_layout.tpl</strong>";

...
...

Fi1osof1
Fi1osof 12 января 2015г в 09:37 #
Да, указать переменную шаблона действительно можно, просто из прошлого коммента подумалось типа {if}{extends ...}{else}..{/if}. Такое там не канает.
А с переменной получается следующее:

1. В __construct лезть не оязательно, у нас же за все отвечает единый контроллер base.php

Прописываем в нем условие:
<?php
// .................................. 
if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){
    $modx->setOption('layout', 'ajax-layout.tpl');
    $compile_id = 'ajax';
}
else{
    $modx->setOption('layout', 'layout.tpl');
    $compile_id = 'layout';
}

return $modx->smarty->fetch("tpl/{$tpl}", '', $compile_id);


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

2. Создаем ajax-layout.tpl
В нем пишем:
{block name=content}
    {$modx->resource->content}
{/block}


3. Создаем промежуточный switch-layout.tpl, с содержимым:
{extends $modx->getOption('layout', null, 'layout.tpl')}


Здесь один минус есть: в рабочем режиме у шаблонов переменная phptemplates.non-cached == false, и Smarty-шаблоны при повторном заходе не отрабатываются. Так что придется некеширование выставлять в true, что конечно же скажется на производительности. Можно конечно в настройках modxSmarty включить кеширование самих смарти-шаблонов, но это усложняет разработку, ибо надо будет более четко продумывать где что кешировань/не кешировать, и прописывать где надо nocache. Но если это правильно использовать, то нагрузка не должна увеличиться так, чтобы заметно было.

P.S. За полезный коммент поднимаю права до члена Клуба :)
o
oobrun 12 января 2015г в 01:06 #
сам не проверял…
M
MisterN 12 января 2015г в 09:41 #
Лезть в modxsmarty.class.php — это перебор. Короче if/else в главном лейауте остается пока самым простым и железобетонным способом.
Fi1osof1
Fi1osof 12 января 2015г в 09:55 #
Я выше написал как без этого храдкода.
M
MisterN 12 января 2015г в 10:13 #
Но вы же говорите, что и там это «скорее баг»?
Fi1osof1
Fi1osof 12 января 2015г в 10:16 #
Нет. Про баг — это здесь. А переменная в {extended ...} — это стабильный вариант. Просто как я и сказал, надо с кешированием быть повнимательней.
M
MisterN 12 января 2015г в 10:16 #
Извиняюсь, не на тот комент подумал. но там тоже не все гладко. Хотя как инфа к размышлению интересно.
M
MisterN 12 января 2015г в 16:56 #
Все ништяк с аджаксом, но скрипты shopmodx теряются.
После первого взгляда на скрипты понимаешь — их куча
Кажется, что разбираться с ними придется долго и т.д.
Но вроде бы работает такая махинация:
Напомню, что в нашем лейауте вот такая конструкция

{if $smarty.server.HTTP_X_REQUESTED_WITH == 'XMLHttpRequest'}
    {include file="inc/shop/product.tpl"}
// от здесь бы прерывать отрисовку шаблона
{else}
    содержание шаблона.
{/if}

{include file=«inc/shop/product.tpl»} так же висит в категории товаров и собственно его мы и отображаем.
Добавляем в product.tpl скрипты из шапки. И не забудем указать в $.ajax указать dataType: «multiple», чтобы при аджакс-загрузках не отрубались js. Теперь все ништяк, после аджакс-обновления страницы товары в корзину добавляются, но дважды )) Нужно удалить скрипты из головы страницы. И конечно их нужно обязательно добавить в шаблон с корзиной, чтобы она тоже работала.
С локалки еще не перенес, тестил пока только в Огнелисе, но выглядит прикольно. И по-идеи должно работать везде. Кстати, выяснилось, что скрипты ШопМодихса не работают в ie6 )))
Т.о. можно делать фильтры любой сложности, любого вида и на аджаксе. Разве что в скобках можно еще указывать количества товаров при выборе разных опций. Но я этим не заморачиваюсь, хотя наверняка это было бы можно.
Fi1osof1
Fi1osof 12 января 2015г в 17:16 #
Кстати, выяснилось, что скрипты ШопМодихса не работают в ie6 )))
Шестой осел уж не первый год как похоронен. О чем вы?

Покликай каталог и корзину здесь: termasol.ru.modxdev.webtm.ru/products/heating/fireplace/
Не все еще сделано, но в целом работает. Корзина там более прокаченная.
proxyfabio1
proxyfabio 12 января 2015г в 17:45 #
Кстати, выяснилось, что скрипты ШопМодихса не работают в ie6 )))
На дворе 2015 год. Уже 8 осел бессмысленно поддерживать, а вы все над хладным телом шестого глумитесь…
M
MisterN 12 января 2015г в 17:49 #
Я между прочим с тела виндо-хр пишу ) Но про ie6 я не серьезно.
M
MisterN 12 января 2015г в 16:57 #
Нда, скрипты обрезались. Ну, вы поняли.
Fi1osof1
Fi1osof 12 января 2015г в 17:18 #
Чессказать даже в исходном тексте сообщения все пусто в в листинге. Выложи на гист то, что ты там писал. Я посмотрю почему вырезалось.
M
MisterN 12 января 2015г в 17:23 #
Fi1osof1
Fi1osof 12 января 2015г в 17:23 #
Странно… Погоняю на досуге
Fi1osof1
Fi1osof 12 января 2015г в 17:27 #
Я так и подумал на них. Вообще MODX вырезает скрипты из запросов. Но посмотрю, может и решу этот вопрос.
Авторизуйтесь или зарегистрируйтесь (можно через соцсети ), чтобы оставлять комментарии.