Mechanizm Event-ów w PHP-ie
EventDispatcher jest to narzędzie umożliwiające aplikacją, komponentem a corem Ready, komunikację między sobą poprzez wywoływanie zdarzeń i ich nasłuchiwanie. EventDispatcher implementuje wzorce projektowe Mediator i Observer.
Events
Różnice miedzy Listener-em a Subscriber-em
Główna różnica w stosunku do Event Listener polega na tym, że EventSubscriber zawsze zna zdarzenia, które nasłuchuje. Jeżeli różne metody EventSubscriber nasłuchują tego samego zdarzenia, ich kolejność określa parametr priorytetu. Ta wartość jest dodatnią lub ujemną liczbą całkowitą, która domyślnie wynosi 0.
Event Listener czy Event Subscriber
Listener i Subscriber mogą być wykorzystywani w tej samej aplikacji w sposób nierozróżnialny. Decyzje by użyć którąkolwiek z nich najczęściej decyduje dobry smak programisty.
Jednakże, są ważne zalety każdego typu zdarzenia:
- Subscriber jest łatwiejszy do ponownego użycia ponieważ wiedza o zdarzeniach jest przechowywana w klasie, a nie w definicji usługi.
- Listener jest bardziej elastyczny ponieważ pakiety mogą warunkowo włączać lub wyłączać każdy z nich w zależności od pewnej wartości konfiguracyjnej.
Event Listener
Nazwa klasy, (którą się podaje jako pierwszy parametr podczas rejestracji) musi implementować interfejs:
- AsynchronousListenerInterface - Wykonanie kodu odbywa się w tle za pomocą kolejki BgTask, w razie niepowodzenia loguje błąd.
- SynchronousListenerInterface - Wczytuje lisynera i przekazuje obiekt do metody
onEvent
.
Interface wymusza by dodać metodę onEvent(object $event): void
, w której należy obsłużyć przychodzący obiekt eventu, który podaliśmy podczas rejestracji.
Przykład Listenera
Listener z przykładu jest odpowiedzialny za:
- ustawienie pola
dscrpt
w trybread only
oraz dodatkowo ustawienie na tym poludisable
W listynerze sprawdzamy czy otrzymany event jest obiektem utworzonym z konkretnej klasy, w tym przypadku z \Ready\App\Processes\Event\MainFormCreated
(tak jak namespace mówi obiekt event-u znajduje się w corze w folderze ./src/
).
<?php
namespace ReadyApp\Projekty\Forms\Plugins;
use Ready\Component\System\Events\Listener\SynchronousListenerInterface;
final class ProcessMainGeneralFormAfterCreate implements SynchronousListenerInterface {
public function onEvent(object $event): void {
if ($event instanceof \Ready\App\Processes\Event\MainFormCreated) {
$processes = $event->getProcess();
$processes->dscrpt->disable();
$processes->dscrpt->setReadOnly(TRUE);
}
}
}
Event Subscriber
Nazwa klasy, (którą się podaje jako pierwszy parametr podczas rejestracji) musi implementować interfejs:
- AsynchronousSubscriberInterface - Dodaje subscriber do kolejki rabita. Wykonanie kodu odbywa się w tle za pomocą kolejki BgTask.
- SynchronousSubscriberInterface - Dodaje subscriber za pomocą addSubscriber do SymfonyEventDispatcher.
Interface wymusza by dodać metodę getSubscribedEvents(): void
, w której należy obsłużyć przychodzący obiekt eventu, który podaliśmy podczas rejestracji.
<?php
namespace ReadyApp\Projekty\Forms\Plugins;
use Ready\Component\System\Events\Subscriber\SynchronousSubscriberInterface;
use Ready\App\Processes\Event\MainFormCreated;
final class ProcessMainGeneralFormAfterCreate implements SynchronousSubscriberInterface {
/**
* @return array[]|\array[][]|string[]
*/
public static function getSubscribedEvents(): array {
return [
MainFormCreated::class => 'onEvent',
];
}
public function onEvent(object $event): void {
if ($event instanceof \Ready\App\Processes\Event\MainFormCreated) {
$processes = $event->getProcess();
$processes->dscrpt->disable();
$processes->dscrpt->setReadOnly(TRUE);
}
}
}
Przykład skryptu:
ProcessMainGeneralFormAfterCreate.inc
metoda getSubscribedEvents
Posiada także możliwość zadeklarowania wielu metod:
['eventName' => 'methodName']
['eventName' => ['methodName', $priority]]
['eventName' => [['methodName1', $priority], ['methodName2']]]
Jeśli nie podamy priorytetu, deflaut
- owo jest ustawiana wartość 0.
Więcej informacji o rejestracji przez AppComposer znajdziesz w Wywoływanie dodatkowych poleceń
Rejestracja Eventu
Eventy rejestrujemy przez ready-cli
oraz dodajemy wpis w AppComposer.json
Definicja
./ready-cli config:register NAMESPACE_WITH_CLASSNAME [EventListener | EventSubscriber] --param-name event-name --param-value EVENT_OBJECT
Przykład rejestracji w AppComposer.json
"scripts": {
"post-install-cmd": [
"ready-cli config:register \\ReadyApp\\Projekty\\Forms\\Plugins\\ProcessMainGeneralFormAfterCreate EventSubscriber"
],
}
Przykład rejestracji Listynera przez CLI
./ready-cli config:register \\ReadyApp\\Projekty\\Forms\\Plugins\\ProcessMainGeneralFormAfterCreate EventListener --param-name=event-name --param-value=process.afterCreate --param-name=priority --param-value=0
lub
Przykład rejestracji Subscrybera przez CLI
./ready-cli config:register \\ReadyApp\\Projekty\\Forms\\Plugins\\ProcessMainGeneralFormAfterCreate EventSubscriber
Kompilacja konfiguracji
Po rejestracji należy z kompilować konfigurację
./ready-cli config:compile
Wyrejestrowanie eventu
Eventy wyjestrujemy w 2 krokach, mianowicie:
- z pliku *.toml w folderze etc/ usuwamy nasz wpis
- przez
ready-cli
wykonujemy komendę config:compile
./ready-cli config:compile
Lista parametrów
- NAMESPACE_WITH_CLASSNAME - Nazwa klasy wraz z jej przestrzenią nazw.
- [EventListener | EventSubscriber] - Musisz wybrać czy rejestrujesz EventListener czy EventSubscriber
- --param-name --param-value - Dodatkowo za pomocą tej opcji można przekazać do kontrolera dodatkowe parametry. Nazwę parametru i wartość należy przekazywać zawsze razem (w tej samej kolejności), inaczej konsola nie będzie mogła tego powiązać.
- --param-name=event-name --param-value=NAZWA - Nazwa zdarzenia pod którym ma zostać zarejestrowana klasa
- --param-name=priority --param-value=0 - Priorytet z jakim klasa ma zostać wywoływana podczas wyemitowania zdarzenia w systemie wiecej tautaj.
- EVENT_OBJECT - Nazwa klasy wraz z jej przestrzenią nazw. Klasę tworzymy w folderze
/src
, na równi zpublic_html
,
Jak należy tworzyć hierarchię folderów
- Zaczynamy od wejścia do folderu
\src
w głównej gałęzi kora, - Następnie najczęstszym naszym wyborem będzie folder
App
- Tworzymy folder, który odpowiada nazwie modułu,
- a następnie folder Event, w którym tworzymy klasę, którą później użyjemy do rejestracji, tjw. w ptk 4. EVENT_OBJECT
Przykład hierarchii folderów
.
└── src
└── App
└── Process
└── Event
└── MainFormCreated.inc
Przykład
./ready-cli config:register ReadyApp\\Projekty\\Forms\\Plugins\\ProcessMainGeneralFormAfterCreate EventListener --param-name=event-name --param-value=Ready\\App\\Processes\\Event\\MainFormCreated
Gdzie można znaleźć wpisy zarejestrowanych eventów
Eventy rejestrują się w plikach .toml, które znajdują się w folderze etc
- event_dispatcher.toml
- event_subscriber.toml