Przejdź do głównej treści

Mechanizm Event-ów w PHP-ie

Ready_™ Developer TeamMniej niż 1 minutaEvent w php

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 tryb read only oraz dodatkowo ustawienie na tym polu disable

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:

  1. z pliku *.toml w folderze etc/ usuwamy nasz wpis
  2. przez ready-cli wykonujemy komendę config:compile
./ready-cli config:compile

Lista parametrów

  1. NAMESPACE_WITH_CLASSNAME - Nazwa klasy wraz z jej przestrzenią nazw.
  2. [EventListener | EventSubscriber] - Musisz wybrać czy rejestrujesz EventListener czy EventSubscriber
  3. --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.
  4. EVENT_OBJECT - Nazwa klasy wraz z jej przestrzenią nazw. Klasę tworzymy w folderze /src, na równi z public_html,

Jak należy tworzyć hierarchię folderów

  1. Zaczynamy od wejścia do folderu \src w głównej gałęzi kora,
  2. Następnie najczęstszym naszym wyborem będzie folder App
  3. Tworzymy folder, który odpowiada nazwie modułu,
  4. 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