Doctrinebundle: [Question] Is there a reason why the bundle doesn't register repositories as services?

Created on 16 May 2017  路  20Comments  路  Source: doctrine/DoctrineBundle

I've looked through the issues and documentation, couldn't find any reference to it, but seeing people are looking for it or doing it in a hackish kind of way: is there a reason why the bundle doesn't register repositories as services?

I see it's quite common and handy to auto-register configured / local resources (for example, GaufretteBundle or Symfony Workflow component).

Most helpful comment

Defining repositories as services is a very bad idea due to the way Doctrine ORM works.
When resetting the entity manager, all repositories must be recreated (to have repositories linked to the new entity manager instance). If you define repositories as services, the service will keep referencing the old instance, leading to very hard to debug bugs in your project.

So I definitely won't implement this in DoctrineBundle itself

All 20 comments

Defining repositories as services is a very bad idea due to the way Doctrine ORM works.
When resetting the entity manager, all repositories must be recreated (to have repositories linked to the new entity manager instance). If you define repositories as services, the service will keep referencing the old instance, leading to very hard to debug bugs in your project.

So I definitely won't implement this in DoctrineBundle itself

@stof great, that's the info I was looking for.

So the preferred way to get a repository into your service is by injecting the entity manager and asking for it?

@stof maybe it's better not to reset entity manager?

@vatson if you get an database error during a flush your entity manager is in an unusable state and doctrine prevents you from using it, the only solution in this case is to reset it.

@jvasseur if it's normal to continue working after you get an error. Generally this is an unpleasant situation that entails a lot of tricky solutions. All this leads to more confusion. It is necessary to choose the lesser of two evils

@vatson But it's probably a good idea to let the developer make this decision based on their project and not force them into one direction.

@craigh That post is 3 years old at this time. Here, have a newer one: https://blog.fervo.se/blog/2017/07/06/doctrine-repositories-autowiring/

about that fervo thing, couldn't that UserRepository from the blog implement "ObjectRepository, Selectable" and you wouldn't notice a difference?

Maybe @magnusnordlander can answer your question, but in theory I'd say you could do that.

@vatson a very good use case to reset the entity manager to keep working is when writing a queue consumer. If there is an issue processing of one the message, you want to be able to recover the entity manager to be able to process next ones. Having to kill your consumer process on each failure is not good.
Removing the need to re-instantiate the entity manager on failure requires changing the architecture of the ORM, and this will not happen anytime soon (rewriting the ORM would be a huge work, and the ORM maintainers don't have resources to do that currently)

@alcaeus - 3 years isn't that long. And "old" doesn't mean wrong or bad. Doctrine 2 hasn't changed too dramatically since that time. I've found @matthiasnoback 's work to be really good.

@alcaeus: He certainly can :)

@Hanmac: You could, yes. That would probably make for a smoother transition if you're already using custom repositories. What you shouldn't do is extend EntityRepository, and what you can't do is have them mapped as the repositoryClass in the entity mapping.

This also means that if your code is doing something like $container->get('doctrine')->getRepositoryForClass('App:SomeEntity') you're going to have to change that.

@craigh: @matthiasnoback is great, and yes, the article is still factually correct, in fact he mentions this very issue under Something to be aware of: resetting closed entity managers. We just disagree in whether this issue means that you should always inject the ManagerRegistry rather than the EntityManager (I think so, he seems to not think so).

@magnusnordlander as of Symfony 3.3, you can reset the entity manager while injecting it directly, as it know uses a lazy service and resets the internal object of the entity manager proxy.
However, you still have the same limitation than before for any other object instantiated by the EM (repositories, the UnitOfWork, and other internal Doctrine objects). If you store them in a property of your object graph instead of getting them from the EntityManager each time, you will keep using the old object.

@stof so to repeat the question:

the preferred way to get a repository into your service is by injecting the entity manager and asking for it?

if you actually need the doctrine repository (the one returned by $em->getRepository()), yes. This is even the only way which is officially supported (defining repositories as services is doable on your side, but you are on your own for issues you face due to this)

Just for the record, my preferred of working with repos is to define an
interface and a Doctrine specific implementation, which gets the registry
injected. Solves all issues (including the previously unknown auto-wiring
one), and leads to a better design (imo of course).

I just wanted to share a recent blogpost on that topic that follows @matthiasnoback 's approach:

https://www.tomasvotruba.cz/blog/2017/10/16/how-to-use-repository-with-doctrine-as-service-in-symfony/

This can be closed. As of DoctrineBundle 1.8, you can use a new base class + Symfony's auto-registration to wire your repositories automatically as services.

@weaverryan Is there any documentation about how to do that?

Do you mean the Doctrine\Common\Persistence\ObjectRepository registered by the fqcn of the repository?

Was this page helpful?
0 / 5 - 0 ratings