On Mon, May 13, 2013 at 12:20 AM, David Muir <davidkm...@gmail.com> wrote:
> On 10/05/13 23:11, Michael Gooden wrote:
>> It should not be firing twice, however you are trying to use the shared
>> event manager the wrong way.
>>
>> If you want to have a listener fire for EVERY dispatch ever, then just
>> attach to normal event manager on EVENT_DISPATCH in one place. If you attach
>> it in the MyModule it will still fire when you access a controller in the
>> Application module. Is that what you need?
>
>
> It was more as an experiment to see what would happen. I was more confused
> by different tutorials showing listeners being attached to the EventManager
> and the SharedEventManager without explaining why one should be used over
> the other.
>
> As for firing twice, I agree, that shouldn't be happening, but
> Zend\Mvc\Application.php triggers MvcEvent::EVENT_DISPATCH on line 309 and
> Zend\Mvc\Controller\AbstractController triggers it on line 115.
> In my opinion this is a bug, and those should be two separate events, but
> there's probably not much that can be done about it now without breaking BC.

They *ARE* two separate events, that simply happen to be named the same.

What do I mean?

Each object composes its own EventManager instance. This is not
shared, and the fact that the instance is not shared is purposeful:
it's to allow each object to trigger isolated events, as well as to
prevent naming collisions. This latter is important -- you can have
the same event name in multiple objects, but they will not trigger the
same listeners due to the fact that the EM instances are separate.

If you want a listener to trigger for the same event name on different
objects, you have two choices:

- attach to each object's EM instance separately
- attach to the SharedEventManager, specifying identifiers for each object

The SharedEventManager is a shared container passed to all EM
instances that were originally pulled from the ServiceManager. This
object allows listeners to attach to events on objects with specific
identifiers; when an event is triggered, the event manager will query
the SharedEventManager to see if it has any listeners on identifiers
it is interested in that correspond to the current event; if so, it
will trigger those, too.

This explains your original question:

> Can someone explain why the shared event listener attached via the 
> Application module never gets called?

When you attached to the SharedEventManager, you were attaching the
the identifier "Application", which will only get triggered by an
object that has the identifier "Application" -- most likely, this will
be a controller, as the default controller implementations will add
their top-level namespace as an event identifier.
(Zend\Mvc\Application does not itself define that identifier, but
instead the identifier "Zend\Mvc\Application".)

You also ask the following:

> Secondary to this, I've seen some examples attach listeners to the shared 
> manager, and others attach them to the event manager. When do I use one 
> instead of the other?

The general rule of thumb is:

- If you already have direct access to an object, and want to attach
listeners to it, use its composed EventManager directly.
- If you do not already have direct access to an object, or do not
know if it will even come into scope in the current request, use the
SharedEventManager to attach listeners.

So, as concrete examples: Let's say I want to attach an event to
trigger when routing has finished. I will generally do this during the
bootstrap event from within my module. Inside a bootstrap listener, I
can access the Application instance directly via either
$e->getTarget() or $e->getApplication(). Since the route event is
triggered directly by the Application instance, I can attach directly
to its EM instance:

    $application = $e->getTarget();
    $events       = $application->getEventManager();
    $events->attach('route', $callback, -10);

Now let's say I want to attach a listener to an event triggered by a
domain model. I don't know yet if that model will be used in this
request, much less if the controller that will communicate with it
will be selected. As such, I'll use the SharedEventManager, which I
will pull from the EM instance composed in the Application instance.

    $application = $e->getTarget();
    $events       = $application->getEventManager();
    $sharedEvents = $events->getSharedManager();
    $sharedEvents->attach('My\Domain\Model', 'fetch', $callback);

Hopefully that answers the questions you have!

