Rzut okiem na Zend Framework 2: Event Manager

by Mateusz Tymek — on Zend Framework, PHP

Head's up! This post was written back in 2011 and is very likely to contain outdated information.

Logo ZF2

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.


comments powered by Disqus