2013-08-07 8 views
15

SfondoUtilizzando gli strumenti CLI di Symfony 2, come posso generare getter e setter con l'hint di tipo corretto per le sottoclassi?

Sto sviluppando un'applicazione utilizzando Symfony 2 che è strutturato in modo tale che un fascio "Core" definisce entità, relazioni e campi. Altri bundle sono quindi in grado di specializzare la funzionalità di base per ereditarietà, i cosiddetti bundle "figlio".

Le annotazioni di Doctrine 2 sono state utilizzate per definire un'entità core denominata "Pacchetto". Un "pacchetto" collega insieme un progetto architettonico e un pezzo di terra, essenzialmente un pacchetto casa-terra. Ho ridisegnato gli esempi a una forma più semplice, quindi non troverete le definizioni per Land e ChildLand negli esempi seguenti, ma si può presumere che siano stati implementati in modo simile.

Aggiornamento

Secondo gli utenti sul canale #symfony di FreeNode, questo è un problema di dottrina come il comando app/console invoca semplicemente il console dottrina. Sto usando la dottrina 2.3.

Ecco un diagramma che mostra la situazione generale che causa il problema, che dovrebbe aiutare a visualizzare lo scenario:

(imgur link to full-size image) Type hinting contract breaking

Inoltre, ecco un link per un bug report sulle issue tracker di dottrina : http://www.doctrine-project.org/jira/browse/DDC-2605

Update 2 - più dettagliate ERD

Th La struttura delle relazioni tra entità è stata messa in discussione, quindi di seguito è riportato un esempio migliore della struttura dei dati che stiamo implementando.

Il requisito principale è di nuovo disporre di classi principali che forniscono un insieme condiviso di entità e campi. Le lezioni secondarie nei pacchetti di società estendono queste classi chiave.

Abbiamo considerato l'EAV a lungo, ma con questo approccio passeremo molto più tempo a creare una piattaforma e gli strumenti per gestire i dati EAV piuttosto che soddisfare i requisiti aziendali attuali, non saremo in grado di utilizzare la dottrina per gestire le entità come saranno definite nel database, ecc.

Con il passare del tempo e giungendo a comprendere meglio questo problema, sembra che l'unico problema sia con i getter e i setter generati dallo strumento CLI di doctrine che si interrompe i contratti tipo di suggerimento come indicato di seguito. Questa struttura funziona perfettamente quando questi problemi vengono corretti manualmente.

(imgur link to full-size image) Detailed data structure

Generazione Entità con CLI Tool

Così, inizialmente ho usato lo strumento da riga di comando ...

> app/console doctrine:generate:entity 

...per generare gli stub entità con mappature dei campi di base, poi ha aggiunto manualmente il rapporto alla terra (come lo strumento non sembra supportare i rapporti):

Questo è il codice risultante:

nucleo entità pacchetto: http://pastebin.com/3ujPT1mJ

bambino entità pacchetto: http://pastebin.com/sjAB0XJ2

Generare getter e setter

Avanti, genero i getter e setter eseguendo:

> app/console doctrine:generate:entities CompanyCoreBundle 

> app/console doctrine:generate:entities CompanyChildBundle 

che modifica automaticamente i core e di entità bambino definizioni:

nucleo entità pacchetto: http://pastebin.com/kfQRxcnm

bambino entità pacchetto: http://pastebin.com/UdiPP9xX

il problema!

Così, il nocciolo della questione è questo: Se si confronta la funzione setLand nel bundle Core e bambino, è possibile vedere le dichiarazioni sono diverse:

public function setLand(\Company\CoreBundle\Entity\Land $land = null) 
public function setLand(\Company\ChildBundle\Entity\ChildLand $land = null) 

