Pull to refresh

Comments 71

Самого шаблонизатора? Тут на вкус и цвет. Суть статьи в том, как использовать конкретный альтернативный шаблонизатор в Laravel, да еще немного расширить его возможности ближе к нативному Blade.
P.S> Я бы конечно мог обсудить то, что мне нравится в Blitz, и не нравится в Blade/Twig/etc. Но прямо если сильно интересно

Так это как раз намного интереснее кода))

В комментариях ниже есть немного рассуждений по этому поводу.

В Blade мне лично не достает однострочников типа
{{ if($var,$var,$var2) }} или {{ $var }}{{ if($_last,'',', ') }} в циклах

В Blade мне лично не достает однострочников типа

{{ $var ? $var : $var2 }} и {{ $loop->last ? ', ', '' }}соответсвенно

Да, наверняка это сработает, пока у вас в данных есть $var. А как не будет, ой. ошибка. Более того, я вижу тут php код в шаблоне. А не только директивы шаблонизатора.

Попробуйте в скобки взять первый вариант.

{{ ($var ? $var : $var2) }}? И что поменяется? Undefined variable $var как было так и останется

Подождите. Если вместо {{$var}} написать {{($var?$var:$var)}}, переменная перестаёт быть определена? Фигня какая-то.

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

Или Вам надо чтобы подставлялась $var2 , если нет $var ?

Тогда {{$var ?? $var2}}

Да неважно, возьмите тупой пример

{{ $some_flag ? $one : $two }}

Если $some_flag не определена, будет ошибка

{{ ($some_flag ?? false )? $one: $two }}


извините, а это масло масляное-то зачем?

На случай, если $some_flag не был объявлен.

В ветке автор статьи спрашивал аналог Blitz для

{{ if($var,$var,$var2) }}

Я не знаком с Blitz, но мне кажется, в случае $var === 0, в коде выше выведется $var2. В вашем же примере {{$var ?? $var2}} выведется 0.

PS. отвечал на исходный комментарий, который был позже отредактирован. Мой ответ был на такой комментарий:

На случай, если $some_flag не был объявлен, так выше уже привели пример, {{$var ?? $var2}}

 но мне кажется, в случае $var === 0, в коде выше выведется $var2

Как знакомый с Blitz отвечу, в таком примере так и будет, если «флаг» не сравнивать со значением, то он как в любом php коде будет приведен к bool.

Такие конструкции в шаблоне - это же тупо генерация кода в "скомпилированные" шаблоны, значит всё, что выглядит как PHP-код, должно работать как полноценный PHP-код. Поэтому ничто не мешает сделать пэхапэшное подавление ошибок {{ @$some_flag ? $one : $two }}

Ну и конструкции вида $a?$b:$c, $a?:$b, $a??$b и прочие @-непотребства прекрасно работают.

Да конечно работают, но вопрос то как раз и стоял «нафига нам php-код в шаблоне». У меня больше верстальщику делать нечего чтоли, только и мечтает php-код в шаблонах писать, да еще с непотребствами вот этих по-моему мнению совершенно плохо читаемых конструкций $a?$b:$c$a?:$b$a??$b . А уж гасить ошибки это вообще зло

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

Окей, неопределённая переменная в шаблоне - это разве не логическая ошибка?

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

Я бы предпочел чтобы шаблонизатор мне сообщал об необъявленной пременной, в противном случае опечатаетесь в каком-нибудь флаге, и он у вас навсегда false, и сообщит вам об этом только клиент

Строго говоря это не задача шаблонизатора. Если Blade ругается на необъявленные переменные это не заслуга Blade etc, это перехват «ошибок» самого PHP конкретно в Laravel и то в режиму отладки. Это с одной стороны удобно, а с другой стороны для этого люди вон тесты пишут :-)

Ах да, в случае Blade это генерация кода в скомпилированном шаблоне, в лучае Blitz никакой «компиляции» там нет

А что, в блэйде уже нельзя собственные директивы писать? Да, не "из коробки". но пишется довольно просто. буквально за несколько минут.

А зачем? Там вообще можно весь php-код писать. Но троллейбус из буханки сразу вспоминается :-)

