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 %}
我最近开始使用 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 %}