Fi1osof 04 апреля 2013 2 10
Верстаю вот такую форму:



Это не просто статика, а результат поиска номеров, то есть информация динамичная, довольно обширная и с элементами хитрой логики (различное количество номеров и вариантов, дополнительные услуги, галерея и т.п.). Я вам по опыту могу сказать, что если это делать на традиционных чанках-сниппетах, то легче было бы убиться об стену, так как объем кода был бы просто огромным, производительность на нуле, делалось бы это недели две минимум и ни один программист бы не взялся такое сопровождать.

А вот это код этого блока на modxSmarty (не законченный еще, но дает полное представление о плюсах применения):
<h1>Доступные номера</h1>

<p style="padding-top:10px; font-weight:bold;"> Выберите понравившийся номер и необходимые дополнительные услуги </p>

{processor ns=Hotel action="web/reservation/step/search/index" assign=result nocache}

{if $result.success==true}
    <table cellspacing="0" cellpadding="0" border="0" id="room-types-cont" class="base-cont">
        <thead><tr>
                <td class="cell left-holder"> </td>
                <td class="cell name">Категория номера</td>
                <td colspan="2" class="cell price"> Цена за
<strong>1 ночь</strong>, 
                    <span class="currency">руб.</span></td>
                <td class="cell quantity">Количество номеров</td>
                <td class="cell amount right-cell">Стоимость, <span class="currency">руб.</span></td></tr>
        </thead>
        <tbody>
            
            
            {* All rooms *}
            {foreach from=$result.object key=room_id item=room nocache}
                {* counf variables *}
                {assign var=variables_total value=count($room.variables)}
                <tr>
                    <td class="cell left-holder" rowspan="{$variables_total+2}"> </td>
                    <td class="cell" rowspan="{$variables_total+2}">
                        <div class="title">{$room.room.title}</div>
                    </td>
                    <td class="cell empty-cell"> </td>
                    <td class="cell empty-cell"> </td>
                    <td class="cell empty-cell"> </td>
                    <td class="cell empty-cell"> </td>
                </tr>
                
                {* All variables *}
                {foreach from=$room.variables key=variable_id item=variable}
                    <tr>
                        <td class="cell empty-cell"> </td>
                        <td class="cell empty-cell"> </td>
                        <td class="cell empty-cell"> </td>
                        <td class="cell empty-cell"> </td>
                    </tr>
                {/foreach}
                {* Eof All variables *}
                
                <tr class="room-type">
                    <td class="cell persons empty-cell border-top-0"> </td>
                    <td class="cell price empty-cell border-top-0"> </td>
                    <td class="cell quantity empty-cell border-top-0"> </td>
                    <td class="cell amount empty-cell border-top-0"> </td>
                </tr>
                
            {/foreach}
            {* Eof All rooms *}
        </tbody>
    </table>
{else}
    {$result.message}
{/if}


Многие очень сильно путают логику (в программном плане), и логику в шаблонах, и утверждают, что в шаблонах логики не должно быть. Вот это большое и опасное заблуждение. Есть логика на сбор, обработку, модификацию и запись информации (толстый клиент с обширными правами), а есть узкопрофильная логика (тонкий клиент). Логика в шаблонизации — чаще всего — это просто логика на чтение. То есть мне (как верстальщику) скормили информацию, сказали (вот тебе такие-то переменные, у тебя там будет то-то и то-то), и я беру и оформляю все это. Но не просто размещаю плейсхолдеры, а могу на основе исходных данных закладывать какую-то логику визуализации (к примеру, подсчитать количество полученных элементов, выполнить валидацию данных и т.п.), и на основе этого следать, к примеру, выпадающие списки, указать различные колспаны и т.п., запрограммировать javascript-плагинчик. Это огромные возможности по визуализации имеющихся сырых данных без необходимости каждый раз дергать программиста «а мне вот еще такая переменная нужна, чтобы это была сумма вот этих трех переменных».

Вот давайте теперь более предметно рассмотрим представленный код.

