-
Notifications
You must be signed in to change notification settings - Fork 11.2k
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
[5.3] Fire BelongsToMany relation events for attach/detach/sync/toggle #14988
[5.3] Fire BelongsToMany relation events for attach/detach/sync/toggle #14988
Conversation
…toggle) + refactored brittle tests
7fa262e
to
8530bcb
Compare
I really like this. Should $model->belongsToRelation()->associate($otherModel) not also have an event? |
1 this is only for belongsToMany, that is operations on pivot table, which Jarek Tkaczyk |
|
||
// we expect to call $relation->wherePivot() | ||
$relation->getQuery()->shouldReceive('where')->once()->andReturn($relation); | ||
// This is our test! The wherePivot() params also need to be called |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does "This is our test!" mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should ask @GrahamCampbell :)
I guess it refers to the wherePivot
line below. There are bunch of tests in this class that are mocking CUT and require refactoring, but I didn't want to do that, so PR doesn't get even bigger and harder to review.
ping @taylorotwell |
Pending you removing "This is our test!" @jarektkaczyk. |
WAT? That's an old test, out of scope of this PR, and btw your test Graham (or at least git blames you) ;) |
well, as irrelevant as it is, here's the time travel:
so git blamed your Now, back to the feature being proposed. |
I'd appreciate you not taking the piss. Please just remove it. I don't care who added it. |
I really don't think this is ever a good solution to a problem to be honest. If you want something to happen before or after you attach / detach / toggle / whatever, you should make a repository class that actually does those things before calling ->attach. That saves us having to maintain all of this complicated event code throughout Eloquent. |
@jarektkaczyk Did you find a clean way to implement this since this PR was rejected? I agree that this would be really useful to have in Laravel core. |
I didn't work on it anymore since then.
Jarek Tkaczyk
softonsofa :: development with pleasure
…On Dec 17, 2016 07:04, "Andrew Kamm" ***@***.***> wrote:
@jarektkaczyk <https://github.com/jarektkaczyk> Did you find a clean way
to implement this since this PR was rejected? I agree that this would be
really useful to have in Laravel core.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#14988 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AGm5sl25ZBTbmPJUUeXmchY4wI05gKSNks5rIxkCgaJpZM4Jrk2W>
.
|
Just manually fire the events , is what I did
On Fri, Dec 16, 2016 at 9:47 PM Jarek Tkaczyk <[email protected]>
wrote:
… I didn't work on it anymore since then.
Jarek Tkaczyk
softonsofa :: development with pleasure
On Dec 17, 2016 07:04, "Andrew Kamm" ***@***.***> wrote:
> @jarektkaczyk <https://github.com/jarektkaczyk> Did you find a clean way
> to implement this since this PR was rejected? I agree that this would be
> really useful to have in Laravel core.
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <#14988 (comment)
>,
> or mute the thread
> <
https://github.com/notifications/unsubscribe-auth/AGm5sl25ZBTbmPJUUeXmchY4wI05gKSNks5rIxkCgaJpZM4Jrk2W
>
> .
>
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#14988 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AB-I7CgF9brA4hZLWHHPk7s5ciA5X97Xks5rI01XgaJpZM4Jrk2W>
.
|
We needed attach/detach events at Agency Core for sending things like User notifications when new tasks were assigned. I've created a Gist with the extensions we added to make it work - https://gist.github.com/andyberry88/be3c45380568fc359cb61e00c4249704. It's basically the changes suggested by @jarektkaczyk above but taken out into app classes. I've had to extract it from other extensions we've added so hopefully it works. It should at least give an idea of the changes required. |
@andyberry88 Thanks! |
@jarektkaczyk maybe we could work together to make it a package ? Not sure if theres a ton of demand for it but it would save me time in some other applications. |
@lukepolo I can help you out with the package, just drop me an email with what assistance you need 🏄♂️ |
I can also assist any attempt to make this formal. |
I sadly do not have the time todo this as previously thought, you can see if @jarektkaczyk still wants to help out |
Experimental package: |
I created a well documented and well-tested package for this problem https://github.com/fico7489/laravel-pivot. |
@taylorotwell If we create a repository class, is there a way to get Nova to utilize it? We are doing some caching and want to invalidate/recalculate the cache when many-to-many relationships change. Do you have any recommendations for how we can do this? For now I will see if we can use laravel-pivot. |
@taylorotwell Sorry to necro this comment on you; however, perhaps there is a better solution here than creating new events or leaving the current functionality as-is?
While I generally agree with this statement regarding business logic like sending notifications, there are good use-cases for wanting events when updating pivots. For example, a common use-case is to implement auditing and having some sort of events fire allows one to setup auditing events in a general way. For example, in an auditing package. My understanding is that sync() does not trigger the normal eloquent events even if we create a custom pivot model. Therefore, currently one can audit on a belongsTo relationship by listening to the model being updated, but there is not a way to listen to a belongsToMany relationship as the information is contained in an unrelated model that isn't triggering events. So maybe the appropriate solution is to just make sync() and related methods trigger these default events if a custom Pivot model exists? Currently one can just ignore these relationship functions and update the pivots manually with a save() statement to get eloquent events. So these convenient functions just become a newbie trap instead of something that one should really use. |
BelongsToMany relations is the only missing part in the events system in eloquent.
It has been requested for a long time and has many applications, eg.
#10435 #10545 #10770 #4022 #2303 #1703 #8452
This PR is BC however it also brings change in the public interface, that is all the methods (
attach/detach/sync/toggle
) get additionalfalse
return value in case*ing
event halts the execution. As is it doesn't break BC however there might be edge case:1. one relies on
array
return value fromsync
ortoggle
2. then adds
syncing/toggling
event handler that can halt execution in some circumstances3. the return value under those circumstances is no longer
array
butfalse
Model
to register these events (due to different nature, they have additional parameter - relation name), eg:Since the
$pivotData
payload may vary depending on the event, here's complete list of its content:attaching
- like in the example above - Collection with raw data to be inserted to the pivot tableattached
- same as abovedetaching
- Collection of ids being detached OR empty Collectiondetaching
- Collection of detached ids OR empty Collectionsyncing
- Collection of id => [ ..pivot data.. ] entries to be inserted/updatedsynced
- Collection of changes made (the same as return value ofsync
only wrapped in Collection)toggling
- Collection of id => [ ..pivot data.. ] entries to be inserted/updatedtoggled
- Collection of changes made (the same as return value ofsync
only wrapped in Collection)and an example of all events being fired when
syncing
:All of the
*ing
events are, just like existing ones, capable of halting the action if your listener returnsfalse
:You can also adjust pivot data in the callback, just like you'd do with exiting events:
Notes on the commits:
BelongsToMany
has been a bit refactored in order to useCollection
where events require that