2015-08-12 33 views
8

Ci sono diversi modi in cui è possibile accedere al repository dell'entità nei controller o nei servizi Symfony2, ciascuno dei quali ha il proprio vantaggio e svantaggio. Per prima cosa li elenco qui, e poi chiedendo se c'è qualche soluzione migliore o queste sono le uniche opzioni che abbiamo e dovremmo scegliere uno o alcuni in base alle nostre preferenze. Voglio anche sapere se il metodo 5 (che ho iniziato a usarlo di recente) può essere buono e non infrange nessuna regola o ha effetti collaterali.Symfony - Come accedere al repository dell'entità

Metodo di base: Utilizzare il gestore entità nel controller o Iniettarlo su un servizio e quindi accedere a qualsiasi repository che desidero. Questo è il modo di base per accedere a un repository nel controller o nel servizio.

class DummyController 
{ 
    public function dummyAction($id) 
    { 
     $em = $this->getDoctrine()->getManager(); 
     $em->getRepository('ProductBundle:Product')->loadProduct($id); 
    } 
} 

Ma ci sono alcuni problemi relativi a questo methos. Il primo problema è che non posso fare Ctrl + clic sulla funzione loadProduct ad esempio e andare direttamente alla sua implementazione (a meno che non ci sia un modo che non conosco). L'altro problema è che finirò per ripetere questa parte di codice più e più volte.

Metodo 2: L'altro metodo è solo per definire un getter nel mio servizio o controller per accedere al mio repository.

class DummyService 
{ 
    protected $em; 

    public function __construct(EntityManager $em) 
    { 
     $this->em = $em; 
    } 

    public function dummyFunction($id) 
    { 
     $this->getProductRepository()->loadProduct($id); 
    } 

    /** 
    * @return \ProductBundle\Entity\Repository\ProductRepository 
    */ 
    public function getProductRepository() 
    { 
     return $this->em->getRepository('ProductBundle:Product'); 
    } 
} 

Questo metodo risolve il primo problema e in qualche modo il secondo, ma ancora devo ripetere tutti i getter che ho bisogno nel mio servizio o del controller, anche avrò parecchi getter nei miei servizi e controller solo per l'accesso al repository

Metodo 3: un altro modo è quello di iniettare un repository per il mio servizio, è bello, soprattutto se abbiamo un buon controllo sul nostro codice e non siamo coinvolti con altri sviluppatori che si iniettano l'intero contenitore al tuo servizio.

class DummyService 
{ 
    protected $productRepository; 

    public function __construct(ProductRepository $productRepository) 
    { 
     $this->productRepository = $productRepository; 
    } 

    public function dummyFunction($id) 
    { 
     $this->productRepository->loadProduct($id); 
    } 
} 

Questo metodo risolve il primo e il secondo problema, ma se il mio servizio è grande e ha bisogno di fare con un sacco di repository, allora non è una bella idea di iniettare per esempio 10 repository al mio servizio .

Metodo 4: Un altro modo è disporre di un servizio per includere tutti i miei repository e iniettare questo servizio su altri servizi.

class DummyService 
{ 
    protected $repositoryService; 

    public function __construct(RepositoryService $repositoryService) 
    { 
     $this->repositoryService = $repositoryService; 
    } 

    public function dummyFunction($id) 
    { 
     $this->repositoryService->getProductRepository()->loadProduct($id); 
    } 
} 

RepositoryService:

class RepositoryService 
{ 
    protected $em; 

    public function __construct(EntityManager $em) 
    { 
     $this->em = $em; 
    } 

    /** 
    * @return \ProductBundle\Entity\Repository\ProductRepository 
    */ 
    public function getProductRepository() 
    { 
     return $this->em->getRepository('ProductBundle:Product'); 
    } 

    /** 
    * @return \CmsBundle\Entity\Repository\PageRepository 
    */ 
    public function getPageRepository() 
    { 
     return $this->em->getRepository('CmsBundle:Page'); 
    } 
} 

Questo metodo risolve anche il primo e secondo problema. Ma RepositoryService può diventare così grande quando abbiamo 200 entità ad esempio.

Metodo 5: Infine, è possibile definire un metodo statico in ogni entità che restituisce il proprio repository.

class DummyService 
{ 
    protected $em; 

    public function __construct(EntityManager $em) 
    { 
     $this->em = $em; 
    } 

    public function dummyFunction($id) 
    { 
     Product::getRepository($this->em)->loadProduct($id); 
    } 
} 

mio Entity:

/** 
* Product 
* 
* @ORM\Table(name="saman_product") 
* @ORM\Entity(repositoryClass="ProductBundle\Entity\ProductRepository") 
*/ 
class Product 
{ 
    /** 
    * 
    * @param \Doctrine\ORM\EntityManagerInterface $em 
    * @return \ProductBundle\Entity\ProductRepository 
    */ 
    public static function getRepository(EntityManagerInterface $em) 
    { 
     return $em->getRepository(__CLASS__); 
    } 
} 

Questo metodo risolve il primo e il secondo problema anche non ho bisogno di definire un servizio per accedere ai repository. L'ho usato di recente e finora è il metodo migliore per me.Non penso che questo metodo infrangerà la regola delle entità poiché è definita nello scope della classe ed è anche così. Ma ancora non ne sono sicuro e se ha o meno effetti collaterali.