Здесь единственное, что досталось от программиста — это процессор «web/reservation/step/search/index» из пространства имен «Hotel». Мне программист сказал «вот этот процессор будет тебе возвращать информацию о всех найденных номерах, их количестве, возможности для бронирования, описание и т.п., там будут переменные с такими-то именами и такими-то типами данных».

Я беру и вызываю этот процессор: {processor ns=Hotel action=«web/reservation/step/search/index» assign=result nocache}

Все. Результат выполнения процессора присвоится указанной мною переменной $result.

Далее я могу проверить статус выполнения процессора. Если $result.success == true, то значит процессор выполнился успешно, и как мне сказал программист, все данные по номерам будут доступны мне в массиве $result.object;
Вот я делаю проверку:
{if $result.success==true}


А если $result.success не будет равен true, то сообщение об ошибке будет мне доступно в переменной $result.message (это мне тоже подсказал добрый программист, так как сам я верстальщик, и вообще не имею доступа к коду этого процессора, для меня это — черный ящик).

Вот я вывожу это сообщение в блоке «иначе»:
{else}
    {$result.message}
{/if}


А в основном блоке (если у меня все ОК) я в цикле по каждому номеру набиваю конечные HTML-блоки.
{foreach from=$result.object key=room_id item=room nocache}


Внутри каждого цикла, как я и указал, у меня будут массив $room, содержащий всю доступную мне информацию по номеру, и ключик — id-шник номера в переменной $room_id.

Вот я себе комментарий написал, который улучшить читаемость моего кода, и не будет выводиться в брацзер: {* counf variables *}

А вот я подсчитал количество вариантов для конкретного номера {assign var=variables_total value=count($room.variables)}, и это значение присвоил переменной $variables_total. Эта переменная мне понадобится в дальнейшем, чтобы указать правильный роуспан для конкретного блока.
<td class="cell left-holder" rowspan="{$variables_total+2}">


А далее я набиваю уже блоки по каждому конкретному варианту номера.
{foreach from=$room.variables key=variable_id item=variable}


Так же для удобства я могу разбить это на отдельные файлы-шаблоны, и подгружать их через {include file=}, а так же использовать типовые файлы-шаблоны для отдельных шаблонов.

И работает это все гораздо быстрее, чем MODX-парсер. Но в сравнении с MODX-парсером есть еще очень серьезное преимущество — актуальность данных в переменных. Вот простой пример:
[[+var:notempty=`[[!mysnippet]]`]]

Вот здесь MODX сначала выполнит сниппет mysnippet, и только потом, в зависимости от того, выполнилось условие var:notempty или нет, выведет результат сниппета mysnippet или не выведет. Но выполнит он этот сниппет в любом случае.

Вот в этом случае этого не произойдет:
{if $var!=''}
    {snippet name=mysnippet}
{/if}


И вот как раз это и есть реальное отделение логики от визуализации. Верстальщик вообще не лезет в логику процессора. У него есть данные, он их визуализирует. Когда будет менять дизайн, он просто переоформит по-новому имеющиеся сырые данные, но не придется менять логику процессора. Данные будут все те же, просто по-другому сверстаны.

Вы все еще работаете на чистых чанках и сниппетах? Сорри, но крупный проект мы вам не сможем доверить.

UPD: Если вы верстальщик со знанием jQuery, мне нужна небольшая помощь по этой форме. Поиск и все такое я напрограммировал, мне нужна помощь именно по верстке отдельных блоков этого модуля, а так же javascript-программинг этой формы (выбор кол-ва номеров, сопутствующих услуг и подсчет конечной суммы), в общем нужен верстальщик-программист интерфейсов.

