Symfony 4-如何向实体添加业务逻辑

时间:2019-02-07 20:36:14

标签: symfony url entity symfony4 business-logic

我有一个 Article 实体,实际上我在3个树枝模板中使用path()函数,提供文章的 slug 作为第二个参数,以获取URL显示一篇文章。

我知道这不是最好的方法,因为例如,如果我想提供id而不是slug,我应该在多个模板中更改代码。

我想在Article类中使用 getUrl()方法,但后来我无法使用Route服务生成网址。

在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()方法的工作,因此,如果我更改路线中的某些内容,它将反映在所有模板中,但是我无法做到这一点,因为我无法在路径中获取Route服务。文章实体。

那么有没有其他方法可以实现相同的目标呢?

2 个答案:

答案 0 :(得分:2)

您要寻找的是获得所需效果的错误方法。为此,您必须将路由器注入实体,这实际上会将其转变为“业务逻辑”(例如控制器),而不是“持久性”,并且打破了单一责任原则。此外,从技术上很难实现,因为您必须修改Doctrine的内部结构

有两种方法可以正确处理此问题,并且都涉及自定义Twig扩展:

最简单的方法是定义一个自定义的Twig过滤器,该过滤器负责生成正确的URL:

type Props = {
   isActive: boolean;
   setIsActive: (active: boolean) => void;
}
const Child = ({ isActive, setIsActive}: Props) {
   // component
} 

然后在树枝中,您只需要使用以下过滤器:

<?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()]);
    }
}

如果您将Symfony 3.4+与aowowiring / autoconfigure一起使用,只需创建类就足够了,否则您需要将其注册为容器中的树枝扩展名。 请参阅Symfony's documentation了解更多详细信息

仅当您想在视图/模板之外重用路由生成时,才需要使用第二个选项。在这种情况下,必须将必要的逻辑(现在在Twig扩展中)移至单独的独立服务。然后,您必须将此服务注入扩展中并使用它,而不是直接调用路由器。在创建/注册服务时,检查相关的documentation entry以获得详细的了解

答案 1 :(得分:0)

我不明白为什么企业实体应该了解路由系统。

如果您希望实体知道其url,只需在实体中添加一个setUrl()getUrl()方法并将其存储在已经生成的url中