Symfony 2.8: Doctrine getManagerForClass () does not return the correct Entity Manager
tl; dr How does a method getManagerForClass()
find out which object manager is the correct one for a particular class?
I created a generic controller that should be able to handle basic actions for different objects. I also have connections to two different databases, so I am using two entity managers.
In my controller, I'm trying to use Doctrine's getManagerForClass () method to find which manager to use for each class, as described in this blog post and this SO answer .
But the method doesn't seem to distinguish between my two entity managers and just returns the first one in the config.
My controller actions start like this:
public function indexAction($namespace, $entityName)
{
$classFullName = "AppBundle:$namespace\\$entityName";
$em = $this->getDoctrine()->getManagerForClass($classFullName);
This is my Doctrine config:
dbal:
default_connection: postgres
connections:
postgres:
driver: pdo_pgsql
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
oracle:
driver: oci8
host: "%oracle_host%"
port: "%oracle_port%"
dbname: "%oracle_name%"
user: "%oracle_user%"
password: "%oracle_password%"
charset: UTF8
orm:
auto_generate_proxy_classes: true
entity_managers:
postgres:
connection: postgres
mappings:
AppBundle:
type: annotation
dir: Entity\Postgres
oracle:
connection: oracle
mappings:
AppBundle:
type: annotation
dir: Entity\Oracle
And my folder structure looks like this:
AppBundle
|___Controller
| |___EntityController.php
|
|___Entity
|___Postgres
| |___SomePostgresBasedEntity.php
|
|___Oracle
|___SomeOracleBasedEntity.php
Now I don't know exactly how this method works, and how it is supposed to know about mapping, if not via configuration. But if I call it that, for example:
$em = $this->getDoctrine()->getManagerForClass("AppBundle:Oracle\\SomeOracleBasedEntity");
... I am getting an Object Manager for Postgres.
But if I just switch the entity manager config by putting one for oracle first, the previous call works, but the following:
$em = $this->getDoctrine()->getManagerForClass("AppBundle:Postgres\\SomePostgresBasedEntity");
Update 1
getManagerForClass()
Loops through each manager and, for each of them, checks if the class is "continuous":
foreach ($this->managers as $id) {
$manager = $this->getService($id);
if (!$manager->getMetadataFactory()->isTransient($class)) {
return $manager;
}
}
It comes down to AnnotationDriver->isTransient()
. Here the doc says the following:
A class is not transient if it is annotated with annotation from AnnotationDriver :: entityAnnotationClasses.
@Entity
seems to be one of those annotations that makes a class non-transient. But then, how can any of my essences be transient at all? How can a driver distinguish an entity belonging to a particular manager based solely on their annotations? I must have missed something in the higher level classes.
Update 2
The method works when using yml
mappings.
I expected this behavior. The difference comes from the implementations of the isTransient () method in different drivers. The isTransient FileDriver implementation returns true
if the metadata file exists in dir:
the display configuration directory .
I would expect AnnotationDriver to only look for annotations on objects contained in the specified directory dir:
, but seems to ignore this setting. Or should I use another one?
Finally I have decided. The solution used a parameter prefix
.
entity_managers:
postgres:
connection: postgres
mappings:
AppBundle:
type: annotation
dir: Entity\Postgres
prefix: AppBundle\Entity\Postgres
alias: Postgres
oracle:
connection: oracle
mappings:
AppBundle:
type: annotation
dir: Entity\Oracle
prefix: AppBundle\Entity\Oracle
alias: Oracle
Explanation
The parameter prefix
is passed to the appropriate Entity Manager service and added to the property entityNamespaces
, which has a default value AppBundle/Entity
. The annotation driver then checks the annotations in that particular namespace, while the File Driver checks for existing mapping files in the directory specified by the parameter dir
. (This parameter alias
is optional.)
At least as I understand it.