Symfony 4(Twig)中可重复使用的动态侧边栏?

reusable dynamic sidebar in Symfony 4 (Twig)?

我最近开始使用 Symfony 4,现在我正在用这个很棒的框架创建我的第一个网站。

我有一个侧边栏应该显示在我大约一半的路线中,侧边栏的内容应该用数据库中的一些数据填充。

目前我在所有这些路由中使用 DI,并将注入存储库的结果传递给路由的模板(包括我的 sidebar.html.twig)。

public function chalupaBatman(FancyRepository $repository)
{
    $sidebarObjects = $repository->getSidebarObjects();
    $this->render('controllername/chalupabatman.html.twig', [
        'sidebarObjects' => $sidebarObjects,
    ]);
}

我想知道是否有办法为我在控制器中定义的每条路线避免这种情况。

到目前为止,我在 Whosebug 上找到了这个主题。

用户 Mvin 完美地描述了我的问题,并提供了一些解决方案。

然而 "what is the best practice" 部分仍然没有答案,而且主题是 2017 年的;因此,解决这个问题的方法在 Symfony 4 中可能已经改变。

我最终得到了一个 TwigExtension 解决方案。我将描述如何实现它,如果你们能提供一些反馈,那就太好了。 如果我产生了大量的开销或遗漏了一些重要的东西,请告诉我 ;-)

好的,首先我通过命令行创建了一个 TwigExtension

php bin/console make:twig-extension AppExtension

然后我将 class 修改为如下所示:

<?php

namespace App\Twig;

use App\Repository\ArticleRepository;
use Psr\Container\ContainerInterface;
use Symfony\Contracts\Service\ServiceSubscriberInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

class AppExtension extends AbstractExtension implements ServiceSubscriberInterface
{
    private $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function getFunctions(): array
    {
        return [
            new TwigFunction('article_sidebar', [$this, 'getArticleSidebar'], ['needs_environment' => true, 'is_safe' => ['html']]),
        ];
    }

    public function getArticleSidebar(\Twig_Environment $twig)
    {
        $articleRepository = $this->container->get(ArticleRepository::class);
        $archive = $articleRepository->myAwesomeLogic('omegalul');

        return $twig->render('/article/sidebar.html.twig', [
           'archive' => $archive,
        ]);
    }

    public static function getSubscribedServices()
    {
        return [
            ArticleRepository::class,
        ];
    }
}

为了激活 Lazy Performance,这样我们的存储库和附加的 Twig_Environment 不会在我们使用 Twig 时每次都被实例化 我们实现 ServiceSubscriberInterface 并添加 getSubscribedServices 方法。

因此,我们的 Repo 和 Twig_Environment 只有在我们在模板中实际调用 {{ article_sidebar() }} 时才会实例化。

{# example-template article_base.html.twig #}
{% extends 'base.html.twig' %}
{% block body %}
    <div class="row">
        <div class="col-10">
            {% block article_body %}{% endblock %}
        </div>
        <div class="col-2">
            {{ article_sidebar() }}
        </div>
    </div>
{% endblock %}

现在我可以像这样定义文章路径的模板了:

{# example-template /article/show.html.twig #}
{% extends 'article_base.html.twig' %}
{% block article_body %}
    {# display the article here #}
{% endblock %}