Skip to content

Conversation

@yceruto
Copy link
Member

@yceruto yceruto commented Sep 6, 2019

Q A
Branch? 4.4
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets #33453
License MIT
Doc PR TODO

Everything is in the linked issue.

@nicolas-grekas
Copy link
Member

nicolas-grekas commented Sep 6, 2019

I'm sorry but I don't think this is an idea we should pursue.
It forces tight coupling to the component by inheritance and relies on pure conventions that happen to be what I call dead-ends: as soon as you want to listen to many events, you need to unlearn what you had to learn to use this class, you then need to learn about subscribers, and best of all, you are forced to change the inheritance chain - thus break BC.

[edit: this comment is now obsolete]

Copy link
Member

@derrabus derrabus left a comment

Choose a reason for hiding this comment

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

Good idea. I would use that class instantly. 👍

Tests for the error cases are missing:

  • Missing event parameter
  • Missing/invalid type declaration
  • Missing __invoke()

@derrabus
Copy link
Member

derrabus commented Sep 6, 2019

It forces tight coupling to the component by inheritance and relies on pure conventions that happen to be what I call dead-ends: as soon as you want to listen to many events, you need to unlearn what you had to learn to use this class, you then need to learn about subscribers, and best of all, you are forced to change the inheritance chain - thus break BC.

For the same reasons, we could ban the abstract Voter class from the security component for instance. Yet, classes like these remove the need for boilerplate that looks the same in 80% of the cases.

Also, developers can look into this class and learn how they can build subscribers without it. The reflection part aside, it's pretty straightforward.

@nicolas-grekas
Copy link
Member

nicolas-grekas commented Sep 6, 2019

Voter doesn't use reflection. It's just a base abstract class.
The proposed one provides conventions by reflection.

All this is exactly the same as writing:

    final public static function getSubscribedEvents(): array
    {
        return [MyEvent::class => ['__invoke', 0]];
    }

Saving writing this is not worth the drawbacks to me.
If you want to save writing this, a maker would do it without the drawbacks.

@yceruto
Copy link
Member Author

yceruto commented Sep 7, 2019

What about a new interface for single-event subscription?

interface EventListenerInterface
{
    public static function getEventName();
    public static function getMethodName();
    public static function getPriority();
}

and with auto-configuration would make the current event listener approach even easier maybe?

@yceruto
Copy link
Member Author

yceruto commented Sep 7, 2019

Related to #33485 (comment), the getMethodName could also be useless if the event listeners already support invokable classes.

@yceruto yceruto force-pushed the event_listener branch 2 times, most recently from c20950c to d347385 Compare September 7, 2019 13:40
@yceruto
Copy link
Member Author

yceruto commented Sep 7, 2019

Talking with @nicolas-grekas on Slack, their architectural objections can be removed using traits, done!, so let's focus on the teachability objections now :)

@yceruto
Copy link
Member Author

yceruto commented Sep 7, 2019

I will add more tests when the objections have been removed, I hope that :)

@yceruto yceruto force-pushed the event_listener branch 2 times, most recently from 59ade0a to badd322 Compare September 7, 2019 14:04
@nicolas-grekas
Copy link
Member

If you're ok with my last review, we could name the trait InvokableEventSubscriberTrait

@yceruto yceruto force-pushed the event_listener branch 4 times, most recently from 1a83a39 to 6031c96 Compare September 7, 2019 14:56
@yceruto
Copy link
Member Author

yceruto commented Sep 7, 2019

@nicolas-grekas comments addressed where possible, how does it look to you now?

@yceruto
Copy link
Member Author

yceruto commented Sep 9, 2019

Update

Removed getEventName and getPriority methods, so you'll use this trait for one exclusive purpose, the most common on app side:

class MyEventSubscriber implements EventSubscriberInterface
{
    use InvokableEventSubscriberTrait;

    public function __invoke(MyEvent $event): void
    {
        // ...
    }
}

If it does not fit your needs, because the event name is not the FQCN or it has a different priority, then you should not use this feature and would implement the getSubscribedEvents() method directly.

@yceruto yceruto force-pushed the event_listener branch 2 times, most recently from 401e7e4 to 61af258 Compare September 9, 2019 18:15
Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

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

(with a request to improve the description in the docblock)

@chalasr
Copy link
Member

chalasr commented Sep 22, 2019

For using this you have to use a given trait + implement a given interface + eventually declare some static properties - vs implementing getSubscribedEvents, I'm not convinced it's worth the complexity.
Also this involves reflection which RegisterListenersPass already uses for similar validation...

Given this basically allows for autoconfigured event listeners, couldn't we just add a marker interface instead? That could allow to keep the reflection-based logic in the compiler pass only and could, I think, reduce the learning curve.

@nicolas-grekas
Copy link
Member

@chalasr I'm personally against adding a new abstraction when we already have all we need. That'd be another option, thus another choice to make for ppl, but learn about them before, document it, etc.

Copy link
Contributor

@Tobion Tobion left a comment

Choose a reason for hiding this comment

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

$listenerEvent and $listenerPriority is also a new concept people need to learn now and it will split knowledge and expectations of developers. I'd be ok to have this helper trait but without those static properties. If someone needs to adjust that, they should use the common and establisted way of implementing getSubscribedEvents
Also those static properties can easily introduce bugs because if you have a typo, it won't be even detectable by static analysis or at container compilation. It would just be buggy at runtime.

@fabpot
Copy link
Member

fabpot commented Sep 27, 2019

The more we talk about this one, the more I think we should not add this to core. I'm now 👎 .

@yceruto
Copy link
Member Author

yceruto commented Sep 27, 2019

Let's close then, it's not worth it for me anymore.

@yceruto yceruto closed this Sep 27, 2019
@yceruto yceruto deleted the event_listener branch September 27, 2019 12:50
nicolas-grekas added a commit that referenced this pull request Oct 9, 2019
…gistering listeners (derrabus)

This PR was merged into the 4.4 branch.

Discussion
----------

[EventDispatcher] Allow to omit the event name when registering listeners

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | #33453 (kind of)
| License       | MIT
| Doc PR        | TODO

After #30801 and #33485, this is another attempt at taking advantage of FQCN events for simplifying the registration of event listeners by inferring the event name from the parameter type declaration of the listener. This is my last attempt, I promise. 🙈

This time, I'd like to make the `event` attribute of the `kernel.event_listener` tag optional. This would allow us to build listeners like the following one without adding any attributes to the `kernel.event_listener` tag.

```php
namespace App\EventListener;

final class MyRequestListener
{
    public function __invoke(RequestEvent $event): void
    {
        // do something
    }
}
```

This in turn allows us to register a whole namespace of such listeners without having to configure each listener individually:

```YAML
services:
    App\EventListener\:
        resource: ../src/EventListener/*
        tags: [kernel.event_listener]
```

Commits
-------

6f32584 [EventDispatcher] Allow to omit the event name when registering listeners.
@nicolas-grekas nicolas-grekas modified the milestones: next, 4.4 Oct 27, 2019
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.