Laravel 5.8 is supposed to dispatch the syncing, attaching and detaching events (https://laravel.com/docs/5.8/releases search for Intermediate Table / Pivot Model Events section).
I tried it out but the following code throws the exception:
Call to undefined method App\ProjectUser::syncing()
class User extends Model
{
public function projects()
{
return $this->belongsToMany(\App\Project::class)->using(\App\ProjectUser::class);
}
}
class Project extends Model
{
public function users()
{
return $this->belongsToMany(\App\User::class)->using(\App\ProjectUser::class);
}
}
class ProjectUser extends Pivot
{
public static function boot()
{
parent::boot();
static::syncing(function ($item) {
dd('syncing event has been fired!');
});
}
}
// web.php
$project = \App\Project::first();
$project->users()->sync([1,2]);
I tried to move the boot method from ProjectUser to User and Project but I get the same exception.
I cannot find any documentation or examples about it.
Can you please fill out the issue template?
Ah sorry, just saw that this is a docs issue. You're free to send in a PR to the docs if you feel that anything is missing or can be corrected.
The code I posted can be a bug as well. I followed the documentation (poor for the syncing event topic) but I get the reported exception.
@danielefavi in any case, this is more a question for the forums. Can you first please try one of the following support channels? If you can actually identify this as a bug, feel free to report back and I'll gladly help you out.
Thanks!
I already tried on Laracast and StackOverflow:
https://laracasts.com/discuss/channels/laravel/laravel-58-and-syncing-event
@danielefavi hey Dan, thanks for providing those links. I've looked at the issue a bit myself but there's no syncing method present anywhere. What makes you think there is? Is there somewhere in the docs where you found this? Because I can't find a reference to it anywhere.
The section Intermediate Table / Pivot Model Events of the Laravel 5.8 release notes is stating that:
In previous versions of Laravel, Eloquent model events were not dispatched when attaching, detaching, or syncing custom intermediate table / "pivot" models of a many-to-many relationship. When using custom intermediate table models in Laravel 5.8, these events will now be dispatched.
So I'm expecting that the syncing, attaching, detaching events are going to be handled like the other events (updating, deleting, creating, updating, ...).
So the issue I opened can be caused by:
I think you didn't misunderstand but I'm talking about static::syncing specifically. This doesn't exists anywhere. Where did you find this code?
I though the syncing event could be treated like all the other events. For example if I want to listen to the updating event, raised by the project, I can set static::updating in the boot method of the project model (another better way is to create an observer).
Here a working example:
class Project extends Model
{
protected $guarded = [];
public static function boot()
{
parent::boot();
static::updating(function ($model) {
dd('updating event has been fired!');
});
}
public function users()
{
return $this->belongsToMany(\App\User::class)->using(\App\ProjectUser::class);
}
}
NOTE: I made a laravel app to test this issue where you can clone the repo, migrate and play around:
https://github.com/danielefavi/laravel-issue-example
Well, this simple doesn't exists. If you feel that it should be added you can always open up a feature request in the ideas repo.
I think the wording of the documentation is possibly confusing here.
Intermediate Table / Pivot Model Events
In previous versions of Laravel, Eloquent model events were not dispatched when attaching, detaching, or syncing custom intermediate table / "pivot" models of a many-to-many relationship. When using custom intermediate table models in Laravel 5.8, these events will now be dispatched.
The way I read this, is that the standard observable events, listed here:
will be fired if they are relevant to the action taking place(attach, detach, sync, etc.).
Attach, detach, sync, etc., do not have their own event that is fired, but they will now trigger the appropriate existing event(updating, updated, etc.).
I may be wrong, but I believe that is what the comment in the docs is trying to say.
@devcircus you are totally right! Now it is clear. Thanks to all of you!
For example the event fired with $project->users()->sync([1,2]); is saving so the boot method of ProjectUser should be:
class ProjectUser extends Pivot
{
public static function boot()
{
parent::boot();
static::saving(function ($item) {
dd($item);
});
}
}
Hmm you're correct. This is confusing. I'll ping Taylor about this since he was the one which added this section.
It's indeed best that we rephrase this. Feel free to send in a PR with a suggested change.
Here is my attempt at clarifying this in the docs.
https://github.com/laravel/docs/pull/5096
@driesvints If this still isn't clear enough or you think it could be better, please close and fix.
@devcircus this is how I replied on Stackoverflow and Laracast
On Laravel 5.8, when you are using the methods sync, attach or detach is going to be fired the appropriate model events (creating, updating, saving, ...) for the called action. Note that using sync, attach or detach is not going to fire any event like syncing, attaching or detaching.
More specifically, the sequence of events fired for each element passed to the sync method are:
The sequence of events fired for each element passed to the attach method are:
The sequence of events fired for each element passed to the detach method are:
So if you want to observe the syncing operation you actually have to observe the saving (or saved) event:
class ProjectUser extends Pivot
{
public static function boot()
{
parent::boot();
static::saving(function ($item) {
// this will die and dump on the first element passed to ->sync()
dd($item);
});
}
}
Pr to docs was merged 馃憤
[v5.8.18] any idea why detach() does not fire event static::deleted or static::deleting?
I just tried and detach is actually firing static::deleted and static::deleting
I guess you are missing the pivot model: if you have a relation many-to-many you have to create a pivot model then call static::deleted or static::deleting within the pivot model.
Here a working example:
https://github.com/danielefavi/laravel-issue-example/tree/master/app
you can see that ProjectUser is the pivot model where I'm observing all the events (included static::deleted and static::deleting).
@danielefavi
I do have a pivot model which extends use Illuminate\Database\Eloquent\Relations\MorphPivot.
Not sure if that is the issue but will try it tomorrow.
Will give your example a try with the MorphPivot.
@sgimmai I just faced the same problem.
After I digged a little bit, I found out, that delete method on MorphPivot overrides delete method defined in Pivot over AsPivot trait. Firing deleting and deleted events is defined only in Pivot class (AsPivot trait), and it definitely woks, but MorphPivot overrides this behaviour.}
Gonna check git commits and make a PR to fix it
UPDATE: As I expected: AsPivot was hardly developed this year, while MorphPivot got only docfixing
As this issue is closed continue here: #29631
Most helpful comment
@devcircus you are totally right! Now it is clear. Thanks to all of you!
For example the event fired with
$project->users()->sync([1,2]);is saving so the boot method ofProjectUsershould be: