Skip to content
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

[EventDispatcher] Throw exception when listener method cannot be resolved #50775

Merged
merged 1 commit into from
Jun 28, 2023

Conversation

nikophil
Copy link
Contributor

@nikophil nikophil commented Jun 26, 2023

Q A
Branch? 5.4
Bug fix? yes
New feature? no
Deprecations? no
License MIT
Doc PR not needed

while working on #50687 I've discovered bugs on how the method for listener is resolved:

Given this code:

#[AsEventListener(event: KernelEvents::REQUEST, priority: 5)]
class MyListenerNotInvokable
{
    public function someMethod(RequestEvent $event): void {}
}

A listener on MyListenerNotInvokable::onKernelRequest() is registered, and then an error is dispatched at runtime when the event is dispatched: Error: Call to undefined method App\EventListener\MyListenerNotInvokable::onKernelRequest()

The problem comes from this code: since the method is omitted in tag definition, we "camelize" the event's name. We then try to fallback on __invoke but because it does not exist, the wrong method name is kept.

this PR fixes this behavior by throwing an exception at compile time if neither the camlized method exist, not the __invoke method.

ping @GromNaN

@carsonbot carsonbot added this to the 6.3 milestone Jun 26, 2023
@nikophil nikophil marked this pull request as draft June 26, 2023 06:23
@nikophil nikophil changed the title [EnventDispatcher] Fix method resolving for listeners [EnventDispatcher] Fix method resolving when it is omitted in tag Jun 26, 2023
@nikophil nikophil force-pushed the fix/resolve-event-listener branch 4 times, most recently from e3797d3 to 838a2fc Compare June 26, 2023 07:05
@nicolas-grekas
Copy link
Member

This should target 5.4 to me since it's a bugfix.

@nikophil nikophil changed the base branch from 6.3 to 5.4 June 26, 2023 07:21
@nikophil nikophil marked this pull request as ready for review June 26, 2023 07:23
@carsonbot carsonbot added the Bug label Jun 26, 2023
@carsonbot carsonbot modified the milestones: 6.3, 5.4 Jun 26, 2023
@symfony symfony deleted a comment from carsonbot Jun 26, 2023
@nikophil
Copy link
Contributor Author

@nicolas-grekas I've rebased the PR

@GromNaN
Copy link
Member

GromNaN commented Jun 26, 2023

Thank you for your findings on this bug.

If it does not, we evaluate if one unique public method exists which would take the event as unique parameter (ie: the listener definition above would resolve someMethod() as the listener's method).

This looks like a new feature. Even if there is currently a runtime exception for this situation, I don't think we should support it as a bugfix.
The bugfix should be restricted to throwing an exception on build time when the method (__invoke or onEventName) doesn't exist.

I see situations where the "only public method" will fail and the developers will have to rework their configuration while it would be working previously:

  • a public getter or setter is added for DI or testing
  • a second event listener is added

For brevity, developers should set the AsEventListener attribute on the method instead of the class.

@nikophil
Copy link
Contributor Author

This looks like a new feature. Even if there is currently a runtime exception for this situation, I don't think we should support it as a bugfix.
The bugfix should be restricted to throwing an exception on build time when the method (__invoke or onEventName) doesn't exist.

ok let's do this: I'll split the PR and in the bugfix I'll only throw an exception if the resolved method does not exist

I see situations where the "only public method" will fail and the developers will have to rework their configuration while it would be working previously:

a public getter or setter is added for DI or testing
a second event listener is added

For brevity, developers should set the AsEventListener attribut on the method instead of the class.

indeed, there will be a failure in these cases, but for both cases, we don't have any way to resolve the method name, then their listener declaration becomes invalid. And since the error will occur in compile time, I think this is acceptable

@GromNaN
Copy link
Member

GromNaN commented Jun 26, 2023

ok let's do this: I'll split the PR and in the bugfix I'll only throw an exception if the resolved method does not exist

👍🏻 Sounds like a plan.

@nikophil
Copy link
Contributor Author

nikophil commented Jun 26, 2023

For brevity, developers should set the AsEventListener attribut on the method instead of the class.

This is just an idea, but since listeners are callables and not actual services, maybe in 7.0 we should allow #[AsEventListener] to be set on the class only if the class in invokable? This would simplify a lot all this method-resolving stuff, and remove some un-needed magic

@GromNaN
Copy link
Member

GromNaN commented Jun 26, 2023

I wouldn't bother developers with such a restriction. We're not going to deprecate documented way of using this attribute.

@nicolas-grekas
Copy link
Member

nicolas-grekas commented Jun 26, 2023

I'll split the PR and in the bugfix I'll only throw an exception if the resolved method does not exist

Totally. I missed this was a new feature.

This is just an idea, but since listeners are callables and not actual services, maybe in 7.0 we should allow #[AsEventListener] to be set on the class only if the class in invokable? This would simplify a lot all this method-resolving stuff, and remove some un-needed magic

I would advise against this. It'd be needlessly rigid.

@kbond kbond changed the title [EnventDispatcher] Fix method resolving when it is omitted in tag [EventDispatcher] Fix method resolving when it is omitted in tag Jun 26, 2023
Copy link
Member

@GromNaN GromNaN left a comment

Choose a reason for hiding this comment

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

LGTM, after few changes.

@nikophil
Copy link
Contributor Author

CI failures seems unrelated

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.

One minor thing. Can you please also update the commit+PR messages to make them tell what this does?

@nikophil nikophil changed the title [EventDispatcher] Fix method resolving when it is omitted in tag [EventDispatcher] Throw exception when listener method cannot be guessed Jun 27, 2023
@nikophil nikophil changed the title [EventDispatcher] Throw exception when listener method cannot be guessed [EventDispatcher] Throw exception when listener method cannot be resolved Jun 27, 2023
@nikophil
Copy link
Contributor Author

@nicolas-grekas done!

@nicolas-grekas
Copy link
Member

Thank you @nikophil.

@nicolas-grekas nicolas-grekas merged commit a6e5b75 into symfony:5.4 Jun 28, 2023
9 of 11 checks passed
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.

None yet

5 participants