2013-10-15 10 views

Odpowiedz

16

Po pierwsze, użycie global jest very bad practice. Radzę ci tego nie robić.
Po drugie, wstrzykiwanie usług do repozytorium nie wydaje się dobrym pomysłem. Często łamie prawa, takie jak Single Responsibility Principle.

Stworzyłem menedżera, który otoczy metody repozytorium i uruchomi potrzebne zdarzenia. Aby uzyskać więcej informacji, patrz how to inject repository to a service.

services.yml

services: 
    my_manager: 
     class: Acme\FooBundle\MyManager 
     arguments: 
      - @acme_foo.repository 
      - @event_dispatcher 

    acme_foo.repository: 
     class: Acme\FooBundle\Repository\FooRepository 
     factory_service: doctrine.orm.entity_manager 
     factory_method: getRepository 
     arguments: 
      - "AcmeFooBundle:Foo" 

Acme \ FooBundle \ MyManager

use Acme\FooBundle\Repository\FooRepository; 
use Symfony\Component\EventDispatcher\EventDispatcherInterface; 

class MyManager 
{ 
    protected $repository; 
    protected $dispatcher; 

    public function __construct(FooRepository $repository, EventDispatcherInterface $dispatcher) 
    { 
     $this->repository = $repository; 
     $this->dispatcher = $dispatcher; 
    } 

    public function findFooEntities(array $options = array()) 
    { 
     $event = new PreFindEvent; 
     $event->setOptions($options); 

     $this->dispatcher->dispatch('find_foo.pre_find', $event); 

     $results = $this->repository->findFooEntities($event->getOptions()); 

     $event = new PostFindEvent; 
     $event->setResults($results); 

     $this->dispatcher->dispatch('find_foo.post_find', $event); 

     return $event->getResults(); 
    } 
} 

Wtedy można go używać w kontrolerze, podobnie jak usługi.

$this->get('my_manager')->findFooEntities($options); 

Jeśli jednak naprawdę trzeba wstrzyknąć dyspozytora zdarzeń do swojej jednostki, można to zrobić

services.yml

services: 
    acme_foo.repository: 
     class: Acme\FooBundle\Repository\FooRepository 
     factory_service: doctrine.orm.entity_manager 
     factory_method: getRepository 
     arguments: 
      - "AcmeFooBundle:Foo" 
     calls: 
      - [ "setEventDispatcher", [ @event_dispatcher ] ] 

Następnie po prostu trzeba dodać metodę t o twoje repozytorium.

Acme \ FooBundle \ Repository \ FooRepository

class FooRepository extends EntityRepository 
{ 
    protected $dispatcher; 

    public function setEventDispatcher(EventDispatcherInterface $dispatcher) 
    { 
     $this->dispatcher = $dispatcher; 
    } 

    public function findFooEntities(array $options = array()) 
    { 
     $dispatcher = $this->dispatcher; 

     // ... 
    } 
} 

Tylko upewnij się, wezwać serwis i nie repozytorium podczas używania go w kontrolerze.

DO

$this->get('acme_foo.repository')->findFooEntities(); 

NIE

$this->getDoctrine()->getManager()->getRepository('AcmeFooBundle:Foo')->findFooEntities(); 
+0

I cam tu ten sam problem, a odpowiedź ma sens. Jednak teraz Menedżer ma 2 obowiązki, proxy repozytorium i podnoszenie wydarzeń. To jest bardzo "pedantyczne" pytanie, ale gdzie przestajesz refaktoryzować, aby uzyskać SRP? – JorgeeFG

+0

@JorgeeFG IMO, możesz go ponownie poprawić, używając opcji 'OpcjeResolwer :: rozstrzygnięcie ($ options)' i 'ResultHandler :: handle ($ results)' (która wywoła zdarzenie) podanych w Menedżerze. Menedżer będzie wówczas działać jako prosta fasada, która połączy wszystkie trzy komponenty. Jednak naprawdę uważam, że dodanie tych dwóch interfejsów może zacząć być przesadzone, ponieważ nie ma prawie żadnych ulepszeń/zmian, których można by się spodziewać poprzez zmianę ich zachowania, ponieważ większość z nich można zrobić w programach obsługi zdarzeń. – Touki