Doctrine2 Best Practice, entità dovrebbero utilizzare i servizi?
-
11-10-2019 - |
Domanda
Ho fatto una domanda simile un po 'indietro: Uso della pattern Data Mapper, se gli enti (Domain Objects) conoscono il Mapper? Tuttavia, era generico e sono davvero interessato a come realizzare un paio di cose con Doctrine2 specificamente .
Ecco un modello semplice esempio: Ogni Thing
può avere un Vote
da un User
, un User
può esprimere più di un Vote
ma solo gli ultimi conteggi Vote
. Perché altri dati (Msssage
, ecc) è legato alla Vote
, quando la seconda Vote
è collocato il Vote
originale non può semplicemente essere aggiornato, ha bisogno di essere sostituito.
Al momento Thing
ha questa funzione:
public function addVote($vote)
{
$vote->entity = $this;
}
E Vote
si prende cura di impostare il rapporto:
public function setThing(Model_Thing $thing)
{
$this->thing = $thing;
$thing->votes[] = $this;
}
Mi sembra che garantire un User
ha solo l'ultimo Vote
contato è qualcosa che l'Thing
dovrebbe garantire, e non un livello di servizio .
Quindi, per mantenere che nel modello, la nuova funzione Thing
:
public function addVote($vote)
{
foreach($this->votes as $v){
if($v->user === $vote->user){
//remove vote
}
}
$vote->entity = $this;
}
Allora, come faccio a rimuovere il Vote
dall'interno del modello di dominio? dovrebbe mi rilasso Vote::setThing()
ad accettare un NULL
? Dovrei comportare un qualche tipo di livello di servizio che Thing
può utilizzare per rimuovere il voto? Una volta che i voti iniziare ad accumulare, che foreach
sta per essere lento -? Se un livello di servizio essere utilizzata per consentire Thing
per cercare un Vote
senza dover caricare l'intera collezione
Sono decisamente sporgendosi verso utilizzando un livello di servizio di luce; tuttavia, c'è un modo migliore per gestire questo tipo di cose con Doctrine2, o sto andando nella direzione giusta?
Soluzione
Io voto per il livello di servizio. Ho spesso lottato con il tentativo di aggiungere il più logica per l'entità in sé, e semplicemente me stesso frustrato. Senza l'accesso al EntityManager, si è semplicemente non in grado di eseguire query di logica, e vi ritroverete con un sacco di operazioni O (n) o pigro-caricamento set di tutto il rapporto quando hai solo bisogno di un paio di record (che è super zoppo rispetto a tutti i vantaggi DQL offerte).
Se avete bisogno di qualche aiuto superando l'idea che il modello di dominio anemico è sempre un anti-modello, vedi questa presentazione da Matthew Weier O'Phinney o questa domanda .
E mentre potrei interpretando male la terminologia, sto non del tutto convinto che le entità devono essere gli unici oggetti permesso nel vostro Domain Model. Vorrei facilmente considerare che la somma di entità oggetti e la loro servizi costituisce il modello. Credo che l'anti-modello si pone quando si finisce per scrivere un livello di servizio che presta poca o nessuna attenzione alla separazione degli interessi.
Mi sono spesso flirtato con l'idea di avere tutti gli oggetti delega alcuni metodi per il livello di servizio la mia entità:
public function addVote($vote)
{
$this->_service->addVoteToThing($vote, $thing);
}
Tuttavia, poiché Doctrine non ha alcun sistema di evento di callback tipo su un oggetto idratazione, non ho trovato un modo elegante per iniettare l'oggetto del servizio.
Altri suggerimenti
Il mio consiglio sarebbe quello di mettere tutta la logica di query in un EntityRepository e poi fare un'interfaccia fuori di esso un po 'come:
class BlogPostRepository extends EntityRepository implements IBlogPostRepository {}
In questo modo è possibile utilizzare l'interfaccia nella vostra unità di test per gli oggetti del servizio e nessuna dipendenza dalla EntityManager è richiesto.