Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting dependency into entity repository

Is there a simple way to inject a dependency into every repository instance in Doctrine2 ?

I have tried listening to the loadClassMetadata event and using setter injection on the repository but this naturally resulted in a infinite loop as calling getRepository in the event triggered the same event.

After taking a look at the Doctrine\ORM\EntityManager::getRepository method it seems like repositories are not using dependency injection at all, instead they are instantiated at the function level:

public function getRepository($entityName) {     $entityName = ltrim($entityName, '\\');     if (isset($this->repositories[$entityName])) {         return $this->repositories[$entityName];     }      $metadata = $this->getClassMetadata($entityName);     $customRepositoryClassName = $metadata->customRepositoryClassName;      if ($customRepositoryClassName !== null) {         $repository = new $customRepositoryClassName($this, $metadata);     } else {         $repository = new EntityRepository($this, $metadata);     }      $this->repositories[$entityName] = $repository;      return $repository; } 

Any ideas ?

like image 767
Hubert Perron Avatar asked Nov 16 '11 14:11

Hubert Perron


People also ask

How do you inject Dbcontext into repository?

You can define a RepositoryConnection class in App. Data that acts as a wrapper to the Context and removes the need to reference EF in App. Web . If you are using an IoC Container you can control the lifetime of the RepositoryConnection class to ensure that all instances of Repository get the same Context.

How do you inject a dependency?

The injector class injects dependencies broadly in three ways: through a constructor, through a property, or through a method. Constructor Injection: In the constructor injection, the injector supplies the service (dependency) through the client class constructor.

What is dependency injection C# with example?

Using dependency injection, we can pass an instance of class C to class B, and pass an instance of B to class A, instead of having these classes to construct the instances of B and C. In the example, below, class Runner has a dependency on the class Logger.


2 Answers

Problem is that repository classes are not part of the Symfony2 codebase as they are part of Doctrine2, so they do not take advantage of the DIC; this is why you can't go for injection in one place for all repositories.

I would advice you to use a different approach. For example you can create a service layer on top of the repositories and actually inject the class you want through a factory in that layer.

Otherwise you could also define repositories as services this way:

<service id="your_namespace.repository.repos_name"           class="%your_namespace.repository.repos_name%"           factory-service="doctrine" factory-method="getRepository">   <argument>entity_name</argument>   <argument>entity_manager_name</argument>   <call method="yourSetter">       <argument>your_argument</argument>   </call> </service> 

A solution that could centralize the set method call is to write a DIC tag and a compiler pass to handle it and tag all repository services.

like image 137
Aldo Stracquadanio Avatar answered Sep 24 '22 13:09

Aldo Stracquadanio


This is a YAML version of Aldo's answer, just in case you are using YAML configurations instead of XML

your_namespace.repository.repos_name:     class: %your_namespace.repository.repos_name%     factory: ["@doctrine", getRepository]     arguments:         - entity_name         - entity_manager_name     calls:         - [setContainer, ["@service_container"]] 

And prior to version 2.8:

your_namespace.repository.repos_name:     class: %your_namespace.repository.repos_name%     factory_service: doctrine     factory_method: getRepository     arguments:         - entity_name         - entity_manager_name     calls:         - [setContainer, [@service_container]] 

Also, as a note, entity_manager_name is an optional parameter. I want the default for my particular use, so I just left it blank (just in case I ever rename the default manager).

like image 34
samanime Avatar answered Sep 23 '22 13:09

samanime