Никаких преимуществ у Блица нет, это тупиковая ветвь развития шаблонизаторов, про которую сейчас никто и не помнит, ну кроме вот отдельных энтузиастов.
Если говорить о преимуществах, то имеет смысл попробовать Twig, в котором изначально отсутствуют все те проблемы Blade, которые упоминаются ниже в комментариях.

то имеет смысл попробовать Twig, в котором изначально отсутствуют все те проблемы Blade

Twig отличается от Blade по сути только тем, что «компилированный» шаблон будет php-классом, а не куском php-спагетти кода. А синтаксис еще менее напоминающий синтаксис php (например циклов) - это для типичного верстальщика еще больший разрыв мозга. ИМХО

А какая разница, что там внутри? Вы ведь версию PHP выбираете не по тому, есть там или нет JIT-компиляция, верно?

Строго говоря разница есть. Оверхед на все это хозяйство никто не отменял. В этом смысле, если вообще в шаблоне не вызывать хелперы и коллбеки, то Blade скорее всего будет чуть быстрее Twig'а. Потому, что "под капотом" у него условно require достаточно "плоского" php и перехват буфера. Twig, насколько я смотрел, будет поднимать свои "скомпилированные" классы через автозагрузку.

Ладно если у вас полтора юзера в минуту по товарам ползает, а если реально хай-лоад? Эти вот оверхеды сложатся в лишнее железо

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

А разве в Blade не так?

Вы не поверите! Ну раз началась такая пьянка.

Blade, однострочный if с проверкой что переменная вообще существует тянет за собой php-код (isset) в шаблон

@if( isset($var) ){{ $var }}@else some @endif

Blitz

{{ IF $var }}{{ $var }}{{ ELSE }}some{{ END }}
или вообще однострочник
{{ if($var,$var,'some') }}

Blade, пробег в цикле по списку опять с проверкой что оно существует

@isset($collection)
@foreach($collection as $entry)
blabla
@endforeach
@endisset

Blitz, нет $collection - нет цикла, есть - будет повторяться.

{{ BEGIN collection }}
blabla
{{ END }}

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

@forelse ($users as $user)
    <li>{{ $user->name }}</li>
@empty
    <p>No users</p>
@endforelse

Вообще-то в Blade это аккуратно решается вот так

Да, но фича Blitz это не сам цикл.
К примеру одним синтаксисом {{ BEGIN block }}{{ END }} там одинаково решается два случая.

$dataOne = ['a'=>1,'b'=>2];
$dataTwo = [
  ['a'=>3,'b'=>4],
  ['a'=>5,'b'=>6]
];
$render['block1'] = $dataOne;
$render['block2'] = $dataTwo;
{{ BEGIN block1 }}{{ $a, $b }}{{ END }}
{{ BEGIN block2 }}{{ $a, $b }}{{ END }}
// rendered block1
1, 2
// rendered block2
3, 4
5, 6

Ну и конечно, по-моему мнению все эти «аккуратные» решения от Blade и есть избыток логики в шаблоне, пусть местами удобной. Я ни в коей мере не говорю, что это плохо. В итоге постепенно пепеползаем на Blade, но этот адаптер как раз сделан для того, чтоб какое-то время прицепив Blitz шаблоны существующие запустить какие-то участки кода до полного рефакторинга.

Но вы ведь как раз в Blitz тем самым переносите логику в шаблон..?

Какую конкретно логику? По мне так в Blade/Twig этой самой логики в 10 раз больше.

В Блитце всё гораздо смешнее. Там логика та же, но пишется два раза.


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

А где вы увидели в блице php-код? Как раз таки только логика отображения, и никакого php-кода. И два раза как раз ничего писать не надо

Вот наглядный пример. Для того чтобы понять, как будет рендериться этот код, надо открывать РНР код контроллера и смотреть там, что куда вложено и кто на ком стоял.


В целом, тут проблема шире. Все проблемы Блица являются следствием неверно понятой идеологии. Блиц писался исходя из [неверного] представления о том, что в шаблонах не должно быть логики (ну и плюс для скорости ещё, которой в те далёкие годы могло не хватать). Но по закону сохранения массы, если в одном месте убудет, то в другом обязательно прибудет. И если мы уменьшаем количество логики в шаблоне, то ее становится больше где-то ещё.

