在Symfony2中使用控制器外部的存储库

时间:2014-05-07 02:05:37

标签: symfony controller doctrine

我目前正在使用一个函数来获取我的存储库:

public function getRepositories()
{
    // Tasks
    $tasks = $this->getDoctrine()
        ->getRepository('Model:Task');

    // Task Info
    $taskInfos = $this->getDoctrine()
        ->getRepository('Model:TaskInfo');


    return array(
        'tasks'             => $tasks,
        'taskInfos'         => $taskInfos,
    );
}

所以在我的控制器动作中,我可以像这样调用一些SQL:

$repositories = $this->getRepositories();
$task = $repositories['tasks']->findOneById($id);

但是现在我有一些控制器,我注意到我正在将相同的getRepositories()函数复制到每个控制器中,因为它会重复复制代码。

我想要的是拥有一个帮助类,这可能是其中的一个功能。

但是我如何做到这一点,因为助手类不是控制器而且$this->getDoctrine()明显不起作用?

由于

3 个答案:

答案 0 :(得分:6)

您可以使用服务(http://symfony.com/doc/current/book/service_container.html)并注入学说。

services:
    my.helper.class:
        class: Acme\MyBundle\Helper\MyHelper
        arguments: [ @doctrine.orm.entity_manager ]

<?php

namespace Acme\MyBundle\Helper;

use Doctrine\ORM\EntityManager;

class MyHelper
{ 
    protected $manager;

    public function __construct(EntityManager $manager)
    {
        $this->manager = $manager;
    }

    public function getRepositories()
    {
        $tasks = $this->manager->getRepository('Model:Task');
        $taskInfos = $this->manager->getRepository('Model:TaskInfo');

       return array(tasks, taskInfos);
    }
}

话虽如此,在你的情况下,我并不真正理解这个目的,因为控制器是为了获取数据并将其返回。

你没有重复逻辑。

看起来太多了,实体经理已经是这样的帮助了。

答案 1 :(得分:3)

使用您想要编写的代码并不能获得任何好处。更好的做法是为每个实体创建一个存储库类,并注入实体管理器。您还可以定义这些实体服务将扩展的另一个抽象存储库服务。我在我的应用程序中这样做,我发现它非常有用,因为我可以将自己的函数添加到我正在使用的存储库中。

我可以在控制器中做这样的事情:

$this->getTaskRepository->findOneById(1);
$this->getTaskRepository->getSomeTasks(); // executes a query with query builder

答案 2 :(得分:2)

@ Tobias的建议很好但你也应该考虑一个好的实践:&#34; 只注入你需要的服务&#34;。

此处的重点是,您正在注入实体管理器以获取两个 Doctrine存储库tasks&amp; tasksInfos)请注意,实体管理器执行的操作更多,仅检索 Doctrine Repositories

当您需要帮助程序中的doctrine存储库时,通常会注入实体管理器,然后检索您的存储库。但是,如果您没有注入所需的服务,那么您需要注入一个来帮助您获得所需的服务。

另一个约束(可以考虑)是Doctrine存储库只能通过实体管理器检索,因此我们可以控制它施工。

因此,注入存储库而不是依赖于实体管理器的唯一方法是考虑using Factory services and methods 委派创建服务,然后注入相关服务。

我会建议,

namespace Acme\MyBundle\Helper;

// Add the relevant use(s) here ...

class AnyGivenService
{ 
    protected $taskRepository;
    protected $taskInfoRepository;

    public function __construct(TaskRepository $taskRepository, TaskInfoRepository $taskInfoRepository)
    {
        $this->taskRepository    = $taskRepository;
        $this->taskInfoRepository= $taskInfoRepository;
    }

    public function doSomethingWithYourRepositories()
    {
        // ....
    }
}

虽然您的服务定义应该是,

<service id="any_given_service" class="AnyGivenService">
    <argument type="task_repository" />
    <argument type="task_info_repository" />
</service>

<service id="task_repository" class="TaskRepository" factory-service="doctrine.orm.entity_manager" factory method="getRepository">
    <argument>Task</argument>
</service>

<service id="task_info_repository" class="TaskInfoRepository" factory-service="doctrine.orm.entity_manager" factory method="getRepository">
    <argument>TaskInfo</argument>
</service>

优点,

  • 您的代码干净且更具可读性,因为您的服务构造函数更具体地了解其实际需求。
  • 可测试性,您只需要模拟您的存储库,而不是为实体管理器和存储库创建模拟。