| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect1 id="zend.event-manager.event-manager">
- <title>The EventManager</title>
-
- <sect2 id="zend.event-manager.event-manager.intro">
- <title>Overview</title>
- <para>
- <classname>Zend_EventManager</classname> is a component designed for the following use
- cases:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Implementing simple subject/observer patterns.
- </para>
- </listitem>
- <listitem>
- <para>
- Implementing Aspect-Oriented designs.
- </para>
- </listitem>
- <listitem>
- <para>
- Implementing event-driven architectures.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- The basic architecture allows you to attach and detach listeners to named events, both on
- a per-instance basis as well as statically; trigger events; and interrupt execution of
- listeners.
- </para>
- </sect2>
-
- <sect2 id="zend.event-manager.event-manager.quick-start">
- <title>Quick Start</title>
- <para>
- Typically, you will compose a <classname>Zend_EventManager_EventManager</classname> instance in a class.
- </para>
- <programlisting language="php"><![CDATA[
- class Foo
- {
- protected $events;
- public function events(Zend_EventManager_EventCollection $events = null)
- {
- if (null !== $events) {
- $this->events = $events;
- } elseif (null === $this->events) {
- $this->events = new Zend_EventManager_EventManager(__CLASS__);
- }
- return $this->events;
- }
- }
- ]]></programlisting>
- <para>
- The above allows users to access the <classname>EventManager</classname> instance, or
- reset it with a new instance; if one does not exist, it will be lazily instantiated
- on-demand.
- </para>
- <para>
- An <classname>EventManager</classname> is really only interesting if it triggers some
- events. Basic triggering takes three arguments: the event name, which is usually the
- current function/method name; the "context", which is usually the current object
- instance; and the arguments, which are usually the arguments provided to the current
- function/method.
- </para>
- <programlisting language="php"><![CDATA[
- class Foo
- {
- // ... assume events definition from above
- public function bar($baz, $bat = null)
- {
- $params = compact('baz', 'bat');
- $this->events()->trigger(__FUNCTION__, $this, $params);
- }
- }
- ]]></programlisting>
- <para>
- In turn, triggering events is only interesting if something is listening for the event.
- Listeners attach to the <classname>EventManager</classname>, specifying a named event
- and the callback to notify. The callback receives a <classname>Zend_EventManager_Event</classname>
- object, which has accessors for retrieving the event name, context, and parameters.
- Let's add a listener, and trigger the event.
- </para>
- <programlisting language="php"><![CDATA[
- $log = Zend_Log::factory($someConfig);
- $foo = new Foo();
- $foo->events()->attach('bar', function ($e) use ($log) {
- $event = $e->getName();
- $target = get_class($e->getTarget());
- $params = json_encode($e->getParams());
- $log->info(sprintf(
- '%s called on %s, using params %s',
- $event,
- $target,
- $params
- ));
- });
- // Results in log message:
- $foo->bar('baz', 'bat');
- // reading: bar called on Foo, using params {"baz" : "baz", "bat" : "bat"}"
- ]]></programlisting>
- <para>
- Note that the second argument to <methodname>attach()</methodname> is any valid callback;
- an anonymous function is shown in the example in order to keep the example
- self-contained. However, you could also utilize a valid function name, a functor, a
- string referencing a static method, or an array callback with a named static method or
- instance method. Again, any PHP callback is valid.
- </para>
- <para>
- Sometimes you may want to specify listeners without yet having an object instance of the
- class composing an <classname>EventManager</classname>. The
- <classname>Zend_EventManager_StaticEventManager</classname> allows you to do this. The call to
- <methodname>attach</methodname> is identical to the <classname>EventManager</classname>,
- but expects an additional parameter at the beginning: a named instance. Remember the
- example of composing an <classname>EventManager</classname>, how we passed it
- <constant>__CLASS__</constant>? That value, or any strings you provide in an array to
- the constructor, may be used to identify an instance when using the
- <classname>StaticEventManager</classname>. As an example, we could change the above
- example to attach statically:
- </para>
- <programlisting language="php"><![CDATA[
- $log = Zend_Log::factory($someConfig);
- $events = Zend_EventManager_StaticEventManager::getInstance();
- $events->attach('Foo', 'bar', function ($e) use ($log) {
- $event = $e->getName();
- $target = get_class($e->getTarget());
- $params = json_encode($e->getParams());
- $log->info(sprintf(
- '%s called on %s, using params %s',
- $event,
- $target,
- $params
- ));
- });
- // Later, instantiate Foo:
- $foo = new Foo();
- // And we can still trigger the above event:
- $foo->bar('baz', 'bat');
- // results in log message:
- // bar called on Foo, using params {"baz" : "baz", "bat" : "bat"}"
- ]]></programlisting>
- <para>
- The <classname>EventManager</classname> also provides the ability to detach listeners,
- short-circuit execution of an event either from within a listener or by testing return
- values of listeners, test and loop through the results returned by listeners, prioritize
- listeners, and more. Many of these features are detailed in the examples.
- </para>
-
- <sect3 id="zend.event-manager.event-manager.quick-start.wildcard">
- <title>Wildcard Listeners</title>
- <para>
- Sometimes you'll want to attach the same listener to many events or to all events of
- a given instance -- or potentially, with the static manager, many contexts, and many
- events. The <classname>EventManager</classname> component allows for this.
- </para>
- <example id="zend.event-manager.event-manager.quick-start.wildcard.many">
- <title>Attaching to many events at once</title>
- <programlisting language="php"><![CDATA[
- $events = new Zend_EventManager_EventManager();
- $events->attach(array('these', 'are', 'event', 'names'), $callback);
- ]]></programlisting>
- <para>
- Note that if you specify a priority, that priority will be used for all events
- specified.
- </para>
- </example>
- <example id="zend.event-manager.event-manager.quick-start.wildcard.wildcard">
- <title>Attaching using the wildcard</title>
- <programlisting language="php"><![CDATA[
- $events = new Zend_EventManager_EventManager();
- $events->attach('*', $callback);
- ]]></programlisting>
- <para>
- Note that if you specify a priority, that priority will be used for this
- listener for any event triggered.
- </para>
- <para>
- What the above specifies is that <emphasis>any</emphasis> event triggered will
- result in notification of this particular listener.
- </para>
- </example>
- <example id="zend.event-manager.event-manager.quick-start.wildcard.static-many">
- <title>Attaching to many events at once via the StaticEventManager</title>
- <programlisting language="php"><![CDATA[
- $events = Zend_EventManager_StaticEventManager::getInstance();
- // Attach to many events on the context "foo"
- $events->attach('foo', array('these', 'are', 'event', 'names'), $callback);
- // Attach to many events on the contexts "foo" and "bar"
- $events->attach(array('foo', 'bar'), array('these', 'are', 'event', 'names'), $callback);
- ]]></programlisting>
- <para>
- Note that if you specify a priority, that priority will be used for all events
- specified.
- </para>
- </example>
- <example id="zend.event-manager.event-manager.quick-start.wildcard.static-wildcard">
- <title>Attaching to many events at once via the StaticEventManager</title>
- <programlisting language="php"><![CDATA[
- $events = Zend_EventManager_StaticEventManager::getInstance();
- // Attach to all events on the context "foo"
- $events->attach('foo', '*', $callback);
- // Attach to all events on the contexts "foo" and "bar"
- $events->attach(array('foo', 'bar'), '*', $callback);
- ]]></programlisting>
- <para>
- Note that if you specify a priority, that priority will be used for all events
- specified.
- </para>
- <para>
- The above is specifying that for the contexts "foo" and "bar", the specified
- listener should be notified for any event they trigger.
- </para>
- </example>
- </sect3>
- </sect2>
-
- <sect2 id="zend.event-manager.event-manager.options">
- <title>Configuration Options</title>
-
- <variablelist>
- <title>Zend_EventManager_EventManager Options</title>
-
- <varlistentry>
- <term>identifier</term>
-
- <listitem>
- <para>
- A string or array of strings to which the given
- <classname>EventManager</classname> instance can answer when accessed via
- the <classname>StaticEventManager</classname>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>event_class</term>
-
- <listitem>
- <para>
- The name of an alternate <classname>Zend_EventManager_Event</classname> class to use for
- representing events passed to listeners.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>static_connections</term>
-
- <listitem>
- <para>
- An instance of a <interfacename>Zend_EventManager_StaticEventCollection</interfacename>
- instance to use when triggering events. By default, this will use
- the global <classname>Zend_EventManager_StaticEventManager</classname> instance, but that can
- be overridden by passing a value to this method. A <constant>null</constant>
- value will prevent the instance from triggering any further statically
- attached listeners.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </sect2>
-
- <sect2 id="zend.event-manager.event-manager.methods">
- <title>Available Methods</title>
-
- <variablelist>
- <varlistentry id="zend.event-manager.event-manager.methods.constructor">
- <term>__construct</term>
- <listitem>
- <methodsynopsis>
- <methodname>__construct</methodname>
- <methodparam>
- <funcparams>null|string|int $identifier</funcparams>
- </methodparam>
- </methodsynopsis>
- <para>
- Constructs a new <classname>EventManager</classname> instance, using the
- given identifier, if provided, for purposes of static attachment.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="zend.event-manager.event-manager.methods.set-event-class">
- <term>setEventClass</term>
- <listitem>
- <methodsynopsis>
- <methodname>setEventClass</methodname>
- <methodparam>
- <funcparams>string $class</funcparams>
- </methodparam>
- </methodsynopsis>
- <para>
- Provide the name of an alternate <classname>Zend_EventManager_Event</classname> class to use
- when creating events to pass to triggered listeners.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="zend.event-manager.event-manager.methods.set-static-connections">
- <term>setStaticConnections</term>
- <listitem>
- <methodsynopsis>
- <methodname>setStaticConnections</methodname>
- <methodparam>
- <funcparams>Zend_EventManager_StaticEventCollection $connections = null</funcparams>
- </methodparam>
- </methodsynopsis>
- <para>
- An instance of a <interfacename>Zend_EventManager_StaticEventCollection</interfacename>
- instance to use when triggering events. By default, this will use
- the global <classname>Zend_EventManager_StaticEventManager</classname> instance, but that can
- be overridden by passing a value to this method. A <constant>null</constant>
- value will prevent the instance from triggering any further statically
- attached listeners.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="zend.event-manager.event-manager.methods.get-static-connections">
- <term>getStaticConnections</term>
- <listitem>
- <methodsynopsis>
- <methodname>getStaticConnections</methodname>
- <void/>
- </methodsynopsis>
- <para>
- Returns the currently attached
- <interfacename>Zend_EventManager_StaticEventCollection</interfacename> instance, lazily
- retrieving the global <classname>Zend_EventManager_StaticEventManager</classname> instance if
- none is attached and usage of static listeners hasn't been disabled by
- passing a <constant>null</constant> value to <link
- linkend="zend.event-manager.event-manager.methods.set-static-connections">setStaticConnections()</link>.
- Returns either a boolean <constant>false</constant> if static listeners are
- disabled, or a <interfacename>StaticEventCollection</interfacename> instance
- otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="zend.event-manager.event-manager.methods.trigger">
- <term>trigger</term>
- <listitem>
- <methodsynopsis>
- <methodname>trigger</methodname>
- <methodparam>
- <funcparams>string $event, mixed $target, mixed $argv, callback $callback</funcparams>
- </methodparam>
- </methodsynopsis>
- <para>
- Triggers all listeners to a named event. The recommendation is to use the
- current function/method name for <varname>$event</varname>, appending it
- with values such as ".pre", ".post", etc. as needed.
- <varname>$context</varname> should be the current object instance, or the
- name of the function if not triggering within an object.
- <varname>$params</varname> should typically be an associative array or
- <classname>ArrayAccess</classname> instance; we recommend using the
- parameters passed to the function/method (<function>compact()</function> is
- often useful here). This method can also take a callback and behave in the
- same way as <methodname>triggerUntil()</methodname>.
- </para>
- <para>
- The method returns an instance of <classname>Zend_EventManager_ResponseCollection</classname>,
- which may be used to introspect return values of the various listeners, test
- for short-circuiting, and more.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="zend.event-manager.event-manager.methods.trigger-until">
- <term>triggerUntil</term>
- <listitem>
- <methodsynopsis>
- <methodname>triggerUntil</methodname>
- <methodparam>
- <funcparams>string $event, mixed $context, mixed $argv, callback
- $callback</funcparams>
- </methodparam>
- </methodsynopsis>
- <para>
- Triggers all listeners to a named event, just like <link
- linkend="zend.event-manager.event-manager.methods.trigger">trigger()</link>,
- with the addition that it passes the return value from each listener to
- <varname>$callback</varname>; if <varname>$callback</varname> returns a
- boolean <constant>true</constant> value, execution of the listeners is
- interrupted. You can test for this using <code>$result->stopped()</code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="zend.event-manager.event-manager.methods.attach">
- <term>attach</term>
- <listitem>
- <methodsynopsis>
- <methodname>attach</methodname>
- <methodparam>
- <funcparams>string $event, callback $callback, int $priority</funcparams>
- </methodparam>
- </methodsynopsis>
- <para>
- Attaches <varname>$callback</varname> to the
- <classname>Zend_EventManager_EventManager</classname> instance, listening for the event
- <varname>$event</varname>. If a <varname>$priority</varname> is provided,
- the listener will be inserted into the internal listener stack using that
- priority; higher values execute earliest. (Default priority is "1", and
- negative priorities are allowed.)
- </para>
- <para>
- The method returns an instance of
- <classname>Zend_Stdlib_CallbackHandler</classname>; this value can later be
- passed to <methodname>detach()</methodname> if desired.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="zend.event-manager.event-manager.methods.attach-aggregate">
- <term>attachAggregate</term>
- <listitem>
- <methodsynopsis>
- <methodname>attachAggregate</methodname>
- <methodparam>
- <funcparams>string|Zend_EventManager_ListenerAggregate $aggregate</funcparams>
- </methodparam>
- </methodsynopsis>
- <para>
- If a string is passed for <varname>$aggregate</varname>, instantiates that
- class. The <varname>$aggregate</varname> is then passed the
- <classname>EventManager</classname> instance to its
- <methodname>attach()</methodname> method so that it may register listeners.
- </para>
- <para>
- The <classname>ListenerAggregate</classname> instance is returned.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="zend.event-manager.event-manager.methods.detach">
- <term>detach</term>
- <listitem>
- <methodsynopsis>
- <methodname>detach</methodname>
- <methodparam>
- <funcparams>Zend_Stdlib_CallbackHandler $listener</funcparams>
- </methodparam>
- </methodsynopsis>
- <para>
- Scans all listeners, and detaches any that match <varname>$listener</varname>
- so that they will no longer be triggered.
- </para>
- <para>
- Returns a boolean <constant>true</constant> if any listeners have been
- identified and unsubscribed, and a boolean <constant>false</constant>
- otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="zend.event-manager.event-manager.methods.detach-aggregate">
- <term>detachAggregate</term>
- <listitem>
- <methodsynopsis>
- <methodname>detachAggregate</methodname>
- <methodparam>
- <funcparams>Zend_EventManager_ListenerAggregate $aggregate</funcparams>
- </methodparam>
- </methodsynopsis>
- <para>
- Loops through all listeners of all events to identify listeners that are
- represented by the aggregate; for all matches, the listeners will be removed.
- </para>
- <para>
- Returns a boolean <constant>true</constant> if any listeners have been
- identified and unsubscribed, and a boolean <constant>false</constant>
- otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="zend.event-manager.event-manager.methods.get-events">
- <term>detachAggregate</term>
- <listitem>
- <methodsynopsis>
- <methodname>getEvents</methodname>
- <void/>
- </methodsynopsis>
- <para>
- Returns an array of all event names that have listeners attached.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="zend.event-manager.event-manager.methods.get-listeners">
- <term>getListeners</term>
- <listitem>
- <methodsynopsis>
- <methodname>getListeners</methodname>
- <methodparam>
- <funcparams>string $event</funcparams>
- </methodparam>
- </methodsynopsis>
- <para>
- Returns a <classname>Zend_Stdlib_PriorityQueue</classname> instance of all
- listeners attached to <varname>$event</varname>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="zend.event-manager.event-manager.methods.clear-listeners">
- <term>clearListeners</term>
- <listitem>
- <methodsynopsis>
- <methodname>clearListeners</methodname>
- <methodparam>
- <funcparams>string $event</funcparams>
- </methodparam>
- </methodsynopsis>
- <para>
- Removes all listeners attached to <varname>$event</varname>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="zend.event-manager.event-manager.methods.prepare-args">
- <term>prepareArgs</term>
- <listitem>
- <methodsynopsis>
- <methodname>prepareArgs</methodname>
- <methodparam>
- <funcparams>array $args</funcparams>
- </methodparam>
- </methodsynopsis>
- <para>
- Creates an <classname>ArrayObject</classname> from the provided
- <varname>$args</varname>. This can be useful if you want yours listeners
- to be able to modify arguments such that later listeners or the triggering
- method can see the changes.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </sect2>
-
- <sect2 id="zend.event-manager.event-manager.examples">
- <title>Examples</title>
-
- <example id="zend.event-manager.event-manager.examples.modifying-args">
- <title>Modifying Arguments</title>
-
- <para>
- Occasionally it can be useful to allow listeners to modify the arguments they
- receive so that later listeners or the calling method will receive those changed
- values.
- </para>
- <para>
- As an example, you might want to pre-filter a date that you know will arrive as a
- string and convert it to a <classname>DateTime</classname> argument.
- </para>
- <para>
- To do this, you can pass your arguments to <methodname>prepareArgs()</methodname>,
- and pass this new object when triggering an event. You will then pull that value
- back into your method.
- </para>
-
- <programlisting language="php"><![CDATA[
- class ValueObject
- {
- // assume a composed event manager
- function inject(array $values)
- {
- $argv = compact('values');
- $argv = $this->events()->prepareArgs($argv);
- $this->events()->trigger(__FUNCTION__, $this, $argv);
- $date = isset($argv['values']['date']) ? $argv['values']['date'] : new DateTime('now');
- // ...
- }
- }
- $v = new ValueObject();
- $v->events()->attach('inject', function($e) {
- $values = $e->getParam('values');
- if (!$values) {
- return;
- }
- if (!isset($values['date'])) {
- $values['date'] = new DateTime('now');
- return;
- }
- $values['date'] = new Datetime($values['date']);
- });
- $v->inject(array(
- 'date' => '2011-08-10 15:30:29',
- ));
- ]]></programlisting>
- </example>
- <example id="zend.event-manager.event-manager.examples.short-circuiting">
- <title>Short Circuiting</title>
-
- <para>
- One common use case for events is to trigger listeners until either one indicates no
- further processing should be done, or until a return value meets specific criteria.
- As examples, if an event creates a Response object, it may want execution to stop.
- </para>
- <programlisting language="php"><![CDATA[
- $listener = function($e) {
- // do some work
-
- // Stop propagation and return a response
- $e->stopPropagation(true);
- return $response;
- };
- ]]></programlisting>
- <para>
- Alternately, we could do the check from the method triggering the event.
- </para>
-
- <programlisting language="php"><![CDATA[
- class Foo implements Dispatchable
- {
- // assume composed event manager
- public function dispatch(Request $request, Response $response = null)
- {
- $argv = compact('request', 'response');
- $results = $this->events()->triggerUntil(__FUNCTION__, $this, $argv, function($v) {
- return ($v instanceof Response);
- });
- }
- }
- ]]></programlisting>
- <para>
- Typically, you may want to return a value that stopped execution, or use it some
- way. Both <methodname>trigger()</methodname> and
- <methodname>triggerUntil()</methodname> return a
- <classname>Zend_EventManager_ResponseCollection</classname> instance; call its
- <methodname>stopped()</methodname> method to test if execution was stopped, and
- <methodname>last()</methodname> method to retrieve the return value from the last
- executed listener:
- </para>
-
- <programlisting language="php"><![CDATA[
- class Foo implements Dispatchable
- {
- // assume composed event manager
- public function dispatch(Request $request, Response $response = null)
- {
- $argv = compact('request', 'response');
- $results = $this->events()->triggerUntil(__FUNCTION__, $this, $argv, function($v) {
- return ($v instanceof Response);
- });
- // Test if execution was halted, and return last result:
- if ($results->stopped()) {
- return $results->last();
- }
- // continue...
- }
- }
- ]]></programlisting>
- </example>
- <example id="zend.event-manager.event-manager.examples.priority">
- <title>Assigning Priority to Listeners</title>
-
- <para>
- One use case for the <classname>EventManager</classname> is for implementing caching
- systems. As such, you often want to check the cache early, and save to it late.
- </para>
- <para>
- The third argument to <methodname>attach()</methodname> is a priority value. The
- higher this number, the earlier that listener will execute; the lower it is, the
- later it executes. The value defaults to 1, and values will trigger in the order
- registered within a given priority.
- </para>
- <para>
- So, to implement a caching system, our method will need to trigger an event at
- method start as well as at method end. At method start, we want an event that will
- trigger early; at method end, an event should trigger late.
- </para>
- <para>
- Here is the class in which we want caching:
- </para>
- <programlisting language="php"><![CDATA[
- class SomeValueObject
- {
- // assume it composes an event manager
- public function get($id)
- {
- $params = compact('id');
- $results = $this->events()->trigger('get.pre', $this, $params);
- // If an event stopped propagation, return the value
- if ($results->stopped()) {
- return $results->last();
- }
- // do some work...
- $params['__RESULT__'] = $someComputedContent;
- $this->events()->trigger('get.post', $this, $params);
- }
- }
- ]]></programlisting>
- <para>
- Now, let's create a <interfacename>ListenerAggregate</interfacename> that can handle
- caching for us:
- </para>
- <programlisting language="php"><![CDATA[
- class CacheListener implements Zend_EventManager_ListenerAggregate
- {
- protected $cache;
- public function __construct(Cache $cache)
- {
- $this->cache = $cache;
- }
- public function attach(Zend_EventManager_EventCollection $events)
- {
- $events->attach('get.pre', array($this, 'load'), 100);
- $events->attach('get.post', array($this, 'save'), -100);
- }
- public function load($e)
- {
- $id = get_class($e->getTarget()) . '-' . json_encode($e->getParams());
- if (false !== ($content = $this->cache->load($id))) {
- $e->stopPropagation(true);
- return $content;
- }
- }
- public function save($e)
- {
- $params = $e->getParams();
- $content = $params['__RESULT__'];
- unset($params['__RESULT__']);
- $id = get_class($e->getTarget()) . '-' . json_encode($params);
- $this->cache->save($content, $id);
- }
- }
- ]]></programlisting>
- <para>
- We can then attach the aggregate to an instance.
- </para>
- <programlisting language="php"><![CDATA[
- $value = new SomeValueObject();
- $cacheListener = new CacheListener($cache);
- $value->events()->attachAggregate($cacheListener);
- ]]></programlisting>
- <para>
- Now, as we call <methodname>get()</methodname>, if we have a cached entry, it will
- be returned immediately; if not, a computed entry will be cached when we complete
- the method.
- </para>
- </example>
- </sect2>
- </sect1>
|