2013-10-15 46 views

回答

16

首先,使用globalvery bad practice。我強烈建議你不要這樣做。
其次,將服務注入存儲庫似乎不是一個好主意。它會經常違反像Single Responsibility Principle這樣的法律。

我會創建一個管理器,它將包裝存儲庫的方法,並將觸發您需要的事件。有關更多信息,請參閱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(); 
    } 
} 

然後你可以使用它在你的控制器,就像一個服務。

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

但是,如果你真的需要注入事件分派到您的實體,您可以做到這一點

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 ] ] 

然後你只需要添加setEventDispatcher方法t你的倉庫。

的Acme \ FooBundle \庫\ FooRepository

class FooRepository extends EntityRepository 
{ 
    protected $dispatcher; 

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

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

     // ... 
    } 
} 

只要確保你的控制器使用時調用服務,而不是倉庫。

DO

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

切勿

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

我CAM這裏有同樣的問題,而你的答案是有道理的。但是,現在經理有2個職責,代理庫和提高事件。這是一個非常「迂腐」的問題,但是你在哪裏停止重構來獲取SRP? – JorgeeFG

+0

@JorgeeFG IMO,你可以通過在你的管理器中給出一個'OptionsResolver :: resolve($ options)'和'ResultHandler :: handle($ results)'(它們都會調用一個事件)來再次重構它。然後經理將作爲一個簡單的Facade來連接所有三個組件。然而,我真的覺得添加這兩個接口會開始變得越來越多,因爲通過改變它們的行爲幾乎沒有任何改進/改變,因爲它們中的大多數可以在事件處理程序中完成。 – Touki

相關問題