Skip to content

Add BeforeMarshalEventInterface #17990

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 3 commits into from
Closed

Conversation

bancer
Copy link
Contributor

@bancer bancer commented Oct 23, 2024

The idea is to explicitly define model callback methods so that in order to use the callbacks table classes would need to implement callback interfaces like BeforeMarshalEventInterface. This way it would be possible to enforce the consistent methods signatures of model callbacks in table classes. For example, if the client code would have public function beforeMarshal($event, $data, $options): void method an error would be generated because it does not match the method defined in BeforeMarshalEventInterface.

Would this approach be okay? Only one callback interface is added here just to make it easier to explain.

@dereuromark
Copy link
Member

dereuromark commented Oct 23, 2024

Such changes should target 5.next directly (minimum).

@ADmad
Copy link
Member

ADmad commented Oct 23, 2024

Such changes should target 5.next directly.

This is not a backward compatible change and would have to wait till 6.0, if approved.

I do like the idea of enforcing the signature for the callback methods, but not too sure about this implementation. If someone adds the beforeMarshal() method but forgets to implement the interface the callback won't be executed. One would imagine such an oversight is easy to debug, but based on my experience in the support channel such silent failures can often lead to a lot of hair pulling, especially for new users.

@ADmad ADmad added this to the Future milestone Oct 23, 2024
@ADmad ADmad added the RFC label Oct 23, 2024
@bancer
Copy link
Contributor Author

bancer commented Oct 23, 2024

@ADmad an alternative approach could be to add empty methods like public function beforeMarshal(EventInterface $event, ArrayObject $data, ArrayObject $options): void {/* To be implemented in children classes if necessarry */} directly to Table class like the existing initialize method.

@ADmad
Copy link
Member

ADmad commented Oct 23, 2024

Yes, adding empty methods is an option too, we already have that for controller events.

@ADmad
Copy link
Member

ADmad commented Oct 23, 2024

But adding the empty methods in 5.2 can also if problematic. Since a signature mismatch with existing methods will create a PHP error.

@dereuromark
Copy link
Member

The main issue with actual methods and inheritance is that you cannot use the concrete objects as types, only EntityInterface etc
Then you rely on the docblock and IDE to "typehint" the correct one to be able to see available properties and methods and let static analyzers do their job.
Right now people are free to use the concrete one if they want to directly.

@ADmad
Copy link
Member

ADmad commented Oct 23, 2024

The main issue with actual methods and inheritance is that you cannot use the concrete objects as types, only EntityInterface

Yes, hence the chance of signature mismatch, I too often use type the argument using the concrete entity class.

@bancer
Copy link
Contributor Author

bancer commented Nov 1, 2024

If someone adds the beforeMarshal() method but forgets to implement the interface the callback won't be executed.

@ADmad I adjusted my changes so that if a model has a callback method but does not implement a corresponding interface then an exception will be thrown. What do you think about this approach?

@ADmad
Copy link
Member

ADmad commented Nov 1, 2024

..if a model has a callback method but does not implement a corresponding interface then an exception will be thrown

That could be considered for the next major.

But I am not in favor of using similar interfaces for callbacks which take an entity as an argument. Typing the argument using EntityInterface in the interface would prevent specifying a concrete entity class as the argument type in the method as that's not be contravariant.

@bancer
Copy link
Contributor Author

bancer commented Nov 1, 2024

But I am not in favor of using similar interfaces for callbacks which take an entity as an argument. Typing the argument using EntityInterface in the interface would prevent specifying a concrete entity class as the argument type in the method as that's not be contravariant.

That I do not understand. Do you suggest to remove "EntityInterface" from the method signature like
public function afterSave(EventInterface $event, $entity, ArrayObject $options): void;?

@bancer bancer mentioned this pull request Nov 1, 2024
@bancer
Copy link
Contributor Author

bancer commented Nov 1, 2024

Would a different approach #18008 be better than this?

@ADmad
Copy link
Member

ADmad commented Nov 1, 2024

Do you suggest to remove "EntityInterface" from the method signature like

Not specifying the type for the $entity argument would be an option then we are back to specifying @var annotation to make the type known to static analyzers and IDEs. I don't really have a solution to this problem right now.

@dereuromark
Copy link
Member

dereuromark commented Nov 20, 2024

Users could chose.
If you add these interfaces to your app/plugin table classes it would autocomplete via IDE for you.
Everything else still works normally.

We could in the future also check on the interface for existence of callbacks.
Of course this would be opt-in, the classic way still works as before.
So the code still mainly checks on the method existence of course.

So basically this is just a way for users to more quickly add their event callbacks with pre-defined signatures if they want to.

I think the framework should provide them as part of the contract. And then people can use to use them.

@ADmad
Copy link
Member

ADmad commented Nov 21, 2024

I like the TableEventsTrait approach of #18008. Users can opt-in to add it to their table classes to get method autocompletion.

@bancer
Copy link
Contributor Author

bancer commented Nov 22, 2024

@ADmad I've finished #18008 and all tests pass there.

@dereuromark
Copy link
Member

With the other PR advancing, closing this for now.

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

Successfully merging this pull request may close these issues.

3 participants