Smarty – проникся, оценил, в восторге %)

Smarty – проникся, оценил, в восторге %)

В таком состоянии прибывал разве что после чтения Кнута или Фридла. Почему-то только сегодня узнал о Smarty, точнее, только сегодня заставил себя прочесть документацию и пожалел, что не сделал этого раньше. Ниже – попытка самооправдания и самоуспокоения %)

Многие вещи красиво реализованы в сией системе. Уже уйму времени брожу вокруг да около, многие из идей были решены подобным образом, но не все.

Модификаторы и последовательный вызов модификаторов у меня реализованы таким же образом. Навеяно было "Escaping substitutions" Масона (для Perl), и развито практически до того, что сейчас присутствует в Smarty. Вот только сами модификаторы представляли собой методы отдельного класса, и поэтому их неудобно было дополнять. Была идея сделать регистратор, но поленился и не реализовал.

Встроенных функций у меня было всего три: include, execute и тренарный if (? : ). Execute позволял вызывать методы любого класса с произвольными параметрами, существовал класс General, содержащий наиболее часто используемые методы. Не так удобно, как в Smarty, но работало и позволяло без особого труда расширять функциональность %) А вот с моим ифом мне приходилось туговато. Сложные, а тем более вложенные, условия не поддерживались, поэтому часто приходилось писать отдельные методы под конкретный случай. Зная о LXP, я понимал, в каком направлении нужно двигаться, но, мать ее за ногу, лень мне не давала.

Способ предоставления доступа к переменным, как это сделано в Smarty, был отброшен с самого начала. Тогда мне казалось, что верстальщикам будет сложно работать с массивами, хешами и различными структурами. Поэтому поддерживались только обычные переменные и псевдохеши (args_param1, cookies_cname и т.д.). Сейчас вновь обдумывая проблему понял, _насколько_ сильно я заблуждался.

Из остального были пре/пост фильтры (реализованные, правда, в другом классе), некоторое подобие конфигурационных файлов. Существовали, конечно, некоторые идеи, которые отсутствуют в Smarty, но они заточены под генерацию блоков и работу в связке с БД.


В общем, выплакался %) С одной стороны приятно, что многие "правильные" вещи родил самостоятельно, с другой – в который раз ругаю себя за то, что не обращаю внимания на разработки других программистов.

Переводить все проекты на php, конечно же, не планирую, но обязательно детально проанализирую и позаимствую лучшее у Smarty.

После изучения документации недостатком определил для себя неудобный синтаксис вызова функций. Приятнее и функциональнее было бы использовать обычный синтаксис языка (для perl уж точно). Section показалась несколько усложненной, но это все легко исправимые мелочи.
 

Demiurg

Guest
>После изучения документации недостатком определил для себя неудобный синтаксис вызова функций.
каких функций ?
 
{custom_func param1="1" param2="$var"}

Гораздо удобнее использовать обычный синтаксис, позволяющий передавать в качестве параметров сформированные на лету структуры.

{# custom_func(param1 =>"1", param2 => [1, 2, 3], param3 => { a => [2,3], 2b=> [3,4]} ) #}
 

Demiurg

Guest
ИМХО синтаксис марти удобнее.
К тому же он близок к HTML. И как показывает практика, параметров, обычно не много и все они простые по своей структуре.
 
Выше я немного не точно выразился. "Удобный" - понятие субъективное, посему насчет этого я спорить не буду. Синтаксис вызова функций в Smarty, мне кажется, преднамеренно упрощен плюс влияние оказала специфика формирования структур в php.

Я часто делаю запросы из шаблона, поэтому для меня наличие возможности передачи сложных параметров обязательно.

{# execute_query("template", { From => ["user"], Where => [["user_name", "=", $param{name}], ["user_email", "=", $param{email}]], OrderBy => [[$param{orderby}, $param{ordertype}]], Limit => [$param{limit}] } #}
 

Demiurg

Guest
А вот это явно не правильно. Шаблоны не должны ничего знать о структуре базы.
 
Originally posted by Demiurg
А вот это явно не правильно. Шаблоны не должны ничего знать о структуре базы.
Пример утрированный, чтоб наглядно показать, о каких структурах я говорю. Впрочем, признаюсь честно, бывают случаи, когда лень добавлять метод и я пользуюсь таким вот выполнением запросов.

А вот практику расширения запросов при построении блоков я использую постоянно и выглядит это примерно так:

func(tmp, param, sql_ext);

{# user_list("template", { user_name => $param{name}, user_email => $param{email} }, { OrderBy => [[$param{orderby}, $param{ordertype}]], Limit => [$param{limit}] }) #}

Структура полностью сокрыта, а управление сортировкой и лимитами доступно верстальщику, который может не знать даже основы SQL.
 

Demiurg

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

Касательно первой части сообщения. Уйду в оффтопик, но все-таки хотелось бы развить мысль. Практика показывает, что использование Limit и OrderBy избавляет программиста от необходимости лишнего кодирования . На примере метода user_list это можно наглядно проиллюстрировать.

Обычный вызов метода. Используются Limit и Order by, установленные программистом по умолчанию в коде метода:
Код:
{# user_list("template") #}
Допустим, понадобилось отобразить отсортированный список e-mail пользователей. Используем тот же метод:
Код:
{# user_list("template", undef, 
{ OrderBy => ["user_email", "asc"] }) #}
Хотим построить блок, содержащий список 5 последних зарегистрированных пользователей:
Код:
{# user_list("template", undef, 
{ OrderBy => ["user_regdate", "desc"], Limit => [0, 5] }) #}
Имея некий механизм, который перед парсингом шаблонов проверяет параметры на предмет удовлетворения некоторым условиям (минимальная / максимальная длинна, регулярное выражение) и, в случае необходимости, устанавливает значения по умолчанию, элементарно решается вопрос построения различных поисковых форм и сортировки таблиц по выбранной пользователем колонке.

Код:
{# user_list("template", undef, 
{ OrderBy => [$param{orderby}, $param{ordertype}]}) #}

По-моему, наглядная демонстрация того, как при минимальных затратах на кодирование можно решать сложные задачи.
 

Demiurg

Guest
Еще раз говорю, что бизнес логика должна быть в скрипте а не в шаблоне. В этом и есть основная идея применения шаблонных движков. Шаблон должен получать данные, которые ему надо вывести. Его задача сделать из данных html. Задача скрипта получить данные из базы/файлов/etc и передать их нужному шаблону. Сортировка так же входит в данные.
 
Я всегда стараюсь понять позицию своего собеседника и, если убеждаюсь в его правоте, принять. При сравнении двух решений аргумент "так правильно" не выглядит особенно убедительно. У любого решения есть достоинства и недостатки и для выявления наиболее оптимального решения достаточно сравнить их по этим двум критериями.

Достоинства своего решения я описал выше и привел наглядные примеры: избавление от необходимости лишнего кодирования, возможность гибкого управления не только внешним видом блока, но и его содержимым путем использования простых параметров, многократное использование одного и того же метода для построения различных блоков.

Возможно, правильнее будет создать методы user_email_list, user_last_registered и т.д., которые будут содержать вызовы user_list с жестко закодированными параметрами. Но я не вижу достоинств такого способа (насколько я понял, ты именно его имел в виду).

Я не хочу спорить ради спора, мне просто интересная аргументированная точка зрения по этому вопросу. Какие недостатки способа, который описал я, и какие преимущества способа, о котором говоришь ты? Как с его помощью решаются описанные выше тривиальные задачи?

Постскриптум. Ты уже два раза говорил о сортировке, как о бизнес-логике. Лимит ты таковой не считаешь?
 

Demiurg

Guest
Ты говоришь о удобстве кодирования а я говорю о проектировании. В твоих примерах в шаблонах присутсвует бизнес логика. Это значит, что при изменения структуры базы или источника данных тебе придется переписывать не только скрипты но и шаблоны. Думаю нет смысла объяснять, что это не удобно. И наоборот, при смене дизайна надо вспоминать структуру базы и логику работы скриптов.

лимит тоже относится к бизнес-логике.
 
Для начала еще раз хочу повторить, что я не считаю правильным и грамотным выполнение запросов из шаблонов. И по этому поводу я спорить не буду.

Originally posted by Demiurg
Ты говоришь о удобстве кодирования а я говорю о проектировании. В твоих примерах в шаблонах присутсвует бизнес логика. Это значит, что при изменения структуры базы или источника данных тебе придется переписывать не только скрипты но и шаблоны.
Опровергну это утверждение. Мне придется лишь переписать метод user_list, и по-другому реагировать на Limit и OrderBy. Если данные хранятся в файле, попросту отсортировать по нужному полю и выдать нужное количество результатов. Нет никакой зависимости от источника данных и структуры хранения. Соответствующий синтаксис для Limit и OrderBy был выбран исключительно потому, что я чаще работаю с БД, но он может быть использован где угодно.

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

Описанные мной задачи, когда необходимо использовать лимит или ту же сортировку встречаются слишком часто. Опиши, пожалуйста, каким образом они должны быть решены в твоем понимании. Считаешь ли ты такую конструкцию:
Код:
{# user_list("template", n) #}
(n – количество необходимых записей) неверной?

Буду благодарен за развернутый ответ.
 

Demiurg

Guest
А если пример расширить и сортировка будет зависить например от прав пользователя, который залогинен ? Сотрировка и лимит это бизнес-логика. То, что в некоторых случаях она давольно простая не значит, что её надо мешать с логикой представления.

>Каким образом может изменение структуры повлечь
>необходимость править шаблоны мне неясно. Объяснишь?
На счет изменения структуры я наверно погоречился, у тебя логика работы с источником за пределами шаблона. Но вот если, например, придется сортировать сначала по имени и потом по фамилии, тогда что ?

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

Все очень просто, шаблон просто выводит пришедшие ему данные и все. Скрипты же исходя из запроса достают данные из источника, лимитируют, сортируют и отдают шаблону. Причем если вывод однообразный, то используется один шаблон.

>Считаешь ли ты такую конструкцию:
>{# user_list("template", n) #}
>(n – количество необходимых записей) неверной?
не верной, лимитирование - это бизнес логика.
 
А если пример расширить и сортировка будет зависить например от прав пользователя, который залогинен ? Сотрировка и лимит это бизнес-логика. То, что в некоторых случаях она давольно простая не значит, что её надо мешать с логикой представления.
Почему не привести аналогию с модификаторами переменных в смарти? Задача user_list выполнить все необходимые действия для получения и обработки данных и вернуть результат. Limit всего лишь влияет на представление результата.

Я так понял, что ты имеешь в виду следующую проблему: нужно для user1 выводить 10 новостей, для user2 – 15, а у меня в шаблоне жестко записано значение для лимита. Но это никакая не проблема. Во-первых, никто не мешает решить данную задачу в самом user_list. Ведь использование описываемого метода позволяет легко решать легкие задачи, но не запрещает решать сложные любым другим способом (например, твоим же). Во-вторых, эта задача (да и многие другие) может быть решена силами описываемого метода. Для плюшек:
Код:
{ # user_list("template", undef, 
{ Limit => [0, $cookies{limit}] }) #}
Если информация хранится в конфиге.
Код:
С возвращением, {# $user{login} #},
{ # user_list("template", undef, 
{ Limit => [0, $user{limit}] }) #}
Надеюсь, я правильно понял то, о чем ты написал.

На счет изменения структуры я наверно погоречился, у тебя логика работы с источником за пределами шаблона. Но вот если, например, придется сортировать сначала по имени и потом по фамилии, тогда что ?
Опять же, если я все верно понял, то решается задача так:
Код:
{ # user_list("template", undef, 
{ OrderBy => [["user_firstname", "asc"], ["user_lastname", "asc"]]}) #}
Все очень просто, шаблон просто выводит пришедшие ему данные и все. Скрипты же исходя из запроса достают данные из источника, лимитируют, сортируют и отдают шаблону. Причем если вывод однообразный, то используется один шаблон.
Т.е. предполагается, что для каждого блока, отличающегося лимитом или сортировкой, существует свой метод? Как быть с динамической сортировкой и лимитом, когда они определяются пользователем?
 

Demiurg

Guest
>Почему не привести аналогию с модификаторами переменных в смарти?
Можификаторы меняют представление данных, но не меняют данных, лимит же - это изменение именно данных.

>Надеюсь, я правильно понял то, о чем ты написал.
да, но в твоем случае шаблон опять же знает о куках, а это бизнес-логика. А если для того, что бы определить какой лимит будет для пользователя, нужно сделать пару запросов в базу ?

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

>Т.е. предполагается, что для каждого блока, отличающегося
>лимитом или сортировкой, существует свой метод?
какой метод ? данные попадают в шаблонизатор до начала отрисовки шаблона.

>Как быть с динамической сортировкой и лимитом, когда они
>определяются пользователем?
все это задается в скрипте, только он знает, как взять данные у пользователя.
 
да, но в твоем случае шаблон опять же знает о куках, а это бизнес-логика. А если для того, что бы определить какой лимит будет для пользователя, нужно сделать пару запросов в базу ?
С плюшками плохой пример, согласен. Второй лучше т.к. хеш user может быть заполнен любым образом (в том числе, данными из таблицы).
и тут получается, что для изменения сортировки нам нужно менять и шаблоны и скрипты.
Скрипт менять нет необходимости. В частном случае он работает с БД и умеет формировать сложный ордер.

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

Описываю только случай с отображением данных.

Инициализация.
Чтение конфигурационного файла.
Подключение к БД.
Получение глобальных настроек.
Определение группы пользователя и его прав.
Определение карты (разметки страницы).
Проверка параметров (полученных из get, post, cookies), обработка ошибок, в случае их возникновения.
Регистрация данных, которые будут доступны в карте (параметры, глобальные настройки, права пользователя).
Передача управления парсеру карт.

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

Например, главная страниц новостей, в которой отображается список 5 свежих новостей, а затем список, содержащий только заголовки.
Код:
{ # include("page_header") # }
Это статическая информация. 
{ # news;:list("news_ext_list", undef, { Limit => [0, 5] } #}
{ # news::list("news_title_list", undef, { Limit => [5, 10] } #}
{ # include("page_footer") # }
А вот так может выглядеть страница какой-то конкретной новости (в $param{id} содержится идентификатор новости, который проверен и должным образом обработан еще на этапе проверки параметров):

Код:
{ # include("page_header") # }

{ # news;:full("news_full", { news_id => $param{id} } #}

{ # news::list("news_bytheme_list", 
{ newsskip_id =>$param{id}, theme_id => $lc{theme_id}} , 
{ Limit => [0, 10] } #}


{ # comment;:list("comment_ext_list", 
{ master_id => $param{id}, master_type => TP_NEWS } #}

{ # include("page_footer") # }
Первый блок – это сама новость, второй – список новостей по теме (выбранная новость пропускается), третий – список комментариев для данной новости.


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

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

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

Постарался объяснить как можно проще, естественно, очень многое упустил.
 
Сверху