tutorial example español php doctrine2 doctrine

example - install doctrine php



En Doctrine, cómo lograr funcionalidades de modelo adicionales para Entity (4)

Digamos que tengo una entidad de Doctrine (versión 2) de la siguiente manera:

<?php namespace AppBundle/Entity; use Doctrine/ORM/Mapping as ORM; /** * User * * @ORM/Table(name="users") * @ORM/Entity */ class User { /** * @var integer * * @ORM/Column(name="id", type="integer") * @ORM/Id * @ORM/GeneratedValue(strategy="IDENTITY") */ private $id /** * @var string * * @ORM/Column(name="name", type="string", length=50, nullable=false) */ private $name; /** * @var string * * @ORM/Column(name="group_id", type="string", length=6, nullable=true) */ private $groupId; // Getters and setters... }

Ahora, me gustaría gestionar la relación del User con el Group , pero con algunas condiciones, como:

  1. devolver NULL (o algún tipo de esqueleto / plantilla de /AppBundle/Entity/Group con valores fijos no cargados desde la base de datos) si el Group of users.group_id no existe, incluso si está establecido en un valor (sin restricciones de clave establecidas en el base de datos para evitar este comportamiento), por lo que se requiere algún tipo de validación / verificación
  2. Group carga diferida, al llamar $user->getGroup()

Estoy leyendo Google una y otra vez y estoy confundido de cómo lograrlo correctamente (en la línea con Doctrine / Symfony).

Podría agregar ManyToOne a la relación de clase de la entidad de esta manera:

/** * @var /AppBundle/Entity/Group * * @ORM/ManyToOne(targetEntity="AppBundle/Entity/Group") * @ORM/JoinColumns({ * @ORM/JoinColumn(name="group_id", referencedColumnName="id") * }) */ private $group;

Pero, ¿cómo evitar excepciones causadas por claves externas inexistentes? Es decir, me gustaría recuperar los detalles del grupo del usuario cuando esté disponible en mi base de datos, pero cuando no lo esté no quiero que Doctrine arroje una excepción y cierre mi aplicación.

La gente dice que usar un Administrador de Entidades dentro de una Entity es una muy mala práctica y estoy de acuerdo. Pero estoy confundido sobre el uso de Proxy Objects o Inheritance Mapping para este propósito.

Parece que utilizar Models podría ser el camino, pero no pude encontrar ninguna documentación sólida sobre cómo implementarlos correctamente en Doctrine2 .

Por favor ayuda si puedes. En Kohana era tan, tan simple (pero inmaduro de esta manera).

EDITAR:

@Massimiliano Fedel sugirió tratar de detectar una excepción en el método User::getGroup() , para eventualmente hacer que los grupos no existentes regresen como NULL .

Así que he comprometido este código:

/** * Get group * * @return /AppBundle/Entity/Group */ public function getGroup() { try { $group = $this->group; } catch (/Doctrine/ORM/EntityNotFoundException $e) { $group = null; } return $group; }

Desafortunadamente, parece que la excepción no se puede atrapar de esta manera, porque el marco sale con una Doctrine/ORM/EntityNotFoundException :

Entity of type ''AppBundle/Entity/Group'' for IDs id(999) was not found

EDICION 2:

A continuación puede encontrar algunos esquemas básicos de Flujo de User , es decir, por qué no puedo asegurar que todos los Users tengan Groups disponibles en mi base de datos. http://oi64.tinypic.com/1sfno5.jpg


1) ¿Has intentado capturar la excepción dentro del método getter del "grupo"? para que pueda detectar la excepción y devolver "nulo" en caso de que ocurra una excepción.

2) a partir de la documentación de la doctrina 2.1: "Las asociaciones se marcan como Lazy de forma predeterminada, lo que significa que el objeto de colección completo para una asociación se rellena la primera vez que se accede a él". http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/tutorials/extra-lazy-associations.html


Bien, ¿qué hay de crear un servicio que envuelva sus operaciones CRUD en la entidad User , digamos UserService ? De esta forma, puede dejar group_id tal como está y agregar un campo de group que no se administre (sin anotaciones, no persistió en DB).

El UserService tendrá el método getGroup , que tomará User como argumento, luego recuperará su group_id y usará EntityManager (o de hecho GroupService ) para recuperar la entidad Group , si no se encuentra ninguno, devolverá null , de lo contrario, establecerá el Group devuelto al campo no administrado de la entidad, por lo que no tiene que volver a buscarla la próxima vez.


Bien, primero, su relación User - Group no está definida correctamente. Es absolutamente necesario agregar la relación ManyToOne :

/** * @var /AppBundle/Entity/Group * * @ORM/ManyToOne(targetEntity="AppBundle/Entity/Group") * @ORM/JoinColumns({ * @ORM/JoinColumn(name="group_id", referencedColumnName="id") * }) */ private $group;

Algunas palabras sobre esto. En la cláusula JoinColumns , de forma predeterminada, la relación es anulable, lo que significa que puede tener NULL lugar de la clave foránea en la columna group_id resultante (la columna de combinación que Doctrine creará para usted).

Si desea tener una relación que no admite nulos, la definición debe ser así:

/** * @var /AppBundle/Entity/Group * * @ORM/ManyToOne(targetEntity="AppBundle/Entity/Group") * @ORM/JoinColumns({ * @ORM/JoinColumn(name="group_id", referencedColumnName="id", nullable=false) * }) */ private $group;

Por lo tanto, de forma predeterminada, puede tener un grupo NULL para un User . Una vez que esto esté definido correctamente, con respecto a sus preguntas:

1.

Si su aplicación se crea correctamente, nunca debe terminar con un User relacionado con un Group que aún no se haya comprometido con la base de datos. Cada Group que vincula a un User debe tomarse de Doctrine de alguna manera antes de persistir en el User . Ya sea desde la aplicación o desde un formulario. Si necesita validar que el Group existe antes de persistir en el User , debe resolver el problema en sentido ascendente, al estar 100% seguro de que cualquier Group que utilice se extrae de la base de datos.

En este contexto específico, setter de setGroup ya debe asegurarse de que lo que se proporciona es de hecho una entidad de Group (si no es así, debe agregar un typehint), y Doctrine ya asegura que esta entidad ya existe en la base de datos. Estoy de acuerdo en que los errores de Doctrine pueden ponerse feos, pero un producto entregado no debería incluir ninguno de todos modos.

Comprenda que la validación de Symfony generalmente se usa con formularios, con la intención de validar violaciones potenciales introducidas por el usuario final, no por el desarrollador (generalmente).

2.

Con una relación bien definida, como se muestra arriba, Doctrine se encargará de esto automáticamente. Por defecto, todas las relaciones de Doctrine se cargan de forma perezosa.

También:

/** * Get group * * @return /AppBundle/Entity/Group */ public function getGroup() { try { $group = $this->group; } catch (/Doctrine/ORM/EntityNotFoundException $e) { $group = null; } return $group; }

No necesitas hacer esto. Eliminarlo


Teniendo en cuenta su caso de uso específico, su mejor apuesta son los suscriptores del evento Doctrine .

Tenga cuidado ya que están separados de los suscriptores habituales del evento Symfony . Estos últimos están relacionados con el flujo de trabajo Symfony genérico y el primero es específico de Doctrine.

Específicamente, el evento postLoad es lo que necesita. La idea aquí es:

  1. Agregue una propiedad de group al User con el captador y colocador tipográfico correspondiente
  2. Cree un suscriptor personalizado de Doctrine, llamado MyBundle/Entity/EventSubscriber/UserSubscriber
  3. Inyectarlo con el servicio del administrador de entidades de Doctrine
  4. Crea el método postLoad así:

    public function postLoad(LifecycleEventArgs $args) { $user = $args->getEntity(); if ($user instanceof User && $user->getGroupId()) { $r = $this->em->getRepository(''MyBundle:Group''); $group = $r->find($user->getGroupId()); if ($group instanceof Group) { $user->setGroup($group); } // If not an instance of Group, no group can be found: do nothing and leave it NULL } }

El método postLoad se postLoad siempre que se carga una entidad Doctrine desde el administrador, lo que significa que todas las entidades encontradas a través de Doctrine se completarán con su grupo cuando sea posible.

Si quieres cargar lazy ... primero, ¿estás seguro de que quieres esto? User grupos de User generalmente se usan en la mayoría de las páginas de las aplicaciones de Symfony, por ejemplo, en verificaciones de autorización. Si los grupos se cargan en cada página, realmente no vale la pena.

Si realmente lo necesita, puede usar el servicio Doctrine proxy factory y rellenar su User con un proxy en lugar de una entidad real (no estoy seguro de cómo funciona esto exactamente):

$group = $this->em->getProxyFactory()->getProxy(''MyBundle:Group'', $user->getGroupId()); $user->setGroup($group);

En ese caso, deberá mantener lo siguiente porque algunos intentos de carga fallarán si el ID no existe:

/** * Get group * * @return /AppBundle/Entity/Group */ public function getGroup() { static $loaded = false; if (!$loaded) { try { $this->group; } catch (/Doctrine/ORM/EntityNotFoundException $e) { $this->group = null; } $loaded = true; } return $this->group; }

Ajusté el código original de Jan Mares ya que en cada llamada de getGroup() Doctrine habría intentado cargar el Group .