risposta

2

Per me, nessuno dei vostri suggerimenti è corretto.
Perché non capisco perché è necessario creare un servizio della propria entità.
Se hai bisogno di accedere a questa entità, l'unica cosa che ti serve è avere accesso alla dottrina.
E doctrine ha un servizio (@doctrine).
Sta a te preparare nel costrutto per avere accesso solo a quell'entità.

Statica sono da dimenticare:

E che si presenta nel metodo di 5 non è corretto, la vostra entità del prodotto già accesso a entityManager tramite ProductRepository con il getEntityManager () metodo.

+2

Uso i servizi per i miei archivi con interfacce. Riduce la quantità che il mio codice è direttamente accoppiato con Doctrine quando non è realmente necessario. Tutto ciò che un servizio/oggetto richiede è che ottiene un repository che si adatta all'interfaccia invece di ottenere Doctrine, per ottenere il repository (che non è anche controllato da un tipo, quindi potrebbe non avere alcun metodo personalizzato). – qooplmao

+1

Non hai assolutamente bisogno di dottrina. È come avere una mucca, quando tutto ciò di cui hai bisogno è un po 'di latte. – user2268997

+0

hai ragione @ user2268997 – Roukmoute

7

Nel mondo di Doctrine l'entità dovrebbe essere un modello anemico di getter e setter (e aggiungere o rimuovere), quindi iniettare il repository sarebbe una cosa sbagliata da fare.

Tutto dipende da quanto vuoi essere accoppiato con Doctrine. Se si sta bene con il passare del servizio @doctrine intorno allora si può solo usare qualcosa di simile:

$this->repository = $doctrine->getRepository('CmsBundle:Page'); 

.. ma allora che, come detto, che richiedono di passare al servizio @doctrine in ogni oggetto. Ciò significherebbe che se tu decidessi di non usare Doctrine per qualsiasi motivo, dovresti rifattorizzare tutto il tuo codice per adattarlo alla tua nuova metodologia (qualunque essa sia), ma questo potrebbe non essere un problema per te. Inoltre, il repository sarebbe di tipo accennato, quindi non vi è alcuna garanzia (oltre a controllare se è la classe corretta nel codice) per garantire che sia il servizio corretto.

A mio parere il modo più pulito per farlo è quello di creare un servizio come:

XML

<service id="cms.page_repository" 
    class="Acme\CmsBundle\Repository\PageRepository"> 
    <factory service="doctrine" method="getRepository" /> 
    <argument>AcmeDemoBundle:ExampleRepository</argument> 
</service> 

YAML

cms.page_repository: 
    class: Acme\CmsBundle\Repository\PageRepository 
    factory: [ @doctrine, 'getRepository' ] 

.. e poi si può passare la tua servizio di repository ovunque tu voglia senza la necessità di utilizzare il servizio doctrine nel tuo codice reale. Con questo approccio, se decidi di allontanarti da Doctrine, devi solo modificare le definizioni del servizio piuttosto che dover rifattorizzare tutto. Anche a causa del fatto che si sta creando il servizio del repository specifici è possibile utilizzare tipo di hinting nel __construct per garantire il servizio corretto viene iniettato come:

public function __construct(PageRepository $repository) 
{ 
    $this->repository = $repository; 
} 
+0

Se il tuo progetto è troppo disordinato per essere in grado di creare e iniettare un servizio, allora hai problemi ben più grandi delle migliori pratiche. – qooplmao

+0

Non voglio iniettare repository alla mia entità, la funzione nel metodo 5 è una funzione statica e non è in ambito oggetto e entità. Sono d'accordo con te, il modo migliore è definire un servizio di repository, ma se lavori in un progetto grande e disordinato è difficile farlo, ma sicuramente se voglio lavorare su uno nuovo seguirò questo schema. –

+0

Ad esempio, uno dei miei servizi deve accedere a 5 repository + altri 5 servizi, quindi ho 10 iniezioni di servizio nel mio servizio. Non penso sia una buona idea. –

1

ti suggerisco di utilizzare il metodo 4, il tuo servizio seguirà Single Resposability Principe in quanto fa solo una cosa: dandoti l'accesso a tutti i tuoi repository.

Questo servizio sarà principalmente come una dipendenza in altri servizi. Per i controller, ti suggerisco di creare una classe base di controller personalizzata con le stesse funzioni di supporto.

Informazioni sulle duplicazioni di codice, i tratti possono essere la soluzione. Anche con il numero di metodi se si utilizza un tratto per "categoria"

+0

Grazie a Yassine, nel mio controller posso anche usare lo stesso servizio e non ho bisogno di avere un controller di base. –

+0

Nel caso in cui si preferisca '$ this-> getMyRepository()' su '$ this-> get ('app.repositories') -> getMyRepository()' :) –

+0

class baseController {public function getRepositories() {return $ this -> get ('app.repositories'); }} classe myController estende baseController {funzione pubblica dummyAction() {$ this-> getRepositories() -> getProductRepo() -> loadProduct()}} –