Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [Symfony][Symfony2]Jak są rejestrowane klasy Eventów w frameworku?
Forum PHP.pl > Forum > PHP > Frameworki
adbacz
Skąd EventDispatcher wie, że o tym Evencie ma poinformować takie a nie inne obiekty? Czyli inaczej mówiąc, gdzie jest przechowywana lista klas, których obiekty są później informowane o wystąpieniu danego Eventu?

Rozumiem całą zasadę działania tego wzroca, ale nie mam zielonego pojęcia jak dzieje się informowanie EventDispachera o tym, kto ma zostać poinfomowany. To się dzieje za każdym razem, gdy jest request do aplikacji? Jeśli tak, to czy aplikacja odpytuje wszystkie możliwe [obiekty, pliki, klasy..?] i sprawdza, który będzie Listenerem Eventu?
Crozin
Aby jakiś obiekt zaczął nasłuchiwać danego zdarzenia musi zostać dodany jako listener pod konkretne zdarzenie:
  1. /** @var Symfony\Component\EventDispatcher\EventDispatcher $dispatcher */
  2. $dispatcher = ...
  3.  
  4. $myObject = new MyClass();
  5.  
  6. $dispatcher->addListener('some.event', [$myObject, 'someMethod']);
  7. $dispatcher->addListener('other.event', [$myObject, 'otherMethod']);
Jeżeli zaś Twój obiekt implementuje interfejs EventSubscriberInterface może on sam określić jakich zdarzeń nasłuchuje:
  1. $myObject = new MyClass();
  2.  
  3. $dispatcher->addSubscriber($myObject);

http://api.symfony.com/2.5/Symfony/Compone...hod_addListener
http://api.symfony.com/2.5/Symfony/Compone...rInterface.html

W samym projekcie z reguły jest to robione niebezpośrednio, a przez kontener zależności. Przy usługach, które mają nasłuchiwać danego zdarzenia zobaczysz jeden z dwóch TAG-ów:
  1. <service id="..." class="...">
  2. <tag name="kernel.event_listener" event="some.event" method="someMethod" />
  3. <tag name="kernel.event_listener" event="other.event" method="otherMethod" />
  4. </service>
  5.  
  6. <service id="..." class="...">
  7. <tag name="kernel.event_subscriber" />
  8. </service>

Co w finalnym kodzie PHP zostanie przekształcone w dokładnie taki sam kod jak podałem na początku postu.

Więcej w dokumentacji: http://symfony.com/doc/current/components/...troduction.html
adbacz
Dziękuję Ci za odpowiedź, przeczytałem artykuły na dokumentacji którą podlinkowałeś, ale nie ma informacji o chociażby tych plikach XML o których wspomniałeś. Tym bardziej nie ma tam informacji o tym, gdzie są trzymane wszystkie EventListenery (tzn. lista klas i metod).

Jeśli są one ładowane na poczekaniu, to jak na przykład dodać EventListener dla eventu kernel.request? jest on przecież wykonywany przed wywołaniem kontrolera, a nie mam jak tego tam podpiąć wcześniej...
Crozin
Cytat
Dziękuję Ci za odpowiedź, przeczytałem artykuły na dokumentacji którą podlinkowałeś, ale nie ma informacji o chociażby tych plikach XML o których wspomniałeś.
Nie ma inf. dot. XML-i ponieważ jest to dokumentacja (fragment) samego komponentu EventDispatcher, który sam w sobie nie ma z nimi absolutnie nic wspólnego. XML-e do zasoby dla komponentu DIC-a, który to wykorzystuje event dispatchera.
Cytat
Tym bardziej nie ma tam informacji o tym, gdzie są trzymane wszystkie EventListenery (tzn. lista klas i metod).
Co masz na myśli przez "gdzie są trzymane wszystkie eventy"? Można podpiąć listenera pod dowolne zdarzenie. Czy może chodzi Ci o listę zdarzeń wykorzystywanych bezpośrednio przez FW?
Cytat
Jeśli są one ładowane na poczekaniu, to jak na przykład dodać EventListener dla eventu kernel.request?
Przecież pokazałem Ci przykład:
  1. <service id="my.service" class="MyEventListener">
  2. <tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" />
  3. </service>
Ten kod poinformuje DIC-a by utworzył usługę my.service, którą podepnie jako listenera dla zdarzenia kernel.request.
adbacz
Teraz chyba zrozumiałem. Jeśli chcę sobie podpiąć Listener pod zdarzenie, które wykonuje się na samym początku, zaraz po uruchomieniu aplikacji, to muszę zdefiniować service i poinformować w tej definicji DIC, że ma go podpiąć pod takie a nie inne zdarzenie?

