2012-07-17 13 views
22

Dopo aver letto un sacco di post e risorse Stack Overflow, ho ancora qualche problema con la famosa domanda su "dove mettere la logica aziendale?" Leggendo StackOverflow Question e A Blog Post, credo di aver capito bene il problema della separazione del codice.Dove posizionare la logica aziendale in Symfony2?

Supponiamo di disporre di un modulo Web in cui è possibile aggiungere un utente che verrà aggiunto a un db. Questo esempio riguarda questi concetti:

  • Forma
  • controller
  • Entity
  • Servizio
  • Repository

Se non mi manca qualcosa, è necessario creare un soggetto con alcune proprietà, getter, setter e così via per renderlo persistente in un db. Se desideri recuperare o scrivere quell'entità, utilizzerai lo entityManager e, per la query "non canonica", entityRepository (è qui che puoi inserire la query "lingua di query").

Ora è necessario definire un servizio (ovvero una classe PHP con un'istanza "lazy") per tutte le logiche di business; questo è il posto dove mettere il codice "pesante". Una volta registrato il servizio nella tua applicazione, puoi usarlo quasi ovunque e ciò comporta il riutilizzo del codice e così via.

Quando si esegue il rendering e il post di un modulo, lo si lega con la propria entità (e con i vincoli ovviamente) e si utilizzano tutti i concetti sopra definiti per mettere tutti insieme.

Quindi, "vecchio-me" scriverei l'azione di un controller in questo modo:

public function indexAction(Request $request) 
    { 
     $modified = False; 
     if($request->getMethod() == 'POST'){ // submit, so have to modify data 
      $em = $this->getDoctrine()->getEntityManager(); 
      $parameters = $request->request->get('User'); //form retriving 
      $id = $parameters['id']; 
      $user = $em->getRepository('SestanteUserBundle:User')->find($id); 
      $form = $this->createForm(new UserType(), $user); 
      $form->bindRequest($request); 
      $em->flush(); 
      $modified = True; 
     } 

     $users = $this->getDoctrine()->getEntityManager()->getRepository('SestanteUserBundle:User')->findAll(); 
     return $this->render('SestanteUserBundle:Default:index.html.twig',array('users'=>$users)); 
    } 

"New-me" ha refactoring del codice in questo modo:

public function indexAction(Request $request) 
    { 
     $um = $this->get('user_manager'); 
     $modified = False; 
     if($request->getMethod() == 'POST'){ // submit, so have to modify data 
      $user = $um->getUserById($request,False); 
      $form = $this->createForm(new UserType(), $user); 
      $form->bindRequest($request); 
      $um->flushAll(); 
      $modified = True; 
     } 
     $users = $um->showAllUser(); 
     return $this->render('SestanteUserBundle:Default:index.html.twig',array('users'=>$users)); 
    } 

Dove $um è un servizio personalizzato in cui è memorizzato tutto il codice che non è possibile vedere dal pezzo di codice n. 1 al pezzo di codice n.

Così, qui sono le mie domande:

  1. ho fatto, infine, ottenere l'essenza di Symfony2 e {M} VC in generale?
  2. Il refactoring è buono? In caso contrario, quale sarebbe un modo migliore?

Post Scriptum: So che posso usare il FOSUserBundle per il deposito e l'autenticazione utente, ma questo è un esempio di base per insegnare a me stesso come lavorare con Symfony. Inoltre, il mio servizio è stato iniettato con ORM.Doctrine. * Per funzionare (solo una nota per chi ha letto questa domanda con la mia stessa confusione)

+0

Qual è lo scopo di $ modificato e qual è lo scopo del secondo parametro a getUserById ()? – redbirdo

+0

Bene, la logica di business del dominio va in [model layer] (http://stackoverflow.com/a/5864000/727208). Mosley negli [oggetti dominio] (http://c2.com/cgi/wiki?DomainObject). –

+0

@redbirdo: non ha importanza ai fini della domanda. – DonCallisto

risposta

3

Ci sono due approcci principali su dove mettere la logica di business: il Architettura SOA e architettura basata su domini. Se i tuoi oggetti di business (entità) sono anemici, voglio dire, se non hanno una logica di business, solo getter e setter, allora preferirai SOA. Tuttavia, se costruisci la logica di business all'interno dei tuoi oggetti di business, allora preferirai l'altra.Adam Bien discute questi approcci:

Domain-Driven Design con Java EE 6: http://www.javaworld.com/javaworld/jw-05-2009/jw-05-domain-driven-design.html

architetture service magra con Java EE 6: http://www.javaworld.com/javaworld/jw-04-2009/jw-04-lean-soa-with-javaee6.html

E 'Java, ma è possibile ottenere l'idea.

+2

Grazie per la risposta alla mia domanda. Ho letto quegli articoli ma questo non mi dà altro che quello che suppongo di sapere :) Se puoi espandere la tua risposta con più dettagli e adattarla al mio esempio "reale", sarò felice (come tutti i comunity sarà) per leggere, capire e - anche - darti un feedback positivo. – DonCallisto

0

Mi rendo conto che questa è una domanda vecchia, ma poiché avevo un problema simile volevo condividere la mia esperienza, sperando che potesse essere di aiuto per qualcuno. Il mio suggerimento sarebbe di introdurre un bus di comando e iniziare ad usare il modello di comando. Il flusso di lavoro è più o meno in questo modo:

  1. controller riceve richiesta e lo traduce ad un comando (un modulo potrebbe essere utilizzato per fare questo, e potrebbe essere necessario un po 'di DTO per spostare i dati in modo pulito da un livello all'altro)
  2. controller invia il comando al comando bus
  3. il bus comando è un gestore di e gestisce il comando
  4. il controller può quindi generare la risposta in base a ciò di cui ha bisogno.

Alcuni codice basato sul tuo esempio:

public function indexAction(Request $request) 
{ 
    $command = new CreateUser(); 
    $form = $this->createForm(new CreateUserFormType(), $command); 
    $form->submit($request); 
    if ($form->isValid()) { 
     $this->get('command_bus')->handle(); 
    } 
    return $this->render(
     'SestanteUserBundle:Default:index.html.twig', 
     ['users' => $this->get('user_manager')->showAllUser()] 
    ); 
} 

Allora il vostro gestore di comando (che è in realtà parte del livello di servizio) sarebbe responsabile della creazione dell'utente. Questo ha diversi vantaggi:

  • I suoi controllori sono molto meno probabilità di diventare gonfio, perché hanno poca o nessuna logica
  • la logica di business è separato dalla logica dell'applicazione (HTTP)
  • il codice diventa più testabile
  • È possibile riutilizzare lo stesso gestore di comandi, ma con i dati provenienti da una porta diversa (ad esempio CLI)

ci sono anche un paio di aspetti negativi:

  • il numero di classi è necessario al fine di applicare questo modello è più elevato e di solito scale linearmente con il numero di caratteristiche dell'applicazione espone
  • ci sono più pezzi in movimento ed è un po 'più difficile ragionare su, in modo da la curva di apprendimento per una squadra potrebbe essere un po 'più ripida.

Un autobus comando paio degni di nota:

https://github.com/thephpleague/tactician https://github.com/SimpleBus/MessageBus

0

È il refactoring una buona? In caso contrario, quale sarebbe un modo migliore?

Una delle migliori pratiche quadro sta utilizzando convertitori param per invocare direttamente un'entità dalla richiesta dell'utente.

Esempio dalla documentazione Symfony:

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; 

/** 
* @Route("/blog/{id}") 
* @ParamConverter("post", class="SensioBlogBundle:Post") 
*/ 
public function showAction(Post $post) 
{ 

} 

Altro su convertitori param:

http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html

+0

Sì, lo so, questa è una risposta molto vecchia e, btw, il tuo dovrebbe essere un commento: non stai rispondendo alla mia domanda. Tuttavia ora so dove posizionare la logica di business: a chi appartiene. Voglio dire, se la logica è legata a un'entità, è quasi obbligatorio (almeno per me) mantenerlo INSIDE entità; altrimenti ora utilizzo un servizio che potrebbe dividere la logica in sotto-servizi al fine di mantenere valida la singola responsabilità principale. Saluti! – DonCallisto

Problemi correlati