Что непонятного в примере? Кроме того, что я для наглядности повторил блоки? Вы настолько плотно работали в Blitz чтоб понимать его проблемы? Мы его юзали около 10 лет (и продолжаем местами), мы знаем как его готовить и он прекрасен. И простейшая, не перегруженная логика там есть. Про отсутствие логики это вам надо смотреть в Mustache – почти индустриальный стандарт logic less templates.

Не надо ничего никуда, ни в каком "коде контроллера" смотреть.

Возьмем для примера некие данные, откуда угодно полученные, это не код "контроллера", это иллюстрация стуктуры.

$data = [
  'item' => ['name'=>'Vasya'],
  'items' => [
    ['name'=>'Petya'],
    ['name'=>'FanatPHP'],
  ],
];

Попрбуем отрендирить его условно Blade

@isset($item)
<div class="item">{{ $item['name'] }}</div>
@endisset
@forelse ($items as $item)
    <div class="item">{{ $item['name'] }}</div>
@empty
    <p>No items</p>
@endforelse

Чтоб не повторять код, можно даже внедрить дочерний подшаблон

<!-- item -->
<div class="item">{{ $item['name'] }}</div>
<!-- main -->
@isset($item)
  @include("item")
@endisset
@forelse ($items as $item)
    @include("item")
@empty
    <p>No items</p>
@endforelse

Ну конечно вызовем

use Illuminate\Support\Facades\View;
return View::make('main', $data);

Теперь сделаем тоже самое на Blitz

<!-- item.tpl -->
<div class="item">{{ $name }}</div>
<!-- main.tpl -->
{{ BEGIN item }}
  {{ include("item.tpl") }}
{{ END }}
{{ IF $items }}
  {{ BEGIN items }}
    {{ include("item.tpl") }}
  {{ END }}
{{ ELSE }}
  <p>No items</p>
{{ END if-items }}

Вызовем, пусть нативно даже

$template = new \Blitz('main');
return $template->parse($data);

Много разницы? Мне кажется никакой. Что тут может быть непонятного?

Честно говоря, я не знаток блейда, и у меня к нему не меньше претензий, чем к Блицу.
Но кстати, хотел спросить. Зачем вы все время выносите кусок шаблона в отдельный файл? Причем одну строчку. Это же maintenance hell. Я реально видел верстальщика, который хотел убить программиста, наплодившего вот таких козявок пару директорий. И тоже, кстати, из-за функциональной убогости шаблонизатора. Убить — не убить, но орал он конкретно — видно что долго копилось. Мало того что приходится открывать 100500 файлов, но главное — не видно общей картины, рвутся теги, ломается форматирование.