errori :(

Purtroppo, i diversi indizi tipo causano errori PHP severe a verificarsi, ad esempio:

PHP Fatal error: Class 'Symfony\Component\Debug\Exception\ContextErrorException' not found in ... Company/ChildBundle/Entity/ChildPackage.php on line ... 

E

Runtime Notice: Declaration of ... should be compatible with ... in ... line ... 

La causa degli errori

Dopo aver fatto qualche ricerca sul motivo per cui questo è stato un problema, ho letto in diversi luoghi che cambiano tipo di hinting in sottoclassi pause tipo alludono contratti (vedi questo post: Is there a way to redefine a type hint to a descendant class when extending an abstract class?).

Opzioni?

ci sono alcune opzioni ovvi ma meno-che-ideale:

  • posso sopprimere le comunicazioni severe abbastanza facilmente, ma il mio responsabile dello sviluppo baulks alla prospettiva di dover creare eccezioni fiocco di neve nei nostri processi di CI.
  • Posso modificare manualmente il codice che la dottrina genera per rimuovere tutti i tipi di suggerimenti, o per garantire che gli hint del tipo di classe figlio siano gli stessi delle classi genitore. Fare questo fa funzionare il codice, ma posso vederlo essere noioso a meno che non scrivo alcuni script per gestirlo per me.
  • Non posso semplicemente usare gli strumenti da riga di comando e creare manualmente le mie entità e sottounità manualmente. Preferirei essere in grado di automatizzare questo con script :(

La mia domanda !!!(finalmente)

La mia domanda è, è possibile utilizzare gli strumenti della riga di comando per fare ciò che sto cercando di fare qui? Idealmente, mi piacerebbe essere in grado di eseguire i comandi della console doctrine per generare stub di entità e getter e setter senza l'intervento manuale per correggere i suggerimenti di tipo nelle sottoclassi. Se questo non è facilmente realizzabile, qual è l'opzione migliore?

Gratitudine

Grazie!

+1

Sarebbe questo aiuto? http://symfony.com/doc/current/cookbook/doctrine/resolve_target_entity.html – jmlnik

+0

Non senza ripensare drasticamente al mio approccio. Innanzitutto, avrei bisogno di un'interfaccia per ogni relazione. La seconda e probabilmente la ragione principale è che secondo la documentazione "il ResolveTargetEntityListener può solo cambiare la destinazione in un singolo oggetto", mentre dovrò estendere le funzionalità di base su molti bambini, quindi avrò "XPackage", "YPackage" ecc. Grazie per la risposta, però, non ero a conoscenza di questa funzionalità e la considererò sicuramente per gli scenari futuri. –

+0

Stai chiedendo una parte di codice in cui puoi vedere che la dottrina non è in grado di gestire la situazione in cui la classe ereditata ha una proprietà di relazione sovrascritta? –

risposta

4

Io non sono esattamente sicuro di quale processo che verrà utilizzato per definire le entità, ma al fine di creare utilmente entità persistibili con la dottrina, come GenericEngine e FordEngine, si vuole @MappedSuperclass

http://docs.doctrine-project.org/en/latest/reference/inheritance-mapping.html#mapped-superclasses

È l'equivalente di Doctrine di una classe astratta.

Ci sono alcuni altri trucchi ereditari interessanti su quella pagina collegata sopra. Potrebbero aiutarti.

Per quanto riguarda la generazione di questa roba automaticamente, potrebbe essere fattibile ma al di sopra del mio grado di paga a +50 punti reputazione. :-) Doctrine può aiutarti a generare modelli di codice per le tue entità, ma in realtà, il tempo che progetta le entità e le loro relazioni è meglio speso del tempo a venire con una combinazione magica di linee di comando.

(Me stesso, mi piacerebbe avere un'entità Manufacturer e poi hanno uno-a-molti tra la Engine e Manufacturer. Ma non è quello che hai chiesto. :-)

+0

Grazie per la risposta. Aggiungerò un ERD dettagliato che illustra come un "Costruttore" non funzionerà senza implementare una struttura EAV; un diverso barattolo di vermi. La nostra struttura soddisfa tutti i requisiti di business e una volta che gli errori di suggerimento del tipo di dottrina vengono risolti manualmente funziona bene. Pensieri diversi sulla struttura dei dati significano che potremmo discuterne per sempre :-). Per quanto riguarda il tempo, l'automazione della generazione di classi secondarie fornirebbe benefici continui, mentre gli strumenti CLI di doctrine sono ben supportati, tranne per il problema del tipo di suggerimento.Se non si utilizzano gli strumenti è davvero la risposta, quindi lo accetto:/ –

+0

Ho aggiunto l'ERD aggiornato. Grazie ancora per il tuo tempo. –