2017-01-22 17 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 %} 

サイドバーには、すべて独自のロジックを実行するウィジェットが2つあります。それらのウィジェットの作成/含める方法は?

これまでのところ、私はいくつかの解決策を見つけました。

コントローラ

は、最初は小枝にembed the widget as a controller(s)であったように。

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 
    // ... 
} 

とサービス

よう

<div id="sidebar">   
    {# Recent Articles widget #} 
    {{ render(controller('AppBundle:Widget:recentArticlesWidget')) }} 

    {# Subscribe-Button widget #} 
    {{ render(controller('AppBundle:Widget:subscribeButtonWidget')) }} 

    {# and so on #} 
</div> 

LIKE「sidebar.html.twig」に私も何人かの人々がそれを使用することができます(サービスとしてのウィジェットを登録見てきたことなどが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)); 
    } 
} 

は、それが単にこのように使用することができますTwigで

{# sidebar.html.twig #} 

{{ recentArticlesWidget.getRecentArticles()|raw }} 

の場合は、サービスをTwigグローバル変数に直接追加することもできます。この方法では、コントローラーの視界に入る必要はありません。小枝拡張

として

#app/config/config.yml 
twig: 
    globals: 
     # twig_var_name: symfony_service 
     recentArticlesWidget: "@recentArticlesWidget" 

この1つは、上記サービス(see the documentation)を使用することに非常に類似しています。あなたは付加されたタグを持つサービスとして

# src/AppBundle/Resources/config/services.yml 
services: 
    recentArticlesWidget: 
     class: AppBundle\Twig\RecentArticlesWidgetExtension 
     arguments: [@service_container] 
     tags: 
      - { name: twig.extension } 

と単純には小枝

にグローバル関数のようにそれを使用することを

// 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'; 
    } 
} 

登録以前に示したサービスとほぼ同じです小枝拡張クラスを作成します私が気づい

{# sidebar.html.twig #} 

{{ getRecentArticles() }} 

思考

ことの一つは、最後の2メートルとのことです論理と見解はもはや分離されていないように見えるということです。あなたは基本的にウィジェット関数を書いて、その関数にウィジェットの完全なhtmlを出力させます。これはSymfonyが実行しようとするモジュール性とパターンに反しているようです。

一方、1つのウィジェットごとに個別のコントローラまたはコントローラアクション(独自のtwigレンダー)を呼び出すと、必要以上に処理が必要になるようです。私はそれが実際に何かを遅くするかどうかはわかりませんが、私はそれが過剰かどうか疑問に思います。

短い話ですが、再利用可能なウィジェットを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 %} 

必要に応じては、例えば、各ページのcssjsブロックをできるだけ多くのブロックを追加することができます。

希望すると便利です。

+0

ありがとうございました!あなたが提案するものは有用で正しいものです。しかし、私の質問は、小枝テンプレートのサイドバー(または他の場所)に複雑なコードをどのように置くのが良いかということに沿ったものでした。同様に、独自のクエリを実行する必要があり、すべての種類のロジックを持ち、出力を生成します。メインコントローラーでは通常通り過ぎることのないもの。私は簡単な例としてウィジェットを取った(私に最も人気のある3つの記事を取り出し、うまく表示する)。私は個人的に上記のように追加の「ウィジェットコントローラ」を埋め込む傾向がありますが、他の人たちが何をしたのか不思議でした。 – Mvin

1

私は最も簡単な方法は、テンプレート内のブロックを定義し、そのようになどのブロックをレンダリングするために、そのテンプレートを拡張していると思う:あなたはより多くの再利用をしたい場合は

#reusable.html.twig 

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

そして

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

{{ block('reusable_code') }} 

をかあなたのブロックにはビジネスロジックやモデルコールが含まれています。小枝の延長は道のりです

1

小枝の拡張子と小枝マクロは正しい方向を指します。

ビジネスロジックの表示と拡張にマクロを使用します。

Twig拡張の例では、サービスコンテナ全体ではなく、使用しているサービスだけを渡すことをお勧めします。