Комментарии 37
А если используется встроенный в Twig кэш шаблонов, который сохраняет компиляцию шаблона в файл и далее просто «дёргает» этот файл. Используя ваш метод придётся заново генерировать весь кэш шаблонов, которые используют константу.
ЕМНИП Twig сам генерирует новый кэш при изменении кода шаблона
Я файловый кеш и имею в виду. Для того и сделано чтобы при генерировании кеша он ругнулся если константы нет, а если есть — подставил значение.
в скомпилированном классе шаблона
2 — это же значение константы Users::TYPE_TROLL? если да, то это строка так и будет выглядеть в кэше шаблона. и если вдруг значение Users::TYPE_TROLL изменится или в обще убрать константу то придётся сбрасывать кэш.
...
if (((isset($context["usertype"]) ? $context["usertype"] : null) == 2)) {
...
2 — это же значение константы Users::TYPE_TROLL? если да, то это строка так и будет выглядеть в кэше шаблона. и если вдруг значение Users::TYPE_TROLL изменится или в обще убрать константу то придётся сбрасывать кэш.
Я в посте описал проблему в самом начале. При выкатке в бой кеш шаблонов компилируется полностью, снуля и целиком, чтобы в бою не пришлось. Именно на этом этапе хорошо было бы ругнуться, чтобы можно было поправить ошибку до того, как она попала в бой. А если ошибки нет, то бонусом значение запилить вместо вызова в рантайме.
Надеюсь, теперь понятно расписал :]
Надеюсь, теперь понятно расписал :]
У автора проблема довольно простая. Каждый раз когда кто-то забывает поправить шаблон после изменения констант в моделях, где-то умирает котенок во время сборки проекта в каком-нибудь CI сервере сброс и разогрев кэша не вызывает никаких ошибок, и о том что есть какие-то проблемы с шаблонами мы узнаем только после деплоя. Автор же хотел что бы на этапе сбоорки проекта ДО деплоя, любые проблемы с шаблонами вызванные изменением констант останавливали сборку и CI сервер слал бы уведомление что все плохо и сломано.
Нельзя так делать. Шаблоны перекомпилируются по времени их изменения, а не по изменению классов, которые использует шаблон.
Я бы такой шаблон написал так:
И соответственно метод
А вот на счет проверки — да, хорошая штука. Вроде как уже PR есть скоро в ядре подобная проверка будет
Я бы такой шаблон написал так:
{% if user.troll %}
fuckoff
{% else %}
ok
{% endif %}
И соответственно метод
User::isTroll()
А вот на счет проверки — да, хорошая штука. Вроде как уже PR есть скоро в ядре подобная проверка будет
В моем случае шаблоны перекомпилируются при выкатке, сделано для ругани на этом этапе, чтобы не допустить кривые константы в бой.
Ну так у вас сейчас включен дебаг в Twig_Environment.
А когда Вы его отключите, то Вам верно выше указали. В случае чего придётся сбрасывать кэш.
Ну или держать постоянно на дебаге, но в таком случае смысла с кэширования нет.
А когда Вы его отключите, то Вам верно выше указали. В случае чего придётся сбрасывать кэш.
Ну или держать постоянно на дебаге, но в таком случае смысла с кэширования нет.
А стоит ли вообще логикой приложения грузить шаблон?
Имхо, если у вас есть некая проверка, не является ли пользователь троллем, то правильнее было бы это обсчитать в ваших моделях, а шаблону просто передать флаг userIsTroll.
Имхо, если у вас есть некая проверка, не является ли пользователь троллем, то правильнее было бы это обсчитать в ваших моделях, а шаблону просто передать флаг userIsTroll.
Это для наглядности. Бывают места, где таких завязок очень много и выносить это в контроллер или модель не выгодно — получится еще более трудно поддерживаемая простыня свойств и функций, используемых только в одном месте.
Как раз правильно в модель выносить подобные проверки, чтобы не сверяться с константами. Как минимум это способствует сохранности чистоты в шаблонах и выносу логики. Оставили метод isBlabla и потом проверяете. Можете убрать константы, отрефакторить 10 раз, а isBlaBla всегда будет работать, а если нет — ошибку тут же увидите
Точно так же не увижу ошибки и точно так же про шаблон забудется :)
Омг. У вас будет ошибка, что twig не нашел свойства blabla, методов has, is.
Еще раз, логика модельки остается логикой модельки, а ее свойства узнаются через методы.
Вы пишите
А в модели это может быть хоть как:
Еще раз, логика модельки остается логикой модельки, а ее свойства узнаются через методы.
Вы пишите
{{ user.troll ? 'fuck off' : 'ok' }}
А в модели это может быть хоть как:
public function isTroll()
{
return $this->status === self::TROLL_STATUS;
}
public function isTroll()
{
return $this->hasStatus('troll');
}
public function isTroll()
{
return 100 > count($this->getLastMessages(60*60*6));
}
#!/usr/bin/env php
<?php
require 'vendor/autoload.php';
class JustForTest { }
$loader = new Twig_Loader_String();
$twig = new Twig_Environment($loader);
echo $twig->render('Hello, {{ test.notExists() }}', [
'test' => new JustForTest()
] );
даже ворнинга не дает, выводит «Hello, ».
И да, я согласен, что по возможности надо выносить такое дело в модели, но это не всегда выгодно, я уже писал выше.
Вы просто твиг готовить не умеете значит. twig.sensiolabs.org/doc/api.html#environment-options — обратите внимание на strict_variables.
Вот исключение:
Вот исключение:
Twig_Error_Runtime: Method "notExists" for object "JustForTest" does not exist in "Hello, {{ test.notExists() }}" at line 1 in /Users/hell0w0rd/Desktop/test/vendor/twig/twig/lib/Twig/Template.php on line 438
Если вы умеете хорошо готовить, в том числе Twig, — приходите к нам на собеседование :)
Со
В любом случае это — уже отдельная тема для обсуждения.
Со
strict_variables
уже не так комфортно, мне кажется. Да и поздно уже его включать, когда шаблонов слишком много.В любом случае это — уже отдельная тема для обсуждения.
Если принимаете стажеров-студентов, прийду) Для того чтобы было комфортно в симфони например есть тестовое окружение. Где все как на продакшене, но включен режим дебага, в тч strict_variables.
Или вы имеете ввиду что вам переодически нужно использовать несуществующие свойства объектов, а проверки писать не хочется? На мой взгляд выключить strict_vars, это как выключить варнинги и нотисы в php)
Или вы имеете ввиду что вам переодически нужно использовать несуществующие свойства объектов, а проверки писать не хочется? На мой взгляд выключить strict_vars, это как выключить варнинги и нотисы в php)
Да, я имею в виду что в существующих шаблонах сплошняком завязки на то, что отсутствующее свойство — аналог false. И, на самом деле, это слишком удобно чтобы от этого взять и отказаться.
Насчет стажеров-студентов не уверен, но вас никто не съест, если вы спросите это в отклике на наши вакансии.
Насчет стажеров-студентов не уверен, но вас никто не съест, если вы спросите это в отклике на наши вакансии.
А можно пример? Вы бы кстати это в статье указали, что подобное нужно когда отключены strict_vars потому-то потому-то)
Да вот пример —
{% if errors %}...{% endif %}
.strict_variables
не влияет на константы, а топик про них. Да и даже не особо про них, сколько поверхностно о системе расширений.Ну тут опять же если везде в шаблонах возможно есть
Но конкретно в таком виде мне не понятно как у вас собираются аргументы для шаблонов. Обычно это как-то так:
То есть в шаблон и так и так передадутся errors, но в хорошем случае массив будет пуст, и проверка нормально отработает, или же там что-то будет и проверка опять же нормально отработает.
Так что мое мнение уже озвучил — отключать strict равносильно отключению ошибок в php. Вы же вот так:
Не пишите? Вот в шаблонах тоже на мой взгляд так не стоит.
errors
, а может и нет — я бы определил глобальную переменную, по умолчанию пустую, а если ошибки есть — переопределять ее в скопе шаблона при передаче аргументов.Но конкретно в таком виде мне не понятно как у вас собираются аргументы для шаблонов. Обычно это как-то так:
$errors = [];
foreach($form as $field) {
$errors[] = $field->getError();
}
// Или
$errors = $form->getErrors();
То есть в шаблон и так и так передадутся errors, но в хорошем случае массив будет пуст, и проверка нормально отработает, или же там что-то будет и проверка опять же нормально отработает.
Так что мое мнение уже озвучил — отключать strict равносильно отключению ошибок в php. Вы же вот так:
foreach($foo as $bar) {
$arr[] = $bar;
}
Не пишите? Вот в шаблонах тоже на мой взгляд так не стоит.
Такой путь ведёт к результирующей каше.
Конечно, заманчиво ввести глобальный вывод ошибок, а для тех контроллеров, для которых это пока что не удалось внедрить, просто ничего не выводить. В итоге логика, которая должна везде работать одинаково, работает по-разному. Вывод ошибок нужен только там, где про ошибки вообще знают. А если про ошибки знают, то результат может быть только один — ошибок нет (errors = null, errors = [], etc.) или ошибки есть (errors = [...]). Это говорит в том числе и о том, что ошибки не забыли импортнуть в шаблон, ошибок действительно нет.
Если бы интерпретатор php изначально шёл в strict-режиме без возможности устраивать хороводы, то никто бы не говорил, что «неинициализированная переменная равна null — это удобно». Нестрогий режим может использоваться только на продакшне (и то только из-за того, что PHP изначально допускает различные режимы). На девелопменте — только strict со всем вытекающим (написал шаблон, шаблон развалился — исправляй).
Конечно, заманчиво ввести глобальный вывод ошибок, а для тех контроллеров, для которых это пока что не удалось внедрить, просто ничего не выводить. В итоге логика, которая должна везде работать одинаково, работает по-разному. Вывод ошибок нужен только там, где про ошибки вообще знают. А если про ошибки знают, то результат может быть только один — ошибок нет (errors = null, errors = [], etc.) или ошибки есть (errors = [...]). Это говорит в том числе и о том, что ошибки не забыли импортнуть в шаблон, ошибок действительно нет.
Если бы интерпретатор php изначально шёл в strict-режиме без возможности устраивать хороводы, то никто бы не говорил, что «неинициализированная переменная равна null — это удобно». Нестрогий режим может использоваться только на продакшне (и то только из-за того, что PHP изначально допускает различные режимы). На девелопменте — только strict со всем вытекающим (написал шаблон, шаблон развалился — исправляй).
Это совершенно некорректно и ведет к тем же проблемам, что и в старых версиях php делал register_globals и не выставленный в E_ALL уровень репортинга. Умом понимаю, почему Twig по умолчанию не включает стрикт по умолчанию, но сердце отказывается верить. Да и согласитесь,
выглядят куда круче. В крайнем случае это может быть
Когда у нас логика сложнее/ненормальнее.
{% if errors is defined %}
выглядят куда круче. В крайнем случае это может быть
{% if errors|default('') is empty %}
Когда у нас логика сложнее/ненормальнее.
Тема-то не отдельная. Какой смысл предлагать велосипеды из-за плохо прочитанной документации?
Если у вас в отображении есть логика, не касающаяся самого отображения, то можете перестать употреблять слова вроде «модель», «контроллер», «отображение».
Шаблон должен быть таким, чтобы верстальщик мог его редактировать без помощи PHP-программиста. Соответственно, шаблон должен включать в себя только включение других шаблонов, плейсхолдеры, форматирующие функции и конструкции, помогающие организовывать ветвление и итерирование.
С этой точки зрения верстальщику нужно знать только некий «контракт», например:
user — объект, данные и параметры текущего пользователя;
user.firstName — строка, имя пользователя;
user.lastName — строка, фамилия пользователя;
user.troll — булевый флаг, является ли пользователь троллем;
users — список объектов user.
Как именно реализуется user.troll и остальные вещи верстальщику знать не обязательно. Для решения задачи: «Вывести в таблице список пользователей с указанием имени и фамилии. Строки пользователей-троллей помечать классом warning.» верстальщику вы не нужны.
Шаблон должен быть таким, чтобы верстальщик мог его редактировать без помощи PHP-программиста. Соответственно, шаблон должен включать в себя только включение других шаблонов, плейсхолдеры, форматирующие функции и конструкции, помогающие организовывать ветвление и итерирование.
С этой точки зрения верстальщику нужно знать только некий «контракт», например:
user — объект, данные и параметры текущего пользователя;
user.firstName — строка, имя пользователя;
user.lastName — строка, фамилия пользователя;
user.troll — булевый флаг, является ли пользователь троллем;
users — список объектов user.
Как именно реализуется user.troll и остальные вещи верстальщику знать не обязательно. Для решения задачи: «Вывести в таблице список пользователей с указанием имени и фамилии. Строки пользователей-троллей помечать классом warning.» верстальщику вы не нужны.
Вы живете в идеальном мире, где все просто и удобно, но на самом деле все не так.
Это — действительно отдельная тема для обсуждения.
Это — действительно отдельная тема для обсуждения.
На самом деле, это всего лишь ваше неправильное мнение.
Нет никого идеального мира. Контроллер разделяет логику и отображение. К контроллеру нужно относиться так же, как к API сервиса — контекст, который он задаёт шаблону — это все данные, которые шаблону нужно и можно знать.
Вы хотели написать о расширении Twig, но в итоге изначально привели пример того, для чего расширения Twig использовать не нужно.
С этой точки зрения вообще сложно понять fabpot. Кто-кто, а он должен понимать, что предоставление таких расширений по умолчанию — это очень плохо.
В итоге получаем следующее: github.com/fabpot/Twig/issues/1149
Как результат, имеем аналог strict-mode для PHP — sandbox-mode. Это для тех, кто не привык использовать PHP в стиле «ай, пофиг, можно же», а привык думать и разделять.
Нет никого идеального мира. Контроллер разделяет логику и отображение. К контроллеру нужно относиться так же, как к API сервиса — контекст, который он задаёт шаблону — это все данные, которые шаблону нужно и можно знать.
Вы хотели написать о расширении Twig, но в итоге изначально привели пример того, для чего расширения Twig использовать не нужно.
С этой точки зрения вообще сложно понять fabpot. Кто-кто, а он должен понимать, что предоставление таких расширений по умолчанию — это очень плохо.
В итоге получаем следующее: github.com/fabpot/Twig/issues/1149
Как результат, имеем аналог strict-mode для PHP — sandbox-mode. Это для тех, кто не привык использовать PHP в стиле «ай, пофиг, можно же», а привык думать и разделять.
Я могу представить только пару кейсов в которых нужно использовать константы в шаблонах:
проверка на то, может ли пользователь делать что-то (тут лучше сделать карту правил для пользователей и там определить что им можно а что нельзя и проверять в шаблоне без привязки к модели и константам)
в зависимости от типа контента нужно что-то другое вывести. тут опять же лучше уж использовать разные шаблоны и общие части вынести в базовый шаблон (слава наследованию шаблонов).
Но сама идея правильная, не только отсутствующие константы (в теории) могут сломать шаблоны не вызывая ошибок при их компиляции. Ну и хороший пример расширения функционала Twig-а.
проверка на то, может ли пользователь делать что-то (тут лучше сделать карту правил для пользователей и там определить что им можно а что нельзя и проверять в шаблоне без привязки к модели и константам)
в зависимости от типа контента нужно что-то другое вывести. тут опять же лучше уж использовать разные шаблоны и общие части вынести в базовый шаблон (слава наследованию шаблонов).
Но сама идея правильная, не только отсутствующие константы (в теории) могут сломать шаблоны не вызывая ошибок при их компиляции. Ну и хороший пример расширения функционала Twig-а.
Если тролль или не тролль пользователь определяется в результате анализа некоего статуса, представленного «перечислением», то для каждого статуса иметь флаг
userIs<Status>
(или метод user.Is<Status>()
) несколько напряжно может быть. Использование констант в шаблоне тут вполне оправдано, если они используются для определения что пользователю показывать, а что нет (как инфу, так и интерфейсы). А собственно что ещё в шаблоне может быть :)Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Простой плагин для Twig или разворачиваем константы