Итак, я все еще довольно новичок в Symfony и Twig. Мне было интересно, как лучше всего включать/создавать фрагмент кода многократного использования в шаблонах. Скажем, например, что у вас есть боковая панель, которую вы хотите показать на каждой странице.Как включить многоразовый виджет в Symfony (Twig)?
{% extends 'AppBundle::base.html.twig' %}
{% block body %}
<div id="wrapper">
<div id="content-container">
{# Main content... #}
</div>
<div id="sidebar">
{% include 'sidebar.html.twig' %}
</div>
</div>
{% endblock %}
И что в этой боковой панели есть пара виджетов, которые все выполняют свою собственную логику. Как вы собираетесь создавать/включать эти виджеты?
До сих пор я сталкивался с несколькими решениями.
В качестве контроллера
Первый был embed the widget as a controller(s) в Twig.
class WidgetController extends Controller
{
public function recentArticlesWidgetAction()
{
// some logic to generate to required widget data
// ...
// Render custom widget template with data
return $this->render('widgets/recentArticles.html.twig', array('data' => $data)
);
}
public function subscribeButtonWidgetAction()
{
// ...
return $this->render('widgets/subscribeButton.html.twig', array('data' => $data)
}
// Many more widgets
// ...
}
И включают в себя, что в «sidebar.html.twig» как так
<div id="sidebar">
{# Recent Articles widget #}
{{ render(controller('AppBundle:Widget:recentArticlesWidget')) }}
{# Subscribe-Button widget #}
{{ render(controller('AppBundle:Widget:subscribeButtonWidget')) }}
{# and so on #}
</div>
Как сервис
Я также видел, что некоторые люди регистрации виджетов в качестве услуги (которые могут быть использованы в Twig напрямую). С виджета главного класса
// src/AppBundle/Service/RecentArticlesWidget.php
namespace AppBundle\Service;
use Symfony\Component\DependencyInjection\ContainerInterface;
class RecentArticlesWidget
{
protected $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function getRecentArticles()
{
// do some logic (use container for doctrine etc.)
}
}
, который затем регистрируется в качестве службы,
# src/AppBundle/Resources/config/services.yml
services:
recentArticlesWidget:
class: AppBundle\Service\RecentArticlesWidget
arguments: ["@service_container"]
передается в шаблон в контроллере
namespace AppBundle\Controller;
class SidebarController {
public function showAction($request) {
// Get the widget(s)
$recentArticlesWidget = $this->get('recentArticlesWidget');
// Pass it (them) along
return $this->render('sidebar.html.twig', array('recentArticlesWidget' => $recentArticlesWidget));
}
}
поэтому он может просто быть использован, как это в Твиг
{# sidebar.html.twig #}
{{ recentArticlesWidget.getRecentArticles()|raw }}
В качестве альтернативы вы также можете добавить свою службу в глобальные переменные Twig, добавив ее в конфигурацию Twig. Таким образом, контроллер не должен будет передаваться в представление.
#app/config/config.yml
twig:
globals:
# twig_var_name: symfony_service
recentArticlesWidget: "@recentArticlesWidget"
В Туиг Extension
Это один очень похоже на использование службы выше (see the documentation). Вы создаете класс удлинительного прутика, который почти идентичен службе, показанную ранее
// src/AppBundle/Twig/RecentArticlesWidgetExtension.php
namespace AppBundle\Twig;
class RecentArticlesWidgetExtension extends \Twig_Extension
{
protected $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function getFunctions()
{
return array(
"getRecentArticles" => new Twig_Function_Method($this, "getRecentArticles")
// register more functions
);
}
public function getRecentArticles()
{
// do some logic (use container for doctrine etc.)
}
// Some more functions...
public function getName()
{
return 'WidgetExtension';
}
}
Регистрации, что в качестве службы с дополнительным тегом
# src/AppBundle/Resources/config/services.yml
services:
recentArticlesWidget:
class: AppBundle\Twig\RecentArticlesWidgetExtension
arguments: [@service_container]
tags:
- { name: twig.extension }
и просто использовать его как глобальную функцию в Twig
{# sidebar.html.twig #}
{{ getRecentArticles() }}
Мысли
Одна вещь, которую я заметил, что с двух последних м Это то, что логика и взгляд не кажутся вообще разделенными. Вы в основном пишете функцию виджетов и получаете эту функцию для вывода полного html для виджета. Это, похоже, противоречит модульности и шаблонам, которые Symfony пытается обеспечить.
С другой стороны, вызов отдельного контроллера или действия контроллера (со своими собственными ветвями) для каждого отдельного виджета, похоже, может потребовать больше обработки, чем может потребоваться. Я не уверен, что это фактически замедляет все, но я действительно задаюсь вопросом, не слишком ли это.
Короче говоря, есть ли практика использования многоразовых виджетов в Symfony? Я уверен, что некоторые из этих методов также могут быть смешаны, поэтому мне просто интересно, как лучше всего поступить по этому поводу.
Спасибо за ваш ответ! То, что вы предлагаете, полезно и правильно. Тем не менее, мой вопрос был более похожим на то, как лучше всего помещать сложный код в боковую панель (или где-либо еще) в шаблон ветви. Как и в, контент, который должен выполнять свои собственные запросы и имеет все виды логики для генерации вывода. Материал, который обычно не передавался в основном контроллере. Я взял виджеты в качестве простого примера (принесите мне три самых популярных статьи и хорошо их покажу). Я лично склонен внедрять дополнительные «контроллеры виджетов», как описано выше, но мне было интересно, что сделали все остальные. – Mvin