>
> Cheers,
> David
>
>>
>> Cheers,
>>
>> Michael
>>
>>
>>
>> On 10 May 2013 15:01, David Muir <davidkm...@gmail.com
>> <mailto:davidkm...@gmail.com>> wrote:
>>
>>     Michael,
>>
>>     Thanks for the explanation. It does explain the issue I have having.
>>
>>     So the gist is:
>>
>>>         $sharedEvents->attach(__NAMESPACE__, MvcEvent::EVENT_DISPATCH
>>>
>>
>>     means that this even will only be triggered if the context is that
>>     namespace. So the one in Application will fire if the context is
>>     "Application" and the one in MyModule will fire if the context is
>>     "MyModule".
>>
>>     So as an experiment, in Application I tried attaching a listener
>>     to 'MyModule' instead of __NAMESPACE__ and it work as expected. It
>>     only fires when hitting a controller in MyModule.
>>
>>     But what if I want to attach something that is triggered in all
>>     contexts on the dispatch event? I tried using the * wildcard, but
>>     now the shared listeners get hit twice:
>>
>>     shared event listener from application module called
>>     shared event listener from my module called
>>     event listener from application module called
>>     event listener from my module called
>>     shared event listener from application module called
>>     shared event listener from my module called
>>
>>     If my understanding is correct, this happens because there are two
>>     EventManager involved. First is the Application's EventManager,
>>     which first triggers the shared events, then triggers the local
>>     events. Then the controller itself triggers
>>     MvcEvent::EVENT_DISPATCH on its own EventManager instance when the
>>     controller's dispatch() method gets called. This in turn triggers
>>     the shared events a 2nd time.
>>
>>     I guess I got exactly what I asked for, but wasn't
>>     expecting MvcEvent::EVENT_DISPATCH to be triggered twice. Kind of
>>     feels wrong...
>>
>>     Cheers,
>>     David
>>
>>     On 10/05/2013, at 4:46 PM, Michael Gooden
>>     <mich...@bluepointweb.com <mailto:mich...@bluepointweb.com>> wrote:
>>
>>>     Hi David,
>>>
>>>     Keep in mind that you are working with the Zend\Mvc\Application's
>>>     EventManager instance. Try and follow the code execution in the
>>>     Application::run() function, to see when and why different events
>>>     fire.
>>>
>>>     I would hazard a guess and say that you are accessing a
>>>     controller in the MyModule, and not in the main Application
>>>     module. If you run a controller from the Application module, you
>>>     will then see the 'shared event from application' message show
>>>     instead of from mymodule. The reason this is happening is because
>>>     the shared event manager listener you are attaching is listening
>>>     for the event identifier of __NAMESPACE__. When the dispatch
>>>     event gets called against a controller under MyModule, only the
>>>     listener tied to the namespace of that controller will be fired.
>>>     The reason you will always see both normal event listener
>>>     messages is because those listeners are both attached to the
>>>     dispatch event.
>>>
>>>     I feel I am failing at explaining this, can you add me on Skype?
>>>
>>>     Cheers,
>>>
>>>     Michael Gooden
>>>
>>>
>>>     On 10 May 2013 03:41, David Muir <davidkm...@gmail.com
>>>     <mailto:davidkm...@gmail.com>> wrote:
>>>
>>>         I'm getting some weird behaviour with the EventManager and
>>>         SharedEventManager when used in the Application module vs
>>>         other modules.
>>>
>>>         Application Module:
>>>
>>>         public function onBootstrap(MvcEvent $e)
>>>             {
>>>         //$e->getApplication()->getServiceManager()->get('translator');
>>>                 $eventManager        =
>>>         $e->getApplication()->getEventManager();
>>>                 $moduleRouteListener = new ModuleRouteListener();
>>>         $moduleRouteListener->attach($eventManager);
>>>
>>>         $eventManager->attach(MvcEvent::EVENT_DISPATCH, function
>>>         ($event){
>>>                     echo 'event listener from application module
>>>         called' . PHP_EOL;
>>>                 });
>>>
>>>                 $sharedEvents = $eventManager->getSharedManager();
>>>
>>>         $sharedEvents->attach(__NAMESPACE__,
>>>         MvcEvent::EVENT_DISPATCH, function ($event){
>>>                     echo 'shared event listener from application
>>>         module called'. PHP_EOL;
>>>                 });
>>>
>>>             }
>>>
>>>
>>>         My Module:
>>>
>>>         public function onBootstrap(\Zend\EventManager\EventInterface $e)
>>>         {
>>>
>>>                 $eventManager        =
>>>         $e->getApplication()->getEventManager();
>>>                 $sharedEvents = $eventManager-> getSharedManager();
>>>
>>>         $eventManager->attach(MvcEvent::EVENT_DISPATCH, function
>>>         ($event){
>>>                     echo 'event listener from my module called'.PHP_EOL;
>>>                 });
>>>
>>>         $sharedEvents->attach(__NAMESPACE__,
>>>         MvcEvent::EVENT_DISPATCH, function ($event){
>>>                     echo 'shared event listener from my module
>>>         called'.PHP_EOL;
>>>                 });
>>>
>>>         }
>>>
>>>
>>>
>>>         outputs:
>>>
>>>         shared event listener from my module called
>>>         event listener from application module called
>>>         event listener from my module called
>>>
>>>
>>>         Can someone explain why the shared event listener attached
>>>         via the Application module never gets called?
>>>
>>>         Secondary to this, I've seen some examples attach listeners
>>>         to the shared manager, and others attach them to the event
>>>         manager. When do I use one instead of the other?
>>>
>>>         Cheers,
>>>         David
>>>
>>>
>>>         --
>>>         List: fw-general@lists.zend.com
>>>         <mailto:fw-general@lists.zend.com>
>>>
>>>         Info: http://framework.zend.com/archives
>>>         Unsubscribe: fw-general-unsubscr...@lists.zend.com
>>>         <mailto:fw-general-unsubscr...@lists.zend.com>
>>>
>>>
>>>
>>
>>
>



--
Matthew Weier O'Phinney
Project Lead            | matt...@zend.com
Zend Framework          | http://framework.zend.com/
PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc

-- 
List: fw-general@lists.zend.com
Info: http://framework.zend.com/archives
Unsubscribe: fw-general-unsubscr...@lists.zend.com


Reply via email to