EventManager
in Zend Framework 2 from the Matthew Weier O'Phinney blog .Zend\EventManager
, how to use it, what advantages are provided by the event method of solving programmer tasks in PHP. About what's waiting for us in ZF2.EventManager
class.EventManager::trigger()
to initiate event handling. use Zend\EventManager\EventManager; $events = new EventManager(); $events->attach('do', function($e) { $event = $e->getName(); $params = $e->getParams(); printf( 'Handled event "%s", with parameters %s', $event, json_encode($params) ); }); $params = array('foo' => 'bar', 'baz' => 'bat'); $events->trigger('do', null, $params);
Handled event "do", with parameters {"foo": "bar", "baz": "bat"}
Note: The examples use an anonymous function, but you can use the name of a function, a static class method, or an object method.
$events->trigger()
method?EventManager
object EventManager
used within a class, and an event is triggered within a method of this class. And this second argument is the "context", or the "target", and in the described case, would be an instance of this class. This provides access for event handlers to the request object, which can sometimes be useful / necessary. use Zend\EventManager\EventCollection, Zend\EventManager\EventManager; class Example { protected $events; public function setEventManager(EventCollection $events) { $this->events = $events; } public function events() { if (!$this->events) { $this->setEventManager(new EventManager( array(__CLASS__, get_called_class()) ); } return $this->events; } public function do($foo, $baz) { $params = compact('foo', 'baz'); $this->events()->trigger(__FUNCTION__, $this, $params); } } $example = new Example(); $example->events()->attach('do', 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) ); }); $example->do('bar', 'bat');
trigger()
method we pass to the handler context (the object - which started the processing of this event), and the handler receives it through the $e->getTarget()
method - and can do something with it (within a reasonable :)).EventCollection
?EventManager
constructor?EventCollection
interface was developed that describes an object capable of aggregating listeners into events and initiating these events. EventManager
is a standard implementation that will go into ZF2.StaticEventCollection
. This class allows you to attach handlers not only to named events, but also to events initiated by a specific context or purpose. EventManager
, when processing events, also takes event handlers (subscribed to the current context) from the StaticEventCollection
object and executes them. use Zend\EventManager\StaticEventManager; $events = StaticEventManager::getInstance(); $events->attach('Example', 'do', 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) ); });
attach()
method, we pass the context - 'Example', to which we want to attach our handler. In other words, when processing the 'do' event, if this event is triggered by the context of 'Example', then we call our handler.EventManager
constructor EventManager
play a role. The constructor allows you to pass a string, or an array of strings, specifying the name / names of contexts for which you need to take event handlers from the StaticEventManager
. If an array of contexts is passed, then all event handlers from these contexts will be executed. Event handlers attached directly to the EventManager
will be executed before the handlers defined in the StaticEventManager
. $example = new Example(); $example->do('bar', 'bat');
Handled event "do" on target "Example", with parameters {"foo": "bar", "baz": "bat"}
class SubExample extends Example { }
EventManager
constructor - this is an array of __CLASS__
and get_called_class()
. This means that when you call the do()
method of the SubExample
class, our event handler will also execute. If we specified only 'SubExample' in the constructor, then our handler will be executed only with SubExample::do()
, but not with Example::do()
.null
parameter to the setStaticConnections()
method: $events->setStaticConnections(null);
$events->setStaticConnections(StaticEventManager::getInstance());
HandlerAggregate
interface in your handler class. This interface defines 2 methods of attach(EventCollection $events)
and detach(EventCollection $events)
. use Zend\EventManager\Event, Zend\EventManager\EventCollection, Zend\EventManager\HandlerAggregate, Zend\Log\Logger; class LogEvents implements HandlerAggregate { protected $handlers = array(); protected $log; public function __construct(Logger $log) { $this->log = $log; } public function attach(EventCollection $events) { $this->handlers[] = $events->attach('do', array($this, 'log')); $this->handlers[] = $events->attach('doSomethingElse', array($this, 'log')); } public function detach(EventCollection $events) { foreach ($this->handlers as $key => $handler) { $events->detach($handler); unset($this->handlers[$key]; } $this->handlers = array(); } public function log(Event $e) { $event = $e->getName(); $params = $e->getParams(); $log->info(sprintf('%s: %s', $event, json_encode($params))); } }
$doLog = new LogEvents($logger); $events->attachAggregate($doLog);
LogEvents
) has to handle will be processed by the corresponding class method. This allows you to define “complex” event handlers in one place (stateful handlers).detach()
method. Just like attach()
, it takes an EventManager
object as an argument, and “detaches” all handlers (from our array of handlers - $this->handlers[]
) from the event manager. This is possible because EventManager::attach()
returns an object representing the handler - which we 'attached' earlier in the LogEvents::attach()
method.EventManager
returns a ResponseCollection
object. This class is inherited from the SplStack
class, and gives you access to the results of all handlers (the result of the last handler will be at the beginning of the result stack).ResponseCollection
addition to the SplStack
methods, SplStack
has additional methods:first()
is the result of the first handlerlast()
- the result of the execution of the last handlercontains($value)
- checking for the presence of a result in the result stack, returns true
/ false
.EventManager
. At the beginning of your method, you initiate a “search data in cache” event, and if one of the handlers finds the necessary data in the responsible cache, the rest of the handlers are interrupted, and you return the data obtained from the cache. If it does not, then you generate the data, and trigger the “write to cache” event.EventManager
provides two ways to do this. The first way is to use a special method triggerUntil()
, which checks the result of each handler executed, and if the result meets certain requirements, then the execution of subsequent handlers is interrupted. public function someExpensiveCall($criteria1, $criteria2) { $params = compact('criteria1', 'criteria2'); $results = $this->events()->triggerUntil(__FUNCTION__, $this, $params, function ($r) { return ($r instanceof SomeResultClass); }); if ($results->stopped()) { return $results->last(); } // ... do some work ... }
triggerUntil()
method are similar to the arguments to the trigger()
method, with the exception of the optional argument at the end - the callback function, which checks the result of each handler, and if it returns true
, then the subsequent handlers are interrupted.stopPropagation(true)
method in the body of the handler itself. What will cause the event manager to stop the execution of subsequent handlers. $events->attach('do', function ($e) { $e->stopPropagation(); return new SomeResultClass(); });
EventManager::attach()
and StaticEventManager::attach()
have an optional priority
argument (it defaults to 1) with which you can control the priority of the execution of handlers. A handler with a higher priority is executed before handlers with a lower priority. $priority = 100; $events->attach('Example', 'do', 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) ); }, $priority);
__FUNCTION__
as an event name in his examples, and considers it a good practice because it allows you to easily write a macro to trigger events, and also allows you to uniquely determine the uniqueness of these names (especially as the context is usually the event). And for the separation of events caused by one method, use the postfixes like “do.pre”, “do.post”, “do.error”, etc.$params
passed to the event is a list of arguments passed to the method. This is because the arguments may not be stored in the object, and handlers may not get the parameters they need from the context. But the question remains, what is the name of the result parameter for the event that writes to the cache? The example uses __RESULT__
, which is convenient, since double underlining on both sides is usually reserved by the system. public function someExpensiveCall($criteria1, $criteria2) { $params = compact('criteria1', 'criteria1'); $results = $this->events()->triggerUntil(__FUNCTION__ . '.pre', $this, $params, function ($r) { return ($r instanceof SomeResultClass); }); if ($results->stopped()) { return $results->last(); } // ... do some work ... $params['__RESULT__'] = $calculatedResult; $this->events()->trigger(__FUNCTION__ . '.post', $this, $params); return $calculatedResult; }
$cache
variable is defined earlier, and is similar to the Zend_Cache object. For the 'someExpensiveCall.pre' handler, we set the priority to 100 to ensure that the handler is faster than others, and for 'someExpensiveCall.post', the priority is -100, in case other handlers want to modify the data before writing to the cache. $events->attach('someExpensiveCall.pre', function($e) use ($cache) { $params = $e->getParams(); $key = md5(json_encode($params)); $hit = $cache->load($key); return $hit; }, 100); $events->attach('someExpensiveCall.post', function($e) use ($cache) { $params = $e->getParams(); $result = $params['__RESULT__']; unset($params['__RESULT__']); $key = md5(json_encode($params)); $cache->save($result, $key); }, -100);
Note: we could defineHandlerAggregate
, and store$cache
in a class property, and not import it into an anonymous function.
EventManager
is a new and powerful addition to the Zend Framework. It is already being used with the new MVC prototype to expand the capabilities of some of its aspects. After the release of ZF2 event model, I am sure, will be very much in demand.Source: https://habr.com/ru/post/131077/
All Articles