DEV Community

Zubair Mohsin
Zubair Mohsin

Posted on

Laravel custom Pivot Model events (many-to-many relationship)

Laravel offers events like created, updated, saved and many other for regular Eloquent models. What about Pivot models?

Starting from Laravel 5.8, Pivot Model events are supported.

For a refresher on Pivot Models, refer to docs here.

Scenario

Let's take consider the example from docs about Many-to-Many relationship. User and Roles.

We are interested in following use case:

Whenever, a Role is assigned to a User, send a notification to Admin.

We can simply use attach method and then send notification right after that like below:


$user->roles()->attach($roleId);

$admin->notify(new RoleAssigned);
Enter fullscreen mode Exit fullscreen mode

Wouldn't it be cool if we can refactor this notifying part to dedicated event and listener and clear up our controller method?

Dude, tell me already!

Let's define the Pivot mode, as RoleUser.

namespace App;

use Illuminate\Database\Eloquent\Relations\Pivot;

class RoleUser extends Pivot
{
    //
}
Enter fullscreen mode Exit fullscreen mode

Let's add the secret sauce, $dispatchesEvents array:

namespace App;

use App\Events\RoleAssigned;
use Illuminate\Database\Eloquent\Relations\Pivot;

class RoleUser extends Pivot
{
    protected $dispatchesEvents = [
      'created' => RoleAssigned::class
    ];
}
Enter fullscreen mode Exit fullscreen mode

Be sure to register this event and its listener in EventServiceProvider.

Event and its listener can be simply defined just any other Event/Listener.

class RoleAssigned
{

    public $roleUser;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct(RoleUser $roleUser)
    {
        $this->roleUser = $roleUser;
    }

}
Enter fullscreen mode Exit fullscreen mode

class MessageCreatedListener implements ShouldQueue
{

   public function handle($event)
   {

      //access the Pivot model like below...

      $event->roleUser

      //send a notification here
   }

}
Enter fullscreen mode Exit fullscreen mode

Extracting logic like "sending notifications" into Event/Listeners can be beneficial, as Listeners can be queued and notification can be sent in background.

Now, our controller function will be super simple:


public function store()
{
  $user->roles()->attach($roleId);

  //
}
Enter fullscreen mode Exit fullscreen mode

Above line will fire the event (RoleAssigned) and its Listener will send the notification.

Peace 🙌🏼

Discussion (2)

Collapse
nijibemani profile image
Niji • Edited on

It seems you don't have to register model events in EventServiceProvider.
When I did that, my listener fired two times!

EDIT : my bad, I sat shouldDiscoverEvents() to true in EventServiceProvider.

Collapse
loktpar profile image
Lokendra Parihar

What about Pivot models?
in laravel 5.7,
is this working with this version of laravel, Or Can i use regular model for pivot table.