php - symfony2 - generate entities symfony 4
Symfony 2.8: Doctrine getManagerForClass() no devuelve el administrador de entidad correcto (1)
Por fin, lo resolví. La solución estaba usando el parámetro de 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
Explicación
El parámetro de prefix
se pasa al servicio correspondiente de Entity Manager, y se agrega a la propiedad entityNamespaces
, que de lo contrario AppBundle/Entity
a ser AppBundle/Entity
. El Controlador de Anotación verificará las anotaciones en ese espacio de nombres específico , mientras que el Controlador de Archivos verifica los archivos de mapeo existentes en el directorio especificado a través del parámetro dir
. (El parámetro de alias
no es obligatorio).
Al menos, así es como lo entiendo.
tl; dr ¿Cómo el método getManagerForClass()
descubre qué administrador de entidades es el correcto para una clase específica?
Creé un controlador genérico que debería poder manejar acciones básicas para diferentes entidades. También tengo conexiones con dos bases de datos diferentes, así que estoy usando dos administradores de entidades.
En mi controlador, estoy tratando de usar el método getManagerForClass () de Doctrine para encontrar qué administrador usar para cada clase, como se explica en este blog y esta respuesta SO .
Pero el método no parece diferenciar a mis dos administradores de entidades y simplemente devuelve el primero en la configuración.
Mi acción de controlador comienza así:
public function indexAction($namespace, $entityName)
{
$classFullName = "AppBundle:$namespace//$entityName";
$em = $this->getDoctrine()->getManagerForClass($classFullName);
Esta es mi configuración de Doctrine:
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
Y mi estructura de carpetas es la siguiente:
AppBundle
|___Controller
| |___EntityController.php
|
|___Entity
|___Postgres
| |___SomePostgresBasedEntity.php
|
|___Oracle
|___SomeOracleBasedEntity.php
Ahora no sé exactamente cómo funciona el método, y cómo se supone que debe saber sobre el mapeo si no a través de la configuración. Pero si lo llamo de esta manera, por ejemplo:
$em = $this->getDoctrine()->getManagerForClass("AppBundle:Oracle//SomeOracleBasedEntity");
... obtengo el administrador de la entidad para Postgres.
Pero si simplemente cambio la configuración del administrador de entidades, poniendo primero la de oráculo, la llamada anterior funciona, pero la siguiente no:
$em = $this->getDoctrine()->getManagerForClass("AppBundle:Postgres//SomePostgresBasedEntity");
Actualización 1
getManagerForClass()
recorre cada administrador y para cada uno, comprueba si la clase es "no transitoria":
foreach ($this->managers as $id) {
$manager = $this->getService($id);
if (!$manager->getMetadataFactory()->isTransient($class)) {
return $manager;
}
}
Esto llega hasta AnnotationDriver->isTransient()
. Aquí el doc dice lo siguiente:
Una clase no es transitoria si está anotada con una anotación de AnnotationDriver :: entityAnnotationClasses.
@Entity
parece ser una de esas anotaciones que hace que una clase no sea transitoria. Pero entonces, ¿cómo podría alguna de mis entidades ser transitoria? ¿Cómo podría el conductor distinguir una entidad que pertenece a un administrador específico basándose únicamente en sus anotaciones? Debo haberme perdido algo en las clases de nivel superior.
Actualización 2
El método funciona cuando se utilizan asignaciones de yml
.
Esperaba este comportamiento. La diferencia proviene de las implementaciones del método isTransient () en los diferentes controladores. La implementación FileDriver de isTransient devuelve true
si el archivo de metadatos existe en el directorio dir:
de la configuración de asignación.
Hubiera esperado que AnnotationDriver buscara anotaciones solo en las entidades contenidas en el directorio dir:
especificado, pero parece ignorar ese parámetro. ¿O debería usar otro?