I am currently using a function to get my repositories like so:

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

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


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

So in my controller actions, I can just call some SQL like this:

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

But now that I have a few controllers, I've noticed that I'm copying that same getRepositories() function into each which is not good as it's replicating the code repeatedly.

What I want is to have like a helper class, and this could be one of the functions in that.

But how do I do this, given the helper class won't be a controller and there for $this->getDoctrine() obviously wouldn't work?

Thanks

有帮助吗?

解决方案

You can use services (http://symfony.com/doc/current/book/service_container.html) and inject doctrine.

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);
    }
}

That being said, I do not really understand the purpose of this in your situation as controllers are meant to get data and return it.

You are not duplicating logic.

It seems too much, the entity manager is already a helper in that way.

其他提示

You don't really gain anything with the code you want to write. A better practice would be to make a repository class for each entity, which has entity manager injected. You could also define another abstract repository service which those entity services will extend. I do it that way in my applications and I found it really useful, because I can add own functions to the repository I am using.

I can do something like this in controller:

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

@Tobias's suggestion works fine but you should also consider a good pratice that says: "Inject only the services you need".

The point here is that you're injecting the Entity Manager to get two Doctrine repositories (tasks & tasksInfos), keep in mind that The Entity Manager did more that only retrieve Doctrine Repositories.

When you need a doctrine repository within your helper, you would normally inject an entity manager and then retrieve your repository. However, you're not injecting the service you need, you're injecting a manager that helps you get what you need.

Another constraint (one may consider) is that a Doctrine repository can only be retrieved through an Entity Manager, so we don't have any control over its construction.

So, the only way to inject your repositories instead of depending on the Entity Manager is to consider using Factory services and methods to delegate the creation of services and then inject the relevant services.

I would then suggest,

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()
    {
        // ....
    }
}

While you service definition should looks like,

<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>

The advantages,

  • Your code is clean and more readable as the constructor of you your service is more specific about its real needs.
  • Testability, Instead of creating a mock for both the entity manager and the repositories, you only have to mock your repositories.
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top