Symfony控制器的最佳实践

时间:2018-06-17 09:34:47

标签: symfony structure code-reuse

我正在寻找symfony控制器逻辑的最佳实践。我目前的代码 有一个控制器:

<?php

namespace App\Controller;

use App\Entity\Categories;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class Controller extends AbstractController
{
    /**
     * @Route("/", name="main_index")
     */
    public function index()
    {

        $categories = $this->getDoctrine()
            ->getRepository(Categories::class)
            ->findAll();

        return $this->render('index.html.twig', [
            'categories' => $categories,
        ]);
    }
}

类别实体:     

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Categories
 *
 * @ORM\Table(name="categories", indexes={@ORM\Index(name="title", columns={"title"}), @ORM\Index(name="url", columns={"url"})})
 * @ORM\Entity
 */
class Categories
{
    /**
     * @var bool
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string|null
     *
     * @ORM\Column(name="title", type="string", length=255, nullable=true, options={"default"="NULL"})
     */
    private $title = 'NULL';

    /**
     * @var string|null
     *
     * @ORM\Column(name="url", type="string", length=255, nullable=true, options={"default"="NULL"})
     */
    private $url = 'NULL';

    /**
     * @var string|null
     *
     * @ORM\Column(name="header_text", type="text", length=65535, nullable=true, options={"default"="NULL"})
     */
    private $headerText = 'NULL';

    /**
     * @var string|null
     *
     * @ORM\Column(name="body_text", type="text", length=65535, nullable=true, options={"default"="NULL"})
     */
    private $bodyText = 'NULL';

    /**
     * @var string|null
     *
     * @ORM\Column(name="footer_text", type="text", length=65535, nullable=true, options={"default"="NULL"})
     */
    private $footerText = 'NULL';

    /**
     * @var \DateTime|null
     *
     * @ORM\Column(name="created_at", type="datetime", nullable=true, options={"default"="NULL"})
     */
    private $createdAt = 'NULL';

    /**
     * @var \DateTime|null
     *
     * @ORM\Column(name="updated_at", type="datetime", nullable=true, options={"default"="NULL"})
     */
    private $updatedAt = 'NULL';

    public function getId(): ?bool
    {
        return $this->id;
    }

    public function getTitle(): ?string
    {
        return $this->title;
    }

    public function setTitle(?string $title): self
    {
        $this->title = $title;

        return $this;
    }

    public function getUrl(): ?string
    {
        return $this->url;
    }

    public function setUrl(?string $url): self
    {
        $this->url = $url;

        return $this;
    }

    public function getHeaderText(): ?string
    {
        return $this->headerText;
    }

    public function setHeaderText(?string $headerText): self
    {
        $this->headerText = $headerText;

        return $this;
    }

    public function getBodyText(): ?string
    {
        return $this->bodyText;
    }

    public function setBodyText(?string $bodyText): self
    {
        $this->bodyText = $bodyText;

        return $this;
    }

    public function getFooterText(): ?string
    {
        return $this->footerText;
    }

    public function setFooterText(?string $footerText): self
    {
        $this->footerText = $footerText;

        return $this;
    }

    public function getCreatedAt(): ?\DateTimeInterface
    {
        return $this->createdAt;
    }

    public function setCreatedAt(?\DateTimeInterface $createdAt): self
    {
        $this->createdAt = $createdAt;

        return $this;
    }

    public function getUpdatedAt(): ?\DateTimeInterface
    {
        return $this->updatedAt;
    }

    public function setUpdatedAt(?\DateTimeInterface $updatedAt): self
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }


}

我想在所有其他页面上重复“$ categories”变量。 所以它意味着 - 每个页面上的额外查询,但我不想重复代码:

$categories = $this->getDoctrine()
        ->getRepository(Categories::class)
        ->findAll();

无处不在,因为所有页面都必须始终显示类别。同样通过symfony逻辑,所有@route都应该有自己的功能。那么我想如何制作路由逻辑而不是重复类别请求代码呢?通过使用此代码创建另一个外部类,并在所有其他路由方法中重用它?

编辑: 我的解决方案:

templates / index.html.twig 文件(一个地方):

 {{ render(controller('App\\Repository\\CategoriesListRepository::getCategories')) }}

templates / categories.html.twig (一个文件):

{% for category in categories %}
    <li>
        {{ category.getName() }}
    </li>
{% endfor %}

Repository / CategoriesListRepository.php

    <?php declare(strict_types=1);

namespace App\Repository;

use App\Entity\Categories;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;

/**
 * Class CategoriesListRepository
 * @package App\Repository
 */
final class CategoriesListRepository extends AbstractController
{


    /**
     * @var \Doctrine\Common\Persistence\ObjectRepository
     */
    private $repository;

    /**
     * CategoriesListRepository constructor.
     * @param EntityManagerInterface $entityManager
     */
    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->repository = $entityManager->getRepository(Categories::class);
    }

    public function getCategories(): Response
    {
        return $this->render('categories.html.twig', ['categories' => $this->repository->findAll()]);
    }
}

很高兴听到一些意见/建议

5 个答案:

答案 0 :(得分:1)

有几种可能的解决方案。最明显的一个是子类AbstractController,向其中添加protected方法getCategories(),并从需要类别的所有控制器方法中调用该方法。

但仍然:这是非常重复的。因此,我可能会添加一个自定义的Twig函数,因此在需要它的任何模板中,您只需编写类似{{ displayCategories() }}{% for category in getCategories() %} ... {% endfor %}的内容,并且Twig扩展可以为您处理所有这些内容。 (有关更多信息,请参阅Twig文档。这并不困难。您只需将Doctrine作为依赖项注入扩展的构造函数并覆盖getFunctions()的{​​{1}}方法。

答案 1 :(得分:0)

您可以从模板中调用控制器。

创建仅呈现类别列表的控制器:

public function listAllAction()
{
    $categories = $this->getDoctrine()
        ->getRepository(Categories::class)
        ->findAll();

    return $this->render('categories.html.twig', [
        'categories' => $categories,
    ]);
}

然后在twig文件中使用render函数调用它:

<div id="list-of-categories">
    {{ render(controller(
        'App:Category:listAll',
    )) }}
</div>

答案 2 :(得分:0)

看看How to Inject Variables into all Templates (i.e. global Variables)

您将创建以下配置:

# config/packages/twig.yaml
twig:
    # ...
    globals:
        # the value is the service's id
        category_service: '@App\Service\CategoryService'

在您的CategoryService中,您将获得getCategories()方法中的所有类别。稍后,您可以调用您的树枝模板category_service.getCategories()

答案 3 :(得分:0)

您可以使用$ container-&gt; set()方法将$ categories作为容器的变量,然后使用$ container-&gt; get(&#39; categories&#39;)获取变量。

答案 4 :(得分:0)

如果您只想避免重复代码(在不同的地方有代码副本),之前的答案可能适合。但是如果你不想一次又一次地执行你的存储库调用以优化数据库性能,我认为将代码移动到不负责的地方(例如twig全局变量)并不是一个好的做法。

即使结果在不同的页面上总是相同的,也可能会返回不同的结果。但那是你不应该担心的事情。

相反,我会为我的查询使用doctrine结果缓存。缓存应该决定所请求的数据是否与之前的请求相同,并给我数据。

只要您使用的是学说而没有DBAL,您就可以了。