Chciałbym wiedzieć, jaka jest najlepsza praktyka wtrysku EventDispatcher w klasie EntityRepository.Jaki jest najlepszy sposób wstrzyknięcia EventDispatcher w EntityRepository?
Odpowiedz
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();
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
@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