2010-09-11 13 views
14

Empezando a trabajar con Doctrine2, y me pregunto cómo y si puedo usar una clase de colección personalizada. Búsquedas me apuntan a this part of the documentation:Colección personalizada en Doctrine2

campos y propiedades persistentes Colección de valor deben ser definidas en términos de la interfaz Doctrine\Common\Collections\Collection. El tipo de implementación de la colección puede ser utilizado por la aplicación para inicializar campos o propiedades antes de que la entidad sea persistente. Una vez que la entidad se gestiona (o se separa), el acceso posterior debe realizarse a través del tipo de interfaz.

Si bien estoy seguro de que es claro para alguien, estoy un poco confuso.

Si configuro mi Entidad para inicializar (por ejemplo, en __construct()) la variable de recopilación para una clase que implementa la interfaz correcta, ¿continuará Doctrine2 utilizando esa clase como colección? ¿Lo estoy entendiendo correctamente?

Actualización: Además, de varios subprocesos deduzco que el objeto de marcador de posición utilizado en la carga diferida puede influir en cómo se puede usar una colección personalizada.

+1

Para aquellos que vinieron aquí tratando de encontrar una respuesta: Hasta el momento, la [función] (https://github.com/doctrine/doctrine2/issues/5057) aún no está implementada, por favor contribuya en el hilo de discusión de la función (votaciones ascendentes, casos de uso, sus soluciones). – Arkemlar

Respuesta

18

Déjame intentar aclarar lo que es posible, no es posible y lo planeado con ejemplos.

La cita del Manual básicamente significa que podría tener el siguiente tipo de implementación personalizada:

use Doctrine\Common\Collections\Collection; 

// MyCollection is the "implementation type" 
class MyCollection implements Collection { 
    // ... interface implementation 

    // This is not on the Collection interface 
    public function myCustomMethod() { ... } 
} 

Ahora se podría utilizar de la siguiente manera:

class MyEntity { 
    private $items; 
    public function __construct() { 
     $this->items = new MyCollection; 
    } 
    // ... accessors/mutators ... 
} 

$e = new MyEntity; 
$e->getItems()->add(new Item); 
$e->getItems()->add(new Item); 
$e->getItems()->myCustomMethod(); // calling method on implementation type 

// $em instanceof EntityManager 
$em->persist($e); 

// from now on $e->getItems() may only be used through the interface type 

En otras palabras, siempre y cuando una La entidad es NUEVA (no administrada, separada o eliminada). Usted es libre de utilizar el tipo concreto de implementación de colecciones, incluso si no es bonita. Si no es NUEVO, debe acceder solo al tipo de interfaz (e idealmente escriba-sugerencia sobre él). Eso significa que el tipo de implementación realmente no importa. Cuando una instancia persistente de MyEntity se recupera de la base de datos, no usará una MyCollection (los constructores no son invocados por Doctrine, nunca, ya que Doctrine solo reconstituye objetos ya existentes/persistentes, nunca crea "nuevos"). Y dado que dicha entidad está ADMINISTRADA, el acceso debe realizarse de todos modos a través del tipo de interfaz.

Ahora a lo que está previsto. La forma más hermosa de tener colecciones personalizadas es tener también un tipo de interfaz personalizada, digamos IMyCollection y MyCollection como el tipo de implementación.Entonces, para que funcione a la perfección con los servicios de persistencia Doctrina 2 que se necesita para implementar una aplicación PersistentCollection personalizada, por ejemplo, MyPersistentCollection que se parece a esto:

class MyPersistentCollection implements IMyCollection { 
    // ... 
} 

continuación te contarían Doctrina en el mapeo a utilizar el MyPersistentCollection contenedor para esa colección (recuerde, una PersistentCollection envuelve un tipo de implementación de colección, implementando la misma interfaz, para que pueda hacer todo el trabajo de persistencia antes/después de delegar en el tipo de implementación de la colección subyacente).

Así que una aplicación de colección personalizada consistiría en 3 partes:

  1. Tipo de interfaz
  2. tipo de implementación (implementa tipo de interfaz)
  3. persistente tipo de envoltorio (implementa tipo de interfaz)

Esto no solo hará posible la escritura de colecciones personalizadas que funcionen sin problemas con Doctrine 2 ORM, sino también para escribir solo un tipo de contenedor persistente personalizado, para e ejemplo para optimizar el comportamiento de carga lenta/inicialización de una colección particular a las necesidades específicas de la aplicación.

Todavía no es posible hacer esto, pero lo será. Esta es la única manera realmente elegante y totalmente funcional para escribir y utilizar colecciones completamente personalizadas que se integran perfectamente en el esquema de persistencia transparente proporcionada por Doctrina 2.

+0

Gran detalle aquí y muy bien explicado. Clarificó la documentación mucho para mí. – cantera

+0

Hola, ahora han pasado 2 años desde que escribiste que "está planeado", pero como veo, todavía no lo está. ¿Tiene alguna idea de cuándo se podría implementar esta característica? – grongor

+0

+1 preguntándose si/esperando que esto se haya hecho. Estoy en Doctrine 2.3 pero no veo ninguna indicación de que este enfoque haya sido habilitado. –

0

No, siempre que Doctrine le devuelva una implementación de la interfaz Doctrine \ Common \ Collections \ Collection, será una instancia de Doctrine \ ORM \ PersistentCollection. No puede poner más lógica personalizada en la colección. Sin embargo, eso ni siquiera es necesario.

Digamos que tiene una entidad (la orden tiene muchos artículos de pedido), entonces no debe ubicarse un método para calcular la suma total de la orden en la colección, sino en el artículo de la orden. Ya que es el lugar en el que la suma tiene sentido en el modelo de dominio:

class Order 
{ 
    private $items; 

    public function getTotalSum() 
    { 
     $total = 0; 
     foreach ($this->items AS $item) { 
      $total += $item->getSum(); 
     } 
     return $total; 
    } 
} 

Colecciones sin embargo, son sólo algunas partes técnicas del ORM, ayudan a implementar y gestionar las referencias entre objetos, nada más.

+0

Mi idea principal fue proporcionar orden/clasificación/filtrado, no ejecutar cálculos en las entidades. –

+0

Incluso los métodos de clasificación/filtrado son mejores para las entidades que tienen la colección. Sin embargo, también hay métodos que aceptan cierres y hacen el trabajo por usted, por ejemplo: $ collection-> map (function ($ element) {return $ element-> getProperty();}); – beberlei

+0

@beberlei Pero si varias entidades tienen la misma colección, terminas duplicando el código (a menos que uses funciones anónimas). –

0

La misma pregunta here, con una referencia a la página official doctrine Jira issue con los detalles y la situación de esta 'característica' ... ¡Puede realizar un seguimiento del desarrollo allí!

Cuestiones relacionadas