Z tą listą wszystkich eventów, to miałem na myśli listę Listenerów. Po prostu nie umiałem sobie wyobrazić, jak podpiąć Listener z Bundle'a, który byłby informowany o zdarzeniu jeszcze przed tym, jak wywoływany jest kontroler tego Bundle. Bo skoro można poinformować Dispatcher o tym, że ten Listener ma nasłuchiwać tego zdarzenia, to jak go podpiąć wcześniej niż jest wykonywany kontroler dalego Bundle, bo nie mam nigdzie wcześniej możliwości tego zrobienia.
skowron-line
Jezeli masz zdefiniowny event w xml (jako service) to przy uruchamianiu aplikacji parsowane są wszystkie pliki i wyszukiwane w nich sa wpisy z odpowiednim tagiem
ustawiane sa w kolejnosci jaka wynika z priorytetu i w odpowienim momencie odpalane.
Crozin
Cytat
Jeśli chcę sobie podpiąć Listener pod zdarzenie, które wykonuje się na samym początku, zaraz po uruchomieniu aplikacji, to muszę zdefiniować service i poinformować w tej definicji DIC, że ma go podpiąć pod takie a nie inne zdarzenie?
Nie musisz, a możesz - to tylko jeden z możliwych sposobów, aczkolwiek najczęściej właśnie tak będziesz chciał to robić.

Zdefiniuj dokładniej co masz dokładnie na myśli pisząc "zaraz po uruchomieniu aplikacji". Aplikacja uruchamia się na linii nr 1 w pliku app.php, ale Tobie zapewne chodzi o jakiś moment, w którym cały framework już działa i masz dostęp do pewnych zasobów. Napisz co dokładnie chciałbyś uzyskać to podpowiem Ci, kiedy i jak powinieneś to uruchomić.

Cytat
Po prostu nie umiałem sobie wyobrazić, jak podpiąć Listener z Bundle'a, który byłby informowany o zdarzeniu jeszcze przed tym, jak wywoływany jest kontroler tego Bundle.
Symfony ma tutaj bardzo prostą architekturę. Musisz to zrobić po prostu zanim zostanie wywołana akcja z kontrolera. A co się dzieje zanim akcja zostanie wywołana? (w uproszczeniu)
1. Jeżeli jeszcze nie istnieje budowany jest kontener zależności (m. in. na podstawie plików XML). W ostatnim etapie jego budowania obsługiwane są TAG-i kernel.event_listener oraz kernel.event_subscriber, które powodują, że wygenerowany kod tworzący obiekt EventDispatchera od razu będzie miał dodane coś na kształt poniższego:
  1. // pseudokod
  2. function getEventDispatcherService() {
  3. $obj = new EventDispatcher(); // definicja <service ...> z XML-a
  4.  
  5. // to zostanie dodane dzięki tagom:
  6. $obj->addListener('kernel.request', getMyCustomKernelRequestListenerService());
  7. $obj->addListener('kernel.request', getMyAnotherCustomKernelRequestListenerService());
  8. $obj->addSubscriber('kernel.response', getMyCustomKernelResponseListenerService());
  9.  
  10. return $obj;
  11. }
Dzięki temu, gdy albo Ty, albo samo Symfony wywoła $container->get('event_dispatcher') wywołana zostanie ta funkcja (tylko raz w obrębie całego życia aplikacji - w kontekście żądania HTTP) i zwrócony zostanie EventDispatcher z już podpiętymi listenerami.
2. Następnie wszystko jest inicjalizowane, tj. odpalane są wszystkie bundle, tj. metoda boot() z MojProjekt\Abcdef\MojProjektAbcdefBundle. Tam możesz na dobrą sprawę zrobić co chcesz - masz dostęp do DIC-a więc możesz odwołać się do wszystkiego. Czyli możesz też dodać kolejnego listenera do EventDispatchera.
3. Następnie odpalane jest serce całego systemu, czyli Symfony\Component\HttpKernelHttpKernel::handleRaw(). Metoda ta przy pomocy EventDispatchera rzuca następującymi zdarzeniami kernel.request - to prawodpodobnie właśnie pod to chcesz się podpiąć, kernel.controller - tutaj wiadomo już jaki konkertnie kontroler i jaka akcja będą miały zostać odpalone, dopiero po tych dwóch zdarzeniach faktycznie odpalana jest akcja z kontrolera.
adbacz
Nawet nie wiesz jak jestem Ci wdzięczny za Twoja wiedzę i czas smile.gif Teraz już wszystko rozumiem. Bardzo Ci dziękuję!
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.