我有一个 Article 实体,实际上我在 3 个 twig 模板中使用了 path() 函数,提供文章的 slug 作为第二个参数,以获取 url显示一篇文章。
我知道这不是最好的方法,因为,例如,如果我想提供 id 而不是 slug,我应该更改多个模板中的代码。
我想在 Article 类中使用 getUrl() 方法,但无法使用 Route 服务来生成 url。
在 Symfony 4 中是否有更好的方法来做到这一点?
这是ArticleController的一部分:
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\Article;
use App\Repository\ArticleRepository;
class ArticleController extends AbstractController
{
...
/**
* @Route("/article/{slug}", name="article_show")
*/
public function show(Article $article) {
return $this->render('article/show.html.twig', [
'article' => $article
]);
}
}
然后在模板中我有类似的代码,如下所示:
{% for article in articles %}
...
<a href="{{ path('article_show',{ 'slug': article.slug } ) }}">
{{ article.title }}
</a>
...
{% endfor %}
我想做的是有这样的代码:
{% for article in articles %}
...
<a href="{{ article.getUrl() }}">
{{ article.title }}
</a>
...
{% endfor %}
其中 getUrl 执行 path() 方法的工作,因此,如果我更改路由中的某些内容,它将反射(reflect)在所有模板中,但我无法执行此操作,因为我无法在文章实体。
那么有没有其他方法可以实现相同的目标?
最佳答案
您正在寻找的是达到预期效果的错误方法。为此,您必须将路由器注入(inject)到实体中,这本质上将其转变为“业务逻辑”(例如 Controller )而不是“持久性”,并打破了单一职责原则。此外,它在技术上很难实现,因为你必须修改 Doctrine 的内部结构
有两种方法可以正确处理这个问题,并且都涉及自定义 Twig 扩展:
最简单的方法是定义一个自定义 Twig 过滤器,负责生成正确的 URL:
<?php
namespace App\Twig\Extension;
use App\Entity\Article;
use Symfony\Component\Routing\RouterInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
class ArticleExtension extends AbstractExtension
{
private $router;
public function __construct(RouterInterface $router)
{
$this->router = $router;
}
public function getFilters()
{
return [
new TwigFilter('article_url', [$this, 'getArticleUrl']),
];
}
public function getArticleUrl(Article $article): string
{
return $this->router->generate('article_show', ['slug' => $article->getSlug()]);
}
}
然后在 twig 中你只需使用这样的过滤器:
{% for article in articles %}
...
<a href="{{ article|article_url }}">
{{ article.title }}
</a>
...
{% endfor %}
如果您使用带有 awtowiring/autoconfigure 的 Symfony 3.4+,只需创建该类就足够了,否则您需要将其注册为容器中的 twig 扩展。 请引用Symfony's documentation了解更多详情
仅当您想在 View /模板之外重用路由生成时,才需要提到第二个选项。在这种情况下,必须将必要的逻辑(现在位于 Twig 扩展中)移至单独的独立服务。然后,您必须将此服务注入(inject)到扩展中并使用它,而不是直接调用路由器。查看相关documentation entry有关创建/注册服务的详细说明
关于Symfony 4 - 如何向实体添加业务逻辑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54581879/