Slide 1

Slide 1 text

Событийная модель ZF2, EventManager Александр Вронский Smile Ukraine Email: [email protected] Site: http://alexandr.vronskiy.name

Slide 2

Slide 2 text

Событийная модель • Что это такое? • В чем преимущество? • Где использовать? • Как реализовать?

Slide 3

Slide 3 text

Событийная модель • Event (Событие) • Listener (Обработчик событий) • Event Manager (Менеджер событий)

Slide 4

Slide 4 text

Событийная модель • Событие1 – Слушатель1, 2, 3… • Событие2 – Слушатель11, 22, 33...

Slide 5

Slide 5 text

EventManager, базовая архитектура Реализует: • Паттерн subject/observer (Наблюдатель) • Аспекто-ориентированный дизайн • Событийно управляемую архитектуру

Slide 6

Slide 6 text

EventManager – простой пример use Zend\EventManager\EventManager; $events = new EventManager(); $events->attach('do', function ($e) { printf( ‘Вызвано событие "%s", с параметрами "%s"' $e->getName(), json_encode($e->getParams()) ); }); $params = array('foo' => 'bar', 'baz' => 'bat'); $events->trigger('do', null, $params); //Вызвано событие "do", с параметрами {"foo":"bar","baz":"bat"}

Slide 7

Slide 7 text

EventManager - Attach • Имя события • Слушатель (callback) • Приоритет (опционально) $events->attach('do', $callback); // приоритет по умолчанию $events->attach('do', $callback, 100); // высокий $events->attach('do', $callback, -100); // низкий

Slide 8

Slide 8 text

EventManager - Trigger • Имя события • «Цель» • Аргументы public function foo($bar, $baz) { $params = compact('bar', 'baz'); $this->events()->trigger('do', $this, $params); }

Slide 9

Slide 9 text

EventManager - Listeners • Слушатель – любой валидный PHP callback • Cлушатели получают объект-событие в качестве единственного аргумента function ($e) { $event = $e->getName(); $target = $e->getTarget(); $target = (is_object($target)) ? get_class($target) : gettype($target); $params = $e->getParams(); printf(‘Событие "%s", параметры %s, контекст "%s"', $event, json_encode($params), $target ); }

Slide 10

Slide 10 text

EventManager - Event interface EventInterface { public function setName($name); public function setTarget($target); public function setParam($name, $value); public function setParams($params); public function getName(); public function getTarget(); public function getParam($name, $default = null); public function getParams(); public function stopPropagation($flag = true); public function propagationIsStopped(); };

Slide 11

Slide 11 text

EventManager - Состав • EventManager • SharedEventManager • StaticEventManager • GlobalEventManager • ?!trait ProvidesEvents

Slide 12

Slide 12 text

EventManager - EventManagerInterface extends SharedEventManagerAwareInterface - EventManagerAwareInterface extends EventsCapableInterface

Slide 13

Slide 13 text

(Shared|Static)EventManager • Позволяет присоединять «сквозных» слушателей • Подписка на событие до создания конкретного экземпляра EventManager • Логирование, кеширование, дебаг и т.д.

Slide 14

Slide 14 text

(Shared|Static)EventManager use Zend\EventManager\StaticEventManager; $events = StaticEventManager::getInstance(); $events->attach('CoreDateModel', 'do', function($e) { $event = $e->getName(); $target = get_class($e->getTarget()); $params = $e->getParams(); printf( 'Handled event "%s" on target "%s", with parameters %s', $event, $target, json_encode($params) ); });

Slide 15

Slide 15 text

(Shared|Static)EventManager контекст • Каждый EventManager екзепляр может слушать 1 и больше контекстов • Определяем в конструкторе или с помощью метода setIdentifier()

Slide 16

Slide 16 text

Listener Aggregates class LogEvents implements ListenerAggregateInterface { protected $handlers = array(); protected $log; public function attach(EventManagerInterface $events) { $this->handlers[] = $events->attach('do',array($this,'log')); $this->handlers[] = $events->attach('doSomethingElse', array($this,'log')); } public function detach(EventManagerInterface $events) { } public function log(Event $e) { $event = $e->getName(); $params = $e->getParams(); $log->info(sprintf('%s: %s', $event, json_encode($params))); } }

Slide 17

Slide 17 text

Listener Aggregates $doLog = new LogEvents($logger); $events->attachAggregate($doLog); //или $doLog->attach($events);

Slide 18

Slide 18 text

EventManager – возврат результатов • EventManager->trigger возвращает объект ResponseCollection • Можно прервать дальнейшую обработку события

Slide 19

Slide 19 text

EventManager – возврат результатов ResponseCollection - методы SplStack, +: • first() • last() • contains($value) // true/false • stopped()

Slide 20

Slide 20 text

EventManager – возврат результатов ResponseCollection - методы SplStack, +: • first() • last() • contains($value) // true/false • stopped()

Slide 21

Slide 21 text

EventManager – возврат результатов public function someExpensiveCall($foo, $bar) { $params = compact(‘foo', 'bar'); $results = $this->events()->triggerUntil( __FUNCTION__, $this, $params, function ($r) { return ($r instanceof SomeResultClass); }); if ($results->stopped()) { return $results->last(); } // ... do some work ... }

Slide 22

Slide 22 text

EventManager – возврат результатов $listener = function ($e) { $e->stopPropagation(true); };

Slide 23

Slide 23 text

EventManager – возврат результатов $results = $events->trigger(/* ... */); if ($results->stopped()) { return $results->last(); }

Slide 24

Slide 24 text

Практика – без событий class SuperCMS_CoreDateModel { public function save($date) // “Y/d/M” public function load($id) } class Modul1_CoreDateModel { public function save($date) //override public function load($id) //override }

Slide 25

Slide 25 text

Практика – с событиями class CoreDateModel implements EventManagerAwareInterface { protected $events; const AFTER_PREFIX = 'after.'; const BEFORE_PREFIX = 'before.'; public function setEventManager(EventManagerInterface $events) { $events->setIdentifiers(array(__CLASS__,get_called_class())); $this->events = $events; return $this; } public function getEventManager() { if (null === $this->events) { $this->setEventManager(new EventManager()); } return $this->events; }

Slide 26

Slide 26 text

Практика – с событиями class CoreDateModel implements EventManagerAwareInterface { use ProvidesEvents; const AFTER_PREFIX = 'after.'; const BEFORE_PREFIX = 'before.';

Slide 27

Slide 27 text

Практика – с событиями class CoreDateModel implements EventManagerAwareInterface { use ProvidesEvents; const AFTER_PREFIX = 'after.'; const BEFORE_PREFIX = 'before.'; public function save($data){ $params = compact('data'); $params = $this->getEventManager()->prepareArgs($params); $result = $this->getEventManager()->trigger( self::BEFORE_PREFIX . __FUNCTION__, $this, $params); /* -- save in DB -- */ echo json_encode($params); $this->getEventManager()->trigger( self::AFTER_PREFIX . __FUNCTION__, $this, $params); }

Slide 28

Slide 28 text

Практика – с событиями use Zend\EventManager\StaticEventManager; $listenerModuleVasya = function($e) { $event = $e->getName(); $target = get_class($e->getTarget()); // "Example" $params = $e->getParams(); printf( 'Handled event "%s" on target "%s", with parameters %s
', $event, $target, json_encode($params) ); $dt = new DateTime(); $dt->createFromFormat('Y/d/M', $params['data']); $params['data'] = $dt->format('Y-m-d'); };

Slide 29

Slide 29 text

Практика – с событиями $listenerModuleVasya = function($e) { $event = $e->getName(); $target = get_class($e->getTarget()); // "Example" $params = $e->getParams(); printf( 'Handled event "%s" on target "%s", with parameters %s
', $event, $target, json_encode($params) ); $params['data'] = $params['data'] . ' 00:00:00'; };

Slide 30

Slide 30 text

Практика – с событиями //Где-то в бутстрапе $events = StaticEventManager::getInstance(); $events->attach('*', 'before.save', $listenerModuleVasya); $events->attach('CoreDateModel', 'before.save', $listenerModulePetya); //Где-то в контроллере $model = new CoreDateModel(); $model->getEventManager()->setSharedManager($events); $model->save('2012/24/11'); --------------- output ----------------------

Slide 31

Slide 31 text

ZF2 компоненты + Events • Zend/Cache • Zend/Db (TableGateway, RowGateway • Zend/ModuleManager • Zend/Mvc • Zend/Session • Zend/View

Slide 32

Slide 32 text

События и MVC

Slide 33

Slide 33 text

Список ZF2 events • Zend\Module\Manager: loadModules.pre • Для каждого модуля: - Zend\Module\Manager: loadModule.resolve - Zend\Module\Manager: loadModule • Zend\Module\Manager: loadModules.post Module Manager

Slide 34

Slide 34 text

Список ZF2 events • Zend\Mvc\Application: bootstrap • Zend\Mvc\Application: route • Zend\Mvc\Application: dispatch … Application

Slide 35

Slide 35 text

Список ZF2 events • Zend\Mvc\Controller\ActionController: dispatch • Zend\Mvc\Application: render • Zend\View\View: renderer • Zend\View\View: response • Zend\Mvc\Application: finish Application

Slide 36

Slide 36 text

Список ZF2 events • Zend\Mvc\Application: dispatch.error • Zend\Mvc\Application: render • Zend\View\View: renderer • Zend\View\View: response • Zend\Mvc\Application: finish Application

Slide 37

Slide 37 text

Итоги • Используйте EventManager • Используйте для базиса событийной модели в ваших приложений • …

Slide 38

Slide 38 text

Вопросы??? while(true){ $q = $this->getPoolQuestions()->pop(); if ($q === false) die(‘Goodbye!’); echo ($this->getPoolAnswers()->search($q))?:$this->saysRtfm(); echo ‘Next!’; }