Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Eloquent attach/detach/sync fires any event?

I have a laravel project, and I need to make some calculations immediately after I save a model and attach some data to it.

Is there any event that is triggered in laravel after calling attach (or detach/sync)?

like image 449
Mihai Crăiță Avatar asked Mar 08 '15 10:03

Mihai Crăiță


3 Answers

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.

like image 78
Jarek Tkaczyk Avatar answered Nov 08 '22 08:11

Jarek Tkaczyk


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

like image 33
fico7489 Avatar answered Nov 08 '22 08:11

fico7489


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

like image 9
Twostein Avatar answered Nov 08 '22 09:11

Twostein