2017-01-22 2 views
3

Итак, я все еще довольно новичок в 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? Я уверен, что некоторые из этих методов также могут быть смешаны, поэтому мне просто интересно, как лучше всего поступить по этому поводу.

ответ

0

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

Что-то вроде этого:

layout.html.twig будет что-то вроде этого:

{% block title} 
// title goes here 
{%endblock%} 

<div id="wrapper"> 
    <div id="content-container"> 
     {% block pageContent %} 
     {% endblock %} 
    </div> 
    <div id="sidebar"> 
     // Side bar html goes here 
    </div> 
</div> 

Теперь все страницы будут наследовать от этого layout.html.twig. Скажем, например, страница называется home.html.twig будет:

home.html.twig 

{% extends 'AppBundle::layout.html.twig' %} 

{% block title%} 
// this page title goes here 
{% endblock %} 

{% block pageContent %} 
    //This page content goes here 
{% endblock %} 

Вы можете добавить столько блоков, как это необходимо, например css и js блоков для каждой страницы.

Надеюсь, это поможет!

+0

Спасибо за ваш ответ! То, что вы предлагаете, полезно и правильно. Тем не менее, мой вопрос был более похожим на то, как лучше всего помещать сложный код в боковую панель (или где-либо еще) в шаблон ветви. Как и в, контент, который должен выполнять свои собственные запросы и имеет все виды логики для генерации вывода. Материал, который обычно не передавался в основном контроллере. Я взял виджеты в качестве простого примера (принесите мне три самых популярных статьи и хорошо их покажу). Я лично склонен внедрять дополнительные «контроллеры виджетов», как описано выше, но мне было интересно, что сделали все остальные. – Mvin

1

Я думаю, что самый простой способ является определение блока в шаблоне, а затем расширяя этот шаблон для визуализации блоков, как так:

#reusable.html.twig 

{% block reusable_code %} 
    ... 
{% endblock %} 

И

#reused.html.twig 
{% extends 'reusable.html.twig' %} 

{{ block('reusable_code') }} 

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

1

Twig extension и Twig macro должны указывать вас в правильном направлении.

Используйте макрос для представления и расширения для бизнес-логики.

На боковой ноте в примере расширения Twig, вероятно, неплохо было бы передать только те сервисы, которые вы используете, а не весь контейнер обслуживания.

Смежные вопросы