По поводу "что здесь непонятного" я, с вашего позволения, не буду ничего отвечать. Зачем вам субъективное мнение одного человека? Спросите ту многочисленную армию программистов, которым настолько понравилось удобство и функциональность Блица, что они не только сами перешли на его использование с других шаблонизаторов, но и активно агитируют других, вызывая лавинообразное увеличение количества сторонников (:

Зачем вы все время выносите кусок шаблона в отдельный файл? Причем одну строчку

Это же пример. И да, не отменяющий факта, что к сожалению, особых вариантов переиспользования под-шаблона в разных местах кроме include нет.

активно агитируют других

Я как раз не агитирую, всего лишь отвечаю на возникающие вопросы. Хотя с моей точки зрения, в случае, если есть доступ к установке расширений и не требуется тянуть фреймворки или другие шаблонизаторы для каких-то небольших проектов – Blitz неплох.

Под небольшими проектами я имею ввиду, к примеру, некую админку с десятком странчек, ради которой не то, что Laravel поднимать смыса нет, а любой шаблонизатор Blade/Twig/etc на php будет с кодовой базой в 10 раз большей самого этого проекта. Я его юзаю даже для одностраничек типа https://nickyx3.ru/geo/, благо на сервере оно и так есть

Господи, да не предлагаю я вам ничего агитировать. Я всего лишь намекаю на "бешеную" популярность этого шаблонизатора, причем делаю это, как мне казалось, довольно толсто.


В данном случае популярность прямо попорциональна юзабилити. Это ответ на ваш вопрос "что непонятно". Да, людям бывает непонятно, почему написано BEGIN, а подразумевается foreach. Причем только в этом месте. А в другом BEGIN будет означать совсем другое — какой-то код, который делает непонятно что, и находится непонятно где.

почему написано BEGIN, а подразумевается foreach. Причем только в этом месте. А в другом BEGIN будет означать совсем другое

Мне кажется, что не разобравшись, Вы делаете неправильные выводы. BEGIN делает совершенно одно и тоже - итерацию по блоку с данными обозначенными ключем в массиве данных. Никакого кода «который делает непонятно что, и находится непонятно где»

намекаю на "бешеную" популярность этого шаблонизатора

Забавно читать это на проекте, который активно его использовал (не уверен что все еще, но тут надо НЛО спрашивать). Это даже если не считать того, что его автор не менее активно использовал его в очень high-load проектах

Blade, пробег в цикле по списку опять с проверкой что он существует

@isset($collection)

Мне показалось или вы показали решение проблемы, которую сами же придумали? Вы же контролируете данные которые попадут в представление, зачем проверки на существование переменных?

П.С. как уже написали выше, в блейде есть аккуратное решение для такого кейса.

Объясню мысль. Я прекрасно понимаю как работают оба шаблонизатора. И да, Blade ЗАСТАВИТ вас пихать в шаблон все данные которые в нем как-бы нужны (либо проверять в самом шаблоне их наличие). Вот только вам они могут быть не нужны в принципе. Ну например пусть у вас есть некая сущность, в которой могут быть какие-то атрибуты, а могут не быть (они в принципе могут быть подтянуты из какого-либо внешнего API например, где вы наличие данных контролировать не можете). Я же не хочу тащить в шаблон «лишние» данные несуществующих атрибутов, это и расход памяти, и некоторое раздувание кода – с моей точки зрения.

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

P.S> Вот так вот пишешь вроде статью про одно, а скатывается все в обсуждение какой шаблонизатор лучше. Никакой. У каждого свои преимущества и недостатки. Статья про то, что если вы знаете и используете что-то альтернативное типа Bllitz (на котором кстати и Хабр когда-то работал (а может и сейчас?), то есть способ прикручивания к Laravel.

А ещё мне кажется, что Blade, как standalone шаблонизатор с ходу использовать не получится, да ведь?

Вы только почему-то забываете, что для шаблона Blade не нужен дополнительный РНР код, чтобы его обслуживать.

Вот щас не понял, вы считаете, что содержимое папки Illuminate\View\* это не дополнительный код для обслуживания "шаблона Blade"?

Раз уж мы решили отойти от темы и обсудить шаблонизаторы. Для «обслуживания» шаблонов Blitz вообще не нужен PHP-код. Ибо сам шаблонизатор это extension. Но к теме это не относится :-)

Да нет, содержимое папки Illuminate\View\ тут не при чем. Речь не про шаблонизатор, а про шаблон. Про такое понятие, как контроллер шаблона(sic!), отсутствующее во всех других шаблонизаторах. Про код вида


foreach (array('Dude', 'Sobchak', 'Donny') as $i_name) {
    $template->block('/block', array('name' => $i_name);
}

который требуется писать в этом контроллере. Меня всегда поражало, что апологеты Блитца как бы не замечают его :)

Вы не поверите, ни разу не использовали в blitz ничего кроме load/parse. Система назначения блоков наверное кому-то нужна (в основном тем, кто хочет выдернуть кусочек шаблона с блоком через fetch), но совсем не обязательна. Собственно в моей обертке она и не используется.

Вообще забавно.

А код вида

use Illuminate\Support\Facades\View;
return View::make('greeting', ['name' => 'James']);
// или
return view('greeting', ['name' => 'James'])->render();

Чем отличается от

$template = new \Blitz('greeting.tpl');
return $template->parse(['name' => 'James']);

Тем более всё это в нашем случае скрыто за фасадом аналогично Blade

use NickyX3\Blitz\Facade\BlitzView;
return BlitzView::apply('greeting',['name' => 'James']);

Смысл команды block то что можно в контекст любой глубины сразу передать переменную, не городя массив 10 кратной вложенности. Точнее говоря, blitz сам построит датасет под капотом. Это очень удобно.

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

Меня тоже. Ибо этот слой и есть самое ключевое и красивое в blitz. Он позволяет отправлять данные в шаблон не городя многомерных массивов, в любом удобном порядке и не смешивая логику вьюхи с HTML. А без этого слоя - блиц обычный шаблонизатор, проигрывающий любому конкуренту по фичасточсти.

не смешивая логику вьюхи с HTML

Этот подход основан на неверных предпосылках. В теории — да, все хорошо, HTML без логики. На практике получается, что вся логика осталась, но теперь размазалась по двум файлам, и в самом шаблоне из явной превратилась в неявную.


Цикл в шаблоне как был — так и остался. Он никуда не делся. Логику из шаблона мы не убрали. Но теперь он стал анонимным, и при правке шаблона мы должны держать в голове, что вот этот блок — это цикл. Это хрестоматийный пример плохого юзабилити.


Не говоря уже о каких-то более хитрых вариантах обработки блоков, где логика действительно выносится из шаблона. И в итоге мы получаем в поддержку два файла — шаблон и его контроллер.


Учитывая всё это, совершенно неудивительно, что пользователи давно уже проголосовали ногами в пользу шаблонов с явной логикой. Из известных мне шаблонизаторов подход с неявной логикой используется ещё в mustache, у которого примерно такая же пользовательская база — несколько early adopters, которые просто привыкли.

mustache, у которого примерно такая же пользовательская база — несколько early adopters, которые просто привыкли

Про mustache вот щас немного смешно было, учитывая что он юзается во всяческих config генераторах, экпорт-скриптах из разных сервисов и т.п., где часто все это программится на bash или внутренних скриптах (даже SQL).

Вот для "хитрых вариантов обработки блоков" это как раз очень хорошо и работает. Понятно, что когда просто список проитерировать подход с "контроллером шаблона" кажется излишеством. Но вот когда возникают всякие нестандартные ситуации, типа условия на закрытие тега, сложные таблицы с colspan и rowspan, итерирования при определенных кратностях и.т.д. и.т.п - удобно, когда это собранно в отдельном скрипте, а не спагетти-шаблоне. Ну во всяком случае, мне удобно. А так дело вкуса.

Ну а про голосование пользователей ногами. Как показал этот тред, пользователи не столько осмысленно делают выбор, сколько просто не осознают этот, несколько нестандартный, подход.

А как насчет поддержки на уровне IDE: автокомплиты, переходы?

Поддерки IDE для чего? Вызвать из фасада одну функцию? Хотя для неё я таки в аннотации положил описание, так что автокомлит работает, да

Или вы про поддержку шаблонов blitz? Тут я вам ничем помочь не могу, хотя можно использовать к примеру Smarty или Twig плагины для IntelliJ IDEA/PHPStorm и просто накрутить в их конфиге двойные фигурные скобки.

Я стал уже немного далек от темы веба, мне действительно просто интересно, а чем сам PHP не шаблонизатор?

Всегда можно написать в HTML

<? ... ?>

... и вставить внутри PHP код, который вроде даже быстрее должен работать

Заглянув в «скомпилированные» файлы того же Blade или Twig вы увидите примерно это самое. На картинке как раз Blade, у Twig там будет php класс

В простейшем случае так и есть. Но шаблонизаторы имеют несколько очень больших преимуществ в сравнении с нативным РНР:


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

Шаблон - это по сути специализированный язык (DSL) для разметки.

Просто интереса ради: а существует ли для PHP на основе XSLT, который можно вкорячить в Laravel?

Речь именно про интеграцию с Ларкой чтобы заменить тот же Blade, сохранив удобство работы с ним и лаконичность со стороны контроллеров.

Так это как раз не сложно, читаете что-то типа "Making Laravel Package", реализуете

Конечно нет, я не стремился полностью повторить функционал фасада View

Blitz, как шаблонизатор, отдельным пакетом есть?

Всмысле пакетом? Это расширение на Си для PHP. Не, ну если совсем сильно хочется, то есть deb который мы собираем для себя, а так github его есть в первом абзаце статьи

Sign up to leave a comment.

Articles