
Zend Framework 2 zbliża się wielkimi krokami. Po okresie zastoju zdecydowano się przenieść główne repozytorium projektu na GitHub i bardziej otworzyć się na społeczność - nie trzeba juz podpisywać CLA przed dodaniem swoich łatek. Dzięki temu rozwój wyraźnie przyspieszył, a kod zaczyna się stabilizować.
Pierwszą nowością którą opiszę jest Event Manager. Komponent ten stanowi jeden z fundamentów nowej wersji frameworka.
Czym jest Event Manager?
Event Manager jest implementacją wzorca "obserwator". Składa się z kilku klas umożliwiających definiowanie zdarzeń oraz podpinanie pod nie funkcji. Takie zdarzenia to np. start aplikacji, lokalizowanie kontrolera i akcji na podstawie URL-a (routing), czy wreszcie wysyłanie odpowiedzi serwera.
Komponent ten wykorzystywany jest na różne sposoby. Na przykład nowy stos MVC używa systemu zdarzeń, aby zespoić warstwy kontrolera i widoku.
Menadżer Zdarzeń a pluginy w Zend Framework 1
Można powiedzieć, że Event Manager jest uogólnieniem systemu pluginów znanego z ZF1. Jeśli pamiętasz poniższy schemat:
Wywoływanie zdarzeń
Wszystkie zdarzenia wywoływane są w kontekście określonego obiektu. Powiemy: obiekt klasy Zend\Mvc\Application wywołuje zdarzenie "dispatch", obiekt klasy Zend\Module\Manager wywołue zdarzenie "loadModule", itp.
Jako przykład, wyobraźmy sobie bardzo prosty silnik blogowy:
class BlogEngine
{
public $article;
public function renderArticle()
{
echo $this->article;
}
}
Zależy nam, aby udostępnić innym programistom możliwość filtrowania artykułu przed wysłaniem go do przeglądarki, co osiągniemy poprzez dodanie Event Managera do powyższej klasy. Metoda renderArticle wywoła zdarzenie o tej samej nazwie (zgodnie z konwencją spotykaną w źródłach ZF2), co pozwoli na zmianę treści, zanim ta zostanie wysłana.
use Zend\EventManager\EventCollection,
Zend\EventManager\EventManager;
class BlogEngine
{
protected $events;
public $article;
public function events(EventCollection $events = null)
{
if (null !== $events) {
$this->events = $events;
} elseif (null === $this->events) {
$this->events = new EventManager(__CLASS__);
}
return $this->events;
}
public function renderArticle()
{
$this->events()->trigger('renderArticle', $this);
echo $this->article;
}
}
Metoda events() umożliwia dostęp do Menadżera zdarzeń. Używamy jej w funkcji renderArticle(), aby wywołać zdarzenie bezpośrednio przed instrukcją echo.
Nasłuchiwanie zdarzeń
Zdarzenie wywołane w poprzednim paragrafie będzie bezużyteczne, dopóki nie podepniemy do niego jakiegoś kodu. Załóżmy, że chcemy utworzyć filtr, który usunie wszystkie znaczniki HTML, a potem zamieni przejścia do nowej linii na tagi <br>:
$blogEngine = new BlogEngine();
$blogEngine->events()->attach('renderArticle', function($event) {
$target = $event->getTarget();
$target->article = strip_tags($target->article);
$target->article = nl2br($target->article);
});
/* ... */
$blogEngine->renderArticle();
Funkcje obsługi zdarzeń możemy przypinać statycznie - to znaczy w momencie gdy nie posiadamy jeszcze obiektu klasy wywołującej zdarzenia. Wykorzystujemy do tego klasę Zend\EventManager\StaticEventManager. Poniższy kod da dokładnie taki sam efekt:
$events = StaticEventManager::getInstance();
$events->attach('BlogEngine', 'renderArticle', function($event) {
$target = $event->getTarget();
$target->article = strip_tags($target->article);
$target->article = nl2br($target->article);
});
/* ... */
$blogEngine = new BlogEngine();
$blogEngine->renderArticle();
Pierwszy parameter metody attach ("BlogEngine") jest to identyfikator obiektu który wywołuje zdarzenie. Konwencja zaleca używanie nazywy klasy, jednak można też zdefiniować inne identyfikatory:
$this->events = new EventManager(array('MyNamespace\Foo\Bar\BlogEngine', 'blog'));
/* ... */
$events->attach('blog', 'renderArticle', function($event) {
$target = $event->getTarget();
$target->article = strip_tags($target->article);
$target->article = nl2br($target->article);
});
Zend\EventManager\Event
Funkcja obsługi zdarzenia przyjmuje pojedynczy parametr: obiekt klasy Zend\EventManager\Event. Udostępnia on kilka przydatnych metod:
- getTarget() - zwraca obiekt wywołujący zdarzenie
- getParam() i setParam() - pozwalają na przekazywanie dodatkowych parametrów
- stopPropagation() - użycie tej metody przerwie wywoływanie kolejnych funkcji podpiętych pod dane zdarzenie.
Podsumowanie
Więcej informacji na temat Zend\EventManager znajdziesz w dokumentacji, która dostarcza też kilku przykładów.



Niestety piszę ten artykuł dużo później niż chciałem. Przyczyną jest dosyć spory projekt nad którym pracowałem przez ostatnie dwa miesiące. Zlecenie było bardzo ciekawe, więc mam nadzieję że będę mógł wkrótce coś o nim napisać.