5

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).

UPDATE: the release notes have been update after posting this question (more info: https://github.com/laravel/framework/issues/28050 - https://github.com/laravel/docs/pull/5096).

I tried it out but the following code throws the exception:

Call to undefined method App\ProjectUser::syncing()

NOTE: since Laravel 5.8 is supposed to dispatch the syncing event I don't want to use an external package.

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.

Dan
  • 3,329
  • 2
  • 21
  • 28
  • You only have `boot()` method there. – Tpojka Mar 28 '19 at 08:04
  • @Tpojka can you be more specific, please? That is a common way to tell laravel to listen to an event (another way is to create an observer). – Dan Mar 28 '19 at 08:23
  • Sorry, didn't use it that way. I fairly use observers but didn't use through boot method. I just searched docs and there is no syncing method. – Tpojka Mar 28 '19 at 08:26

2 Answers2

5

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:

  • saving
  • creating
  • created
  • saved

The sequence of events fired for each element passed to the attach method are:

  • saving
  • creating
  • created
  • saved

The sequence of events fired for each element passed to the detach method are:

  • deleting
  • deleted

So if you want to observe the syncing operation you actually have to observe the saving (or saved) event from the pivot model (in this case ProjectUser):

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);
        });
    }
}

A working example https://github.com/danielefavi/laravel-issue-example

More info on this issue https://github.com/laravel/framework/issues/28050

The release notes were misleading and they have been changed https://github.com/laravel/docs/pull/5096.

Dan
  • 3,329
  • 2
  • 21
  • 28
2

If detach method called without ids (for detach all relations), events are not firing

https://github.com/laravel/framework/pull/27571#issuecomment-493451259

i tried many different way for the solve this need, but it is impossible without use external package or override many method.

I choose chelout/laravel-relationship-events package.

It's look clean and understable. And use with trait.

eyaylagul
  • 31
  • 1
  • 5
  • Yes you are right, the detach method requires the IDs if you want to fire the events. A solution to detach all elements and have the events as well can be: `$project->users()->detach( User::all()->pluck('id') );` – Dan Jul 10 '19 at 09:50