Eloquent attach/detach/sync fires any event?

Laravel 5.8 now fires events on ->attach()

Check out: https://laravel.com/docs/5.8/releases

And search for: Intermediate Table / Pivot Model Events

https://laracasts.com/discuss/channels/eloquent/eloquent-attach-which-event-is-fired?page=1


No, there are no relation events in Eloquent. But you can easily do it yourself (Given for example Ticket belongsToMany Component relation):

// Ticket model
use App\Events\Relations\Attached;
use App\Events\Relations\Detached;
use App\Events\Relations\Syncing;
// ...

public function syncComponents($ids, $detaching = true)
{
    static::$dispatcher->fire(new Syncing($this, $ids, $detaching));

    $result = $this->components()->sync($ids, $detaching);

    if ($detached = $result['detached'])
    {
        static::$dispatcher->fire(new Detached($this, $detached));
    }

    if ($attached = $result['attached'])
    {
        static::$dispatcher->fire(new Attached($this, $attached));
    }
}

event object as simple as this:

<?php namespace App\Events\Relations;

use Illuminate\Database\Eloquent\Model;

class Attached {

    protected $parent;
    protected $related;

    public function __construct(Model $parent, array $related)
    {
        $this->parent    = $parent;
        $this->related   = $related;
    }

    public function getParent()
    {
        return $this->parent;
    }

    public function getRelated()
    {
        return $this->related;
    }
}

then a basic listener as a sensible example:

    // eg. AppServiceProvider::boot()
    $this->app['events']->listen('App\Events\Relations\Detached', function ($event) {
        echo PHP_EOL.'detached: '.join(',',$event->getRelated());
    });
    $this->app['events']->listen('App\Events\Relations\Attached', function ($event) {
        echo PHP_EOL.'attached: '.join(',',$event->getRelated());
    });

and usage:

$ php artisan tinker

>>> $t = Ticket::find(1);
=> <App\Models\Ticket>

>>> $t->syncComponents([1,3]);

detached: 4
attached: 1,3
=> null

Of course you could do it without creating Event objects, but this way is more convenient, flexible and simply better.


Steps to solve your problem:

  1. Create custom BelongsToMany relation
  2. In BelongsToMany custom relation override attach, detach, sync and updateExistingPivot methods
  3. In overriden method dispatch desired events.
  4. Override belongsToMany() method in Model and return your custom relation not default relation

and that's it. I created package that already doing that: https://github.com/fico7489/laravel-pivot