2010-09-11 6 views
14

Appena iniziato a lavorare con Doctrine2, mi chiedo come/se posso usare una classe di raccolta personalizzata. Ricerche punto me this part of the documentation:Raccolta personalizzata in Doctrine2

campi e proprietà persistenti Collection valori devono essere definiti in termini di interfaccia Doctrine\Common\Collections\Collection. Il tipo di implementazione della raccolta può essere utilizzato dall'applicazione per inizializzare campi o proprietà prima che l'entità sia resa persistente. Una volta che l'entità viene gestita (o stacca), l'accesso successivo deve avvenire attraverso il tipo di interfaccia.

Mentre sono sicuro che è chiaro per qualcuno, sono un po 'confuso.

Se configuro la mia Entità per inizializzare (diciamo in __construct()) la variabile di raccolta in una classe che implementa l'interfaccia corretta, Doctrine2 continuerà a usare quella classe come raccolta? Lo capisco correttamente?

Aggiornamento: Inoltre, raccolgo da vari thread che l'oggetto segnaposto utilizzato nel caricamento lento può influenzare il modo in cui una raccolta personalizzata può essere utilizzata.

+1

Per coloro che sono venuti qui cercando di trovare una risposta: Per ora, la [funzione] (https://github.com/doctrine/doctrine2/issues/5057) non è ancora implementata, si prega di contribuire in discussione discussione funzione (upvotes, use case, le tue soluzioni). – Arkemlar

risposta

18

Lasciatemi provare a chiarire cosa è possibile, non possibile e pianificato con esempi.

La citazione dal manuale significa sostanzialmente si potrebbe avere il seguente tipo di implementazione personalizzata:

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() { ... } 
} 

Ora si potrebbe usare come segue:

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 

In altre parole, fino a quando un l'entità è NUOVA (non GESTITA, STACCATA o RIMOSSA) sei libero di utilizzare il tipo concreto di implementazione delle collezioni, anche se non è carina. Se non è NUOVO, è necessario accedere solo al tipo di interfaccia (e idealmente digitare suggerimenti su di esso). Ciò significa che il tipo di implementazione non ha molta importanza. Quando un'istanza MyEntity persistente viene recuperata dal database, non utilizzerà MyCollection (i costruttori non vengono invocati da Doctrine, sempre, dal momento che Doctrine ricostituisce solo oggetti esistenti/persistenti, non crea mai "nuovi"). E poiché tale entità è GESTITA, l'accesso deve comunque avvenire tramite il tipo di interfaccia.

Ora a quanto pianificato. Il modo più bello per avere collezioni personalizzate è anche avere un tipo di interfaccia personalizzata, ad esempio IMyCollection e MyCollection come tipo di implementazione.Poi, per farlo funzionare perfettamente con i servizi di persistenza Doctrine 2 si avrebbe bisogno di implementare un'implementazione PersistentCollection personalizzato, ad esempio, MyPersistentCollection che assomiglia a questo:

class MyPersistentCollection implements IMyCollection { 
    // ... 
} 

allora si sarebbe dire Dottrina nella mappatura di utilizzare il MyPersistentCollection wrapper per quella raccolta (ricorda, una PersistentCollection esegue il wrapping un tipo di implementazione di raccolta, implementando la stessa interfaccia, in modo che possa eseguire tutto il lavoro di persistenza prima/dopo la delega al tipo di implementazione della raccolta sottostante).

Quindi un'implementazione raccolta personalizzata sarebbe costituito da 3 parti:

  1. Tipo interfaccia
  2. tipo di implementazione (implementa tipo di interfaccia)
  3. tipo di involucro persistente (implementa tipo di interfaccia)

Ciò non solo consentirà di scrivere raccolte personalizzate che funzionano in modo incoerente con Doctrine 2 ORM ma anche di scrivere solo un tipo di wrapper persistente personalizzato, per e xample per ottimizzare il comportamento di caricamento lento/inizializzazione di una particolare raccolta in base alle esigenze specifiche dell'applicazione.

Non è ancora possibile farlo ma lo sarà. Questo è l'unico modo veramente elegante e completamente funzionale per scrivere e utilizzare le collezioni completamente personalizzate che si integrano perfettamente nello schema di persistenza trasparente fornita da Doctrine 2.

+0

Ottimo dettaglio qui e molto ben spiegato. Chiarito molto la documentazione per me. – cantera

+0

Ciao, ora sono passati 2 anni dal momento in cui hai scritto che "è programmato" ma, come vedo, non lo è ancora. Hai qualche idea su quando questa funzionalità potrebbe essere implementata? – grongor

+0

+1 chiedendosi se/sperando che ciò sia stato fatto. Sono su Doctrine 2.3 ma non vedo alcuna indicazione che questo approccio sia stato abilitato. –

0

No, ogni volta che Doctrine restituisce un'implementazione dell'interfaccia Doctrine \ Common \ Collections \ Collection, sarà un'istanza Doctrine \ ORM \ PersistentCollection. Non è possibile aggiungere più logica personalizzata alla raccolta. Tuttavia non è nemmeno necessario.

Supponiamo che tu abbia un'entità (l'ordine ha molti ordini), quindi un metodo per calcolare la somma totale dell'ordine non deve essere collocato sulla raccolta, ma sulla voce ordine. Dal momento che è la posizione in cui la somma ha un senso nel modello di dominio:

class Order 
{ 
    private $items; 

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

Collezioni, tuttavia, sono solo parti tecniche del ORM, aiutano a implementare e gestire i riferimenti tra gli oggetti, niente di più.

+0

Il mio pensiero principale era di fornire ordine/ordinamento/filtro, non eseguire calcoli sulle entità. –

+0

Anche i metodi di ordinamento/filtro sono meglio posizionati sulle entità che detengono la raccolta. Tuttavia ci sono anche metodi che accettano chiusure e fanno il lavoro per voi, ad esempio: $ collection-> map (function ($ element) {return $ element-> getProperty();}); – beberlei

+0

@beberlei Ma se più entità hanno la stessa collezione, si finisce con la duplicazione del codice (a meno che non si utilizzino funzioni anonime). –

0

Stessa domanda here, con un riferimento alla pagina official doctrine Jira issue con i dettagli e lo stato di questa 'caratteristica' ... Puoi tenere traccia dello sviluppo lì!