How to get the EntityManager in Symfony 3, correctly?
Doctrine has a two types of Data Mappers: the ORM for the RDBMS and the ODM for document-oriented DBs (mostly for MongoDB). Data mappers try to achieve in a sort of persistence-ignorance and both of them implements a generic interfaces defined in the Doctrine\Common
, such as ObjectManager
or ObjectRepository
.
In the Symfony the getDoctrine()
method returns an instance of Registry
class from the DoctrineBundle
(by default). In short this service holds all available connections and entity managers. His method getManager()
implemented in the Doctrine\Common
, it don't knows what type of data mapper and declares return type as generic ObjectManager
.
To avoid IDE warnings you can explicitly define the inline PHPDoc. Netbeans and PHPStorm are support it.
/* @var $entityManager Doctrine\ORM\EntityManager */
$entityManager = $this->getDoctrine()->getManager();
Other solution is a simple helper method:
public function getEntityManager(): EntityManager
{
return $this->getDoctrine()->getManager();
}
With above solutions we assume that requested service is actually from the ORM, so is a sort of type downcasting: actual class will be checked only in runtime. For the type-safety you can directly inject the entity manager in the your service.
cg.
Updated on June 08, 2022Comments
-
cg. almost 2 years
I am using current versions of Symfony (3.2.3) and Doctrine ORM (2.5.6) and I'm still trying to wrap my head around how to handle the deprecation of
getEntityManager()
and related methods correctly.For instance, the current documentation states that this is the way to create a query builder instance:
$repository = $this->getDoctrine()->getRepository('AppBundle:Product'); $queryBuilder = $repository->createQueryBuilder('p')
But the way I see it (and my IDE seems to agree),
getRepository()
is type hinted to return an instance ofObjectRepository
and the methodcreateQueryBuilder()
is not declared in that interface but in the implementing classEntityRepository
.An other example would be explicitly starting a transaction in a controller:
$this->getDoctrine()->getEntityManager()->getConnection()->beginTransaction()
I'm supposed to call
getManager()
instead ofgetEntityManager()
because the latter method is deprecated. ButgetManager()
is type hinted to return an instance ofObjectManager
which does not declaregetConnection()
.PHP being PHP the code still seems to be working in all cases, but my IDE and I are left with an uneasy feeling. So, what is the correct way to create a query builder or begin a transaction in Symfony 3? Am I missing something?
-
cg. about 7 yearsSorry if I'm nitpicking but after all that is what my question is about: I don't need to try this, I know it is working and that's not my point. What I want is clean code without having to brace every call to getManager() with "instanceof"...
-
cg. about 7 yearsGood explanation and hints to possible solutions, thanks! I'll wait a little longer, but if no one comes up with anything better I'll accept your answer.
-
cg. about 7 yearsMy problem is not my IDE but type safety, clean code and honoring the contracts offered by the Doctrine interfaces.
-
Vinicius Dias about 7 yearsIn a staticly typed language the solution would be type casting, which in this case isn't possible with PHP. The method getRepository is actually returning a ProductRepository instance, isn't it? So you are honoring the contract.
-
cg. about 7 yearsNo, there might not even be a class called ProductRepository. All I can actually expect is an instance of ObjectRepository that is registered for the given entity type.