Skip to content
This repository has been archived by the owner on Jan 29, 2020. It is now read-only.

Question - Best way for modules to attach listeners #40

Open
cgaube opened this issue Oct 26, 2016 · 8 comments
Open

Question - Best way for modules to attach listeners #40

cgaube opened this issue Oct 26, 2016 · 8 comments

Comments

@cgaube
Copy link

cgaube commented Oct 26, 2016

Hello
First my apologies if this is not the right place to ask questions.
Please let me know if there is a better place -
Thank you


Here is my issue
I was wondering what would be the best way to attach listeners to an Event Manager from a Different Module

Here is my scenario, I have a user form lets call it Application\UserForm

In its class factory I inject an Event Manager and a Shared Event Manager

factory:

$userForm = new UserForm();

$sharedEventManager = $container->get('FormSharedEventManager');
$eventManager =  new EventManager($sharedEventManager);

$userForm->setEventManager($eventManager);

What is the Best way for another module (lets call it Module X) to attach its listener to this Form (and any other forms really that use the same FormSharedEventManager ) ?

Here are my choices

Delegators

I could add Delegators in the Module X Config

Option 1: at the UserForm level
--> so that everytime UserForm is created My delegator class would fetch the event manager and directly attach listeners

Option 2
-> Same idea but at the shared event manager level
Everytime FormSharedEventManager is created i would attach the listeners
(That also allow me to use the identifiers )

Config file parameters

Option 3:
i could create a new config parameter

return [
  'shared_event_manager_listeners' => [ 
        'FormSharedEventManager::class => [
                 ModuleXFormListenersAggregate::class
         ]
  ]
];

And I would have a to use a new Factory to create FormSharedEventManager

'factories' => [
    FormSharedEventManager::class => AggregateAwareSharedEventManagerFACTORY::class
]

My new Factory (AggregateAwareSharedEventManagerFACTORY)
Would then fetch all the listeners aggregates from the "shared_event_manager_listers" config attached to the requested class (FormSharedEventManager::class)

I want to use the fastest or cleanest way to attach those listeners
Ideally the Module would also add listeners to other part of the process

Pros and Cons

Option 1:

  • Pros: The listeners are only attached when we need create UserForm class
  • Cons: Need to create a Delegator file for each forms that the module want to listen to

Option 2:

  • Pros: Using the SharedEvent Manager I can use identifiers and thus attach all my Event from ONE delegator file
  • Cons: ?

Option 3:

  • Pros: We are not using delegators - so it might be faster ? (am I right to assume so ?)
  • Cons:
    Need to create new parameter in the config, Need to create a new factory

Ideally Module X would also want to listen to other events like Controller Events
For e.g When a user submit the form Module X will want to send an email
Would it be smarter to Inject the default Shared Event Manager into my Form instead of creating a new FormSharedEventManager
and attaching the listeners into the Default shared event manager ?

@snapshotpl
Copy link
Contributor

Good question. I resolve it by creating module for that: https://github.com/snapshotpl/ZfConfigListener

@cgaube
Copy link
Author

cgaube commented Oct 27, 2016

So your module is kind-of a mix and matches of the options I described
You are using a new configuration in the module.config files that defines what listeners should be attached to what service
Then your module, during the "merge config" event, will attach a delegator to each of those services
The delegator then just fetch the listeners and attach them to the service's event manager

This is nice but you are limiting yourself to services defined in the service_manager
That would not work for my scenario because my form would be defined in the Form Element Manager (form_elements)

Thank you for your input though I am going to use it to build the perfect solution for me

@thomasvargiu
Copy link

thomasvargiu commented Oct 27, 2016

There is a big problem with delegators with zend-eventmanager >= 3.0.
Please see my issue zendframework/zend-mvc#205.

The event manager in classes that implements EventManagerAwareInterface will be overrode by an initializer in zend-mvc because it checks if getSharedManager() is an instance of SharedEventManagerInterface.

The EventManagerAwareTrait in zend-eventmanager >= 3.0 does not create the shared manager anymore, so the whole event manager will be overrode in the initializer, and after delegators, losing the attached listeners.

If you want to use delegators, you should be sure that a complete event manager with the shared event manager is injected in the object.

@cgaube
Copy link
Author

cgaube commented Oct 27, 2016

If you want to use delegators, you should be sure that a complete event manager with the shared event manager is injected in the object.

This is what I was planning to do anyway, because like you said, the SharedEvent Manager is not injected to any event manager by default anymore -

See my first comment

$userForm = new UserForm();

$sharedEventManager = $container->get('FormSharedEventManager');
$eventManager =  new EventManager($sharedEventManager);

$userForm->setEventManager($eventManager);

Doing so allow you to have full control on the event manager
I like also like to create an Event Class eventPrototype for each Event Managers -
For e.g My Event Manager injected in my UserForm use a new Event Type called \FormEvent
and not \Zend\EventManager\Event

$eventManager->setEventPrototype( new FormEvent() );

@thomasvargiu
Copy link

thomasvargiu commented Oct 27, 2016

Why would you use another SharedEventManager instance for your service?

You can do something like this with zend-mvc:

$userForm = new UserForm();

// zend-mvc defines the 'EventManager' not shared, creating a new EventManager each time
$eventManager =  $container->get('EventManager');

$userForm->setEventManager($eventManager);

For libraries without zend-mvc I would suggest something like this:

$userForm = new UserForm();

// zend-mvc defines the 'SharedEventManager'
$sharedEventManager = $container->has('SharedEventManager') ? $container->get('SharedEventManager') : null;
$eventManager =  new EventManager($sharedEventManager);

$userForm->setEventManager($eventManager);

In this way you can use the default SharedEventManager, using the identifiers.

@cgaube
Copy link
Author

cgaube commented Oct 27, 2016

Probably because I did not know/check that zend-mvc was defining a service called "EventManager" that was automatically inject the default SharedEventManager.

This is why I opened that discussion - I am trying to understand what would be the best way to do it
Thank you for your input

Why would you use another SharedEventManager instance for your service?
To separate Functionalities by Class Type - I was thinking that It might be faster and cleaner to have several shared event managers
So I could have a FormSharedManager that would only apply to Form Classes (like UserForm)
I could still use the identifiers to filter by class name (UserForm / PermissionForm ... ),

I could also have another separate ShareEventManager for my Models
etc etc

Is this method overkill ? Should I just attach all my listeners to the default SharedEvent manager ?

@thomasvargiu
Copy link

It's just my opinion.
You can inject another SharedEvent manager, but I suggest to use a "standard", like the "SharedEventManager" service of zend-mvc.
In this way, anyone can attach listeners without to know which SharedManager is.

@weierophinney
Copy link
Member

This repository has been closed and moved to laminas/laminas-eventmanager; a new issue has been opened at laminas/laminas-eventmanager#7.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants