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 ?
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.
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.
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.
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.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With