UPD2: Помощник нашелся.
10 комментариев
abaddon651
abaddon65 04 апреля 2013г в 10:34 #
Полностью согласен, так работать с шаблоном намного удобнее. Modxsmarty пока не успел опробовать (работа срочная навалилась), но думаю скоро наверстаю. Но по опыту работы с шаблонизатором Twig (где так же есть плюшки типа вложеных циклов и логических операторов, да еще и наследование шаблонов, которые в принципе способны заменить тот же phx), могу сказать, что потом со стандартным шаблонизатором modx работаешь, так сказать с кривой улыбкой. Вроде бы все хорошо, столько всего понапихано, но скорость не та, от кучи чанков и сниппетов меню раздуто кук бурдюк. В общем было бы замечательно если бы modx из коробки поддерживал бы еще парочку шаблонизаторов на выбор)
Fi1osof1
Fi1osof 04 апреля 2013г в 10:57 #
В общем было бы замечательно если бы modx из коробки поддерживал бы еще парочку шаблонизаторов на выбор)
Так он сейчас как бы и поддерживает (основное новшество версии 2.2.7, анонсированной на 9 апреля). Теперь можно переопределить системную настройку, и $modx->getParser() будет подтягивать ваш собственный парсер. Но я не уверен, что там все идеально (сужу по логике Смарти). Шаблонизатор компиллирует свои шаблоны, а не просто парсит какой-то код. Это включает подгрузку функций всяких и т.п. А если у нас в чанке код, я не могу сказать точно по поводу того, как Смарти будет кушать этот код. Есть ли возможность скармливать ему контент. Очень сомневаюсь, так как он подавится первой же фигурной скобкой.
Может Twig лучше себя ведет?
К любом случае, я считаю, что они должны сделать поддержку php-кода в шаблонах (на подобии того, как это у меня сделано в phpTemplates). В таком случае я четко знаю, что я выполню чистый php, пропишу там логику, и всегда буду уверен, где у меня реальный код, а где шаблонизация.
Fi1osof1
Fi1osof 04 апреля 2013г в 11:09 #
Вот еще небольшой примерчик:
{assign var=i value=1}
<select>
    <option>Выбрать</option>
    {while $i <= $room.available}
    {assign var="mod" value=$i%100}
        <option>{$i} {if $mod > 4 && $mod < 20}номеров{elseif $mod==1}номер{else}номера{/if}</option>
        {$i++}
    {/while}
</select>

То есть набивается select, и в зависимости от конкретного числа, используется склонение слова.
abaddon651
abaddon65 04 апреля 2013г в 13:19 #
А нет ли какой документации по работе с modxsmarty (как вызывать сниппеты, как глобальные переменные типа site_url выводить и т.д.)? Или синтаксис смарти смотреть в документации?
Fi1osof1
Fi1osof 04 апреля 2013г в 13:23 #
Сам синтаксис Smarty стандартный. По Smarty в инете полно проработанной мануалы.
От меня только несколько тегов, специфических конкретно для MODX: {snippet}, {chunk} и т.п. По ним примеры есть прям на странице компонента: modx.com/extras/package/modxsmarty
Там же есть демо-видео.
Все остальное в рамках самого MODX-а. То есть, к примеру, вызываем {snippet name=test}. Происходит вызов $modx->runSnippet(). Далее все на уровне самого MODX-а.
s
silentworks 04 апреля 2013г в 15:20 #
Great explanation Nik, this is something I think the MODX community in general still haven't grasped. I am working on some Twig integration which I will probably do a core version in a fork of MODX just for Experimental use. It is said too often that designers don't like logic in template, but designers don't make templates anyway (besides designing them). Frontend developers make template, as since most are familiar with JavaScript they would have to create logic of some sort anyway.

I will share this on Twitter and hope others will understand the useful of having logic in templates, rather than a bunch of parsers parsing Snippets/Chunks and Templates.
Fi1osof1
Fi1osof 04 апреля 2013г в 15:41 #
Hi, Andrew!
Glad to see you here :)
Thanks for sharing and for kind words.
rthrash1
rthrash 04 апреля 2013г в 21:12 #
This looks like a very cool experiment Nick and a look forward to seeing others like it from you. This would probably come in very handy for more complex Add-ons like Discuss. Keep up the good work! :)
Fi1osof1
Fi1osof 04 апреля 2013г в 21:15 #
Thank, Ryan.
Fi1osof1
Fi1osof 03 мая 2013г в 02:57 #
Опытным путем выяснил, что можно, к примеру, и вот такое творить: {assign var=cost value=array('500000 руб.', '3000000 руб.', '5000000 руб.')}
Авторизуйтесь или зарегистрируйтесь (можно через соцсети ), чтобы оставлять комментарии.