Twig: выбор определенных блоков и их рендеринг
Я перехожу к движку шаблонов twig в PHP-приложении. В частности, я хотел бы использовать движок ветки для визуализации форм.
Посмотрев, как symfony2 использует ветку для визуализации виджета формы, у них есть огромный файл шаблонов, который содержит все виджеты:
(...)
{% block password_widget %}
{% spaceless %}
{% set type = type|default('password') %}
{{ block('field_widget') }}
{% endspaceless %}
{% endblock password_widget %}
{% block hidden_widget %}
{% set type = type|default('hidden') %}
{{ block('field_widget') }}
{% endblock hidden_widget %}
{% block email_widget %}
{% spaceless %}
{% set type = type|default('email') %}
{{ block('field_widget') }}
{% endspaceless %}
{% endblock email_widget %}
{% block test_widget %}
{% spaceless %}
<div>
{{test}}
<div>
{% endspaceless %}
{% endblock test_widget %}
(...)
У меня есть вопрос, как я могу "захватить" блоки из этого шаблона и сделать их?
Пока я могу загрузить шаблон и вызвать get block для получения всех блоков:
twig = new \Twig_Environment($loader, array('cache' => 'cache'));
$template = $twig->loadTemplate('view\form_div_layout.html.twig');
//var_dump($template->getBlocks()); //try getting all blocks
$template->displayBlock('test_widget', array('test' => 'test'));
echo $template->render();
К сожалению, в этом случае я не могу отобразить только блок "test_widget". Что мне нужно сделать, чтобы извлечь блок "test_widget" из шаблона, а затем вставить его в другой шаблон, чтобы отобразить всю форму?
Ответы
Ответ 1
Оказывается, вместо этого следует использовать $template->renderBlock('blockname', array('test' => 'test'));
. Это сделает рендеринг twig, который блокирует, а затем возвращает строку, содержащую разметку для этого блока. Затем можно использовать эхо, чтобы отобразить его или вставить в другие шаблоны.
Полный пример:
$loader = new \Twig_Loader_Filesystem(array('/my-template-root'));
$twig = new \Twig_Environment($loader, array('debug' => true));
$template = $twig->loadTemplate('view\form_div_layout.html.twig');
$result = $template->renderBlock('blockname', array('test' => 'test'));
echo $result;
Ответ 2
Это здорово! Я также хотел добавить, что есть функция hasBlock
, которая позволяет выполнить проверку, прежде чем пытаться сделать рендеринг шаблона. Это позволяет проверять шаблон, который строится, как ожидалось, или, в моем случае, имеет дополнительные блоки. Для чего это стоит, вот пример из одного из моих консольных приложений, которое отправляет уведомления по электронной почте
$templateContent = $this->getContainer()->get('twig')->loadTemplate('FTWGuildBundle:AuctionNotification:notificationEmail.html.twig');
$body = $templateContent->renderBlock('body', array('siteDomain' => $siteClient->getSiteDomain(), 'staticContentDomain' => $siteClient->getStaticContentDomain(), 'batch' => $batch->getNotifications(), 'auction_notification_lockout_period' => $this->getContainer()->getParameter('auction_notification_lockout_period')));
$subject = ($templateContent->hasBlock("subject")
? $templateContent->renderBlock("subject", array('batchSize' => $batch->getSize(), 'batch' => $batch))
: "Auction House Notifications");
Ответ 3
Если вы используете Symfony и хотите иметь доступ к глобальным переменным (app, app.user и т.д.), тогда это отлично работает:
private function renderBlock($template, $block, $params = array())
{
/** @var \Twig_Environment $twig */
$twig = $this->get('twig');
/** @var \Twig_Template $template */
$template = $twig->loadTemplate($template);
return $template->renderBlock($block, $twig->mergeGlobals($params));
}
Я просто добавил, что на моем контроллере есть частная функция. Прекрасно работает. Благодаря @F21 для указания меня в правильном направлении.
Ответ 4
Примечание: hasBlock не будет работать, если шаблон расширяет или внедряет родительский блок.
см
https://github.com/twigphp/Twig/issues/450