【问题标题】:Using a repository outside of a controller in Symfony2在 Symfony2 中使用控制器外部的存储库
【发布时间】:2014-05-07 02:05:37
【问题描述】:

我目前正在使用一个函数来获取我的存储库,如下所示:

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() 显然不起作用?

谢谢

【问题讨论】:

    标签: symfony controller doctrine


    【解决方案1】:

    您可以使用服务 (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);
        }
    }
    

    话虽如此,我并不真正理解在您的情况下这样做的目的,因为控制器旨在获取数据并返回它。

    你没有重复逻辑。

    好像太过分了,实体管理器那样已经是帮手了。

    【讨论】:

    • 你是个传奇!!谢谢,这正是我需要的!
    • 很高兴能为您提供帮助!
    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

      @Tobias 的建议效果很好,但您还应该考虑一个好的做法:“仅注入您需要的服务”。

      这里的重点是您要注入 Entity Manager 以获得两个 Doctrine 存储库 (tasks & tasksInfos),请记住 strong>Entity Manager 所做的更多只是检索 Doctrine Repositories

      当您需要在您的助手中创建一个理论存储库时,您通常会注入一个实体管理器,然后检索您的存储库。但是,您不是在注入您需要的服务,而是在注入一个帮助您获得您需要的管理器。

      另一个限制(可以考虑)是 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>
      

      优势,

      • 您的代码更简洁,更易读,因为您的服务的构造函数更具体地了解其实际需求。
      • 可测试性,无需为实体管理器和存储库创建模拟,您只需模拟存储库。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-02
        • 1970-01-01
        • 1970-01-01
        • 2021-10-06
        • 2016-01-22
        • 1970-01-01
        • 2020-10-18
        • 2016-12-25
        相关资源
        最近更新 更多