Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[EventDispatcher] Add listener caller extension point #18873

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
wants to merge 1 commit into from

Conversation

unkind
Copy link
Contributor

@unkind unkind commented May 25, 2016

Q A
Branch? master
Bug fix? no
New feature? sort of
BC breaks? no
Deprecations? no
Tests pass? let's see
Fixed tickets -
License MIT
Doc PR -

In our project we reuse infrastructure of the EventDispatcher for dispatching domain events. In the past we had 2 issues:

  • inheriting the Event class (because it makes our domain coupled on the framework and it also contains undesirable propagation logic);
  • having eventName, i.e. our "event name" is simple get_class($event).

We introduced DomainEventEnvelope extends \Symfony\Component\EventDispatcher\Event and the following dispatcher:

final class DomainEventAwareEventDispatcher extends ContainerAwareEventDispatcher
{
    /**
     * {@inheritdoc}
     */
    protected function doDispatch($listeners, $eventName, Event $event) {
        if ($event instanceof DomainEventEnvelope) {
            foreach ($listeners as $listener) {
                $listener($event->getDomainEvent(), $event->getMetadata());
            }
        } else {
            parent::doDispatch($listeners, $eventName, $event);
        }
    }
}

It works, but this solution is rather bad. This PR adds new extension point in the EventDispatcher which allows to solve issue above with composition:

final class DomainEventListenerCaller implements EventListenerCallerInterface
{
    private $fallbackListenerCaller;

    public function __construct(EventListenerCallerInterface $fallbackListenerCaller)
    {
        $this->fallbackListenerCaller = $fallbackListenerCaller;
    }

    public function call(callable $listener, Event $event, $eventName, EventDispatcherInterface $eventDispatcher)
    {
        if ($event instanceof DomainEventEnvelope) {
            $listener($event->getDomainEvent(), $event->getMetadata());
            return;
        }

        $this->fallbackListenerCaller->call($listener, $event, $eventName, $eventDispatcher);
    }
}

@fabpot
Copy link
Member

fabpot commented Jun 15, 2016

I'm 👎 for this change as it makes the code complex at the Symfony level with more indirections and probably some small performance penalty.

@unkind
Copy link
Contributor Author

unkind commented Jun 15, 2016

it makes the code complex at the Symfony level with more indirections

Technically, this PR doesn't allow to do something new. Symfony already provides the extension point (protected method). But existing extension point is painful in practice (as you can see, I have to extend ContainerAwareEventDispatcher, not even EventDispatcher).
If Symfony does allow this kind of extension, I want to see explicit extension point.

probably some small performance penalty

We can make some benchmarks, but I don't think it should be noticeable impact.

*/
public function call(callable $listener, Event $event, $eventName, EventDispatcherInterface $eventDispatcher)
{
$listener($event, $eventName, $eventDispatcher);
Copy link
Member

Choose a reason for hiding this comment

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

this will not support all kind of callables (which is why the existing code still uses call_user_func

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's interesting. What kind of callables do you mean?

Copy link
Member

Choose a reason for hiding this comment

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

array(__CLASS__, 'someStaticMethod') cannot be called with this notation (this is the last remaining one in PHP 5.4+)

@unkind unkind force-pushed the feature-listener-caller branch from f09bdf9 to a4d8626 Compare June 15, 2016 10:28
@fabpot
Copy link
Member

fabpot commented Jun 21, 2016

I think this not something we need in Symfony. Your use case is very specific and I'm not willing to add this extension point as it is not useful for regular usages of the component.

@fabpot fabpot closed this Jun 21, 2016
@unkind
Copy link
Contributor Author

unkind commented Aug 15, 2016

I found another case for this extension point: it makes sense to catch exceptions from listeners and log them. In case of "true" events, we don't really care about listeners from caller perspective. For example, in our system, we managed to enqueue some listeners in order to execute them later (in shutdown callback). Thus, listeners may be executed in indefinite time point and throwing exceptions from them is something similar to throwing exceptions from __destruct().

It is possible to fix it by inheritance, but again I don't find this solution perfect.

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

Successfully merging this pull request may close these issues.

5 participants