8000 [RFC][2.3][EventDispatcher] toward cleaner events by kriswallsmith · Pull Request #7627 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[RFC][2.3][EventDispatcher] toward cleaner events #7627

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

kriswallsmith
Copy link
Contributor

I've quickly implemented my proposed fixes for both #6686 and #7582. We can't remove getName() and getDispatcher() from Event because those methods are marked @api, but we can deprecate them and remove them in 3.0.

@@ -158,10 +159,10 @@ public function removeSubscriber(EventSubscriberInterface $subscriber)
* @param string $eventName The name of the event to dispatch.
* @param Event $event The event object to pass to the event handlers/listeners.
*/
protected function doDispatch($listeners, $eventName, Event $event)
protected function doDispatch($listeners, $eventName, Event $event, EventDispatcherInterface $dispatcher = null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing phpdoc

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not required

@stof
Copy link
Member
stof commented Apr 11, 2013

tests should be updated for this

@kriswallsmith
Copy link
Contributor Author

This is not ready for merge. I'd like feedback on the approach before spending the time to flesh it out.

$event->setName($eventName);

if (!isset($this->listeners[$eventName])) {
return $event;
}

$this->doDispatch($this->getListeners($eventName), $eventName, $event);
$this->doDispatch($this->getListeners($eventName), $eventName, $event, $dispatcher);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not required.

@ghost
Copy link
ghost commented Apr 13, 2013

@kriswallsmith - if you don't have time I can finish this PR up and add the necessary tests, but I would be sorry to see getName() removed from the base Event I think it belongs as part of the event objects state.

@mpdude
Copy link
Contributor
mpdude commented Apr 14, 2013

The one thing I don't like about this is that the new third parameter for dispatch() is also exposed to "userland", i. e. client code wanting to dispatch an event. It is optional, but in times of IDEs and code suggestion one might wonder what to put in there. In fact it is relevant only internally in event dispatcher compositions.

As the title is "towards cleaner events" I would also like to add the following reasoning.

Event objects are supposed to carry additional (domain) information about what happened. Their name is given to a dispatcher along with the object.

As long as the API is like that, the name is not a property of the Event in the first place. If it were, the dispatcher's client could as well set the name on the Event itself (instead of passing it to the dispatcher) or the Event would even provide the name (hard-coded).

The same applies to the dispatcher: If an Event describes what happened, it should be agnostic of how that information is distributed to interested parties (listeners).

The Event class currently mixes up what happend with how that is distributed. In fact, the base class does not even care about what and only provides methods for the how.

This PR is in line with that reasoning and starts to clean this up, but it does not go the whole way.

If you take responsibilities for the name and dispatcher from this base class, you leave it with the propagation-stopping stuff alone. IMO that belongs to the other two and could easily be implemented another way as listeners get the dispatcher already (even more explicitely in this PR).

So what we could do in the long run is to separate the "Event" (an arbitrary, userland, "what"-object simply passed around; no base class needed; dispatcher-agnostic) from an "EventPropagation" class. The first dispatcher involved creates it and it is passed to all listeners, similar to what is suggested above. Only that the EventPropagation is more valuable than the dispatcher alone as it could take more methods in the future without changing listeners' signature, keep track of all dispatchers involved etc.

_Update_: I made #7792 for this.

@kriswallsmith
Copy link
Contributor Author

@mpdude Moving propagation control from the event object to the dispatcher sounds like a good idea to me. That way the event object could be any POPO (in 3.0), which would be awesome.

@Drak I agree that the 3rd argument to dispatch() is strange, but it's a simple solution to the problem.

@stof
Copy link
Member
stof commented Apr 14, 2013

@kriswallsmith it cannot be moved to the dispatcher, only to a separate class. The propagation is a state related to the event. The dispatcher must stay stateless, otherwise it will become really hard to dispatch several events (and even worse when dispatching an event inside a listener for another event)

@kriswallsmith
Copy link
Contributor Author

I've updated my PR. Propagation can be stopped by throwing an exception. I know some of you are going to balk about this use of an exception, but again, it's the simplest and cleanest solution to the problem. Other ideas are welcome, of course.

@mpdude
Copy link
Contributor
mpdude commented Apr 14, 2013

I created #7792 to show an idea how the Event Dispatcher could be made less obtrusive in 3.0 based on this work.

@fabpot
Copy link
Member
fabpot commented Apr 22, 2013

I'm (obviously) -1 to this change. I agree with @Drak that doing this just to fix a problem in the way we collect data is wrong.

Then, we decided a long time ago to use the current approach (which was really the Doctrine approach), so, that's not to change it now just before the first LTS.

We might revisit this for 3.0, but as this is in a very long time, I'm closing this PR for now.

@kriswallsmith
Copy link
Contributor Author

I'm not clear on why you oppose this PR (it's not obvious). Would you mind explaining? Thanks!

trigger_error(
'Calling stopPropagation() on the event object is deprecated. '.
'Throw a StopPropagationException instead.',
E_USER_DEPRECATED
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a bad idea of using exceptions to control application flow.

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

Successfully merging this pull request may close these issues.

7 participants
0