如何在 Symfony (Twig) 中包含可重用的小部件? [英] How to include a reusable widget in Symfony (Twig)?

查看:15
本文介绍了如何在 Symfony (Twig) 中包含可重用的小部件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,我对 Symfony 和 Twig 还是很陌生.我想知道如何最好地在模板中包含/创建一段可重用的代码.例如,假设您有一个要在每个页面上显示的侧边栏.

So, I'm still fairly new to Symfony and Twig. I was wondering how to best include/create a snippet of reusable code in the templates. Say, for example, that you have a sidebar that you want to show on every page.

{% 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 %}

在那个侧边栏中有几个小部件,它们都有自己的逻辑.您如何创建/包含这些小部件?

And that in that sidebar are a couple of widgets that all do their own logic. How you do go about creating/including those widgets?

到目前为止,我遇到了几种解决方案.

So far, I've come across several solutions.

第一个是将小部件作为控制器嵌入树枝.

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"中

And include that in 'sidebar.html.twig' like so

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

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

    {# and so on #}
</div>

作为服务

我还看到一些人将小部件注册为服务(可以直接在 Twig 中使用).与小部件主类

As a service

I've also seen some people register widgets as services (that can be used in Twig directly). With the widget main class

// src/AppBundle/Service/RecentArticlesWidget.php
namespace AppBundleService;

use SymfonyComponentDependencyInjectionContainerInterface;

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:     AppBundleServiceRecentArticlesWidget
        arguments: ["@service_container"]

传递给控制器​​中的模板,

passed to the template in the controller,

namespace AppBundleController;

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 中像这样简单地使用

so it can simply be used like this in Twig

{# sidebar.html.twig #}

{{ recentArticlesWidget.getRecentArticles()|raw }}

或者,您还可以通过将服务添加到 Twig 配置中来直接将服务添加到 Twig 全局变量中.这样,控制器就不需要将它传递到视图中.

Alternatively, you can also add your service to the Twig global variables directly by adding it to the Twig config. This way, it won't need to be passed into the view by the controller.

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

作为 Twig 扩展

这与使用上面的服务非常相似(查看文档).您创建了一个与前面显示的服务几乎相同的 twig 扩展类

As a Twig Extension

This one is very similar to using a service above (see the documentation). You create an a twig extension class that is almost identical to the service shown previously

// src/AppBundle/Twig/RecentArticlesWidgetExtension.php
namespace AppBundleTwig;

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

将其注册为带有添加标签的服务

Register that as a service with an added tag

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

并像 Twig 中的全局函数一样简单地使用它

and simply use it like a global function in Twig

{# sidebar.html.twig #}

{{ getRecentArticles() }}

想法

我注意到的一件事是,对于最后两种方法,逻辑和视图似乎不再分离.您基本上编写了一个小部件函数并让该函数输出小部件的完整 html.这似乎违背了 Symfony 试图强制执行的模块化和模式.

Thoughts

One thing I noticed is that with the last two methods is that the logic and the view don't seem to be seperated at all anymore. You basically write a widget function and have that function output the complete html for the widget. This seems to go against the modularity and patterns Symfony tries to enforce.

另一方面,为每个小部件调用不同的控制器或控制器操作(使用它们自己的树枝渲染)似乎可能需要比可能需要的更多处理.我不确定它是否真的会减慢任何速度,但我想知道它是否过度.

On the other hand, calling a distinct controller or controller action (with their own twig renders) for every single widget seems like it could take more processing than might be needed. I'm not sure if it actually slows anything down, but I do wonder if its excessive.

长话短说,有没有在 Symfony 中使用可重用小部件的最佳实践?我确信其中一些方法也可以混合使用,所以我只是想知道如何最好地解决这个问题.

Long story short, is there a best practice for using reusable widgets in Symfony? I'm sure some of these methods can also be mixed, so I was just wondering how to best go about this.

推荐答案

Twig 扩展和 Twig 宏应该为您指明正确的方向.

Twig extension and Twig macro should point you in the right direction.

对视图使用宏,对业务逻辑使用扩展.

Use the macro for the view and extension for the business logic.

在您的 Twig 扩展示例的旁注中,最好只传递您正在使用的服务而不是整个服务容器.

On a side note in your Twig extension example, it's probably a good idea to only pass in services that you are using instead of the whole service container.

这篇关于如何在 Symfony (Twig) 中包含可重用的小部件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