Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to register a default Observer for every Model instance with Laravel

Laravel 5.1

I'm trying to register a single model observer for every Model that extends my AbstractModel (who are extending Illuminate\Database\Eloquent\Model).

The problem is my GenericModelObserver can't listen to events fired by Models inheriting AbstractModel.

Let me show what I did so far.

A Service Provider was created and put on the last position of the providers array inside config/app.php

<?php

// app/Providers/ObserverServiceProvider.php

namespace App\Providers;

use App\Models\Quotation;
use App\Models\AbstractModel;
use App\Observers\QuotationObserver;
use App\Observers\GenericModelObserver;
use Illuminate\Support\ServiceProvider;

class ObserverServiceProvider extends ServiceProvider
{

    public function boot()
    {
        AbstractModel::observe(GenericModelObserver::class);
        Quotation::observe(QuotationObserver::class);
    }

    public function register()
    {

    }
}

Then I have my plain simple GenericModelObserver

<?php

// app/Observers/GenericModelObserver.php

namespace App\Observers;

use App\Models\AbstractModel;

class GenericModelObserver
{
    public function saving(AbstractModel $model)
    {
        return $model->valid();
    }
}

The Abstract Model

<?php

// app/Models/AbstractModel.php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class AbstractModel extends Model
{
    // ...
}

My Quotation Model

<?php

// app/Models/Quotation.php

namespace App\Models;

class Quotation extends AbstractModel
{
    // ...
}

When Quotation is saved, the GenericModelObserver can't listen to the saving event or any other event.

The same applies for other Models that don't have a specific Model Observer.

Is this the right strategy? I would not like to bind a observer to every model through the boot method.

like image 395
Álvaro Guimarães Avatar asked Apr 08 '16 14:04

Álvaro Guimarães


2 Answers

Instead of extending model - write your own trait which will work as observer.
Below I wrote some basic trait:

<?php

namespace App\YourPackage\Traits;

use Illuminate\Database\Eloquent\Model;

trait Observable
{
    public static function bootObservable()
    {
        static::updating(function (Model $model) {
            dd('updating');
        });
    }
}

and use it by typing use Observable; in your model class.

Also for your learning take a note how traits is booting: You have to put boot[TraitClassName] method into trait, to boot it properly.
Never write boot method inside your trait, it's dangerous!

like image 74
Giedrius Kiršys Avatar answered Sep 20 '22 22:09

Giedrius Kiršys


Why not simply extend a parent class say BaseObserver

I have something similar in my caching system

<?php namespace App\Observers;
class BaseObserver {
    public function saving($model)
    {
        //do your thing here that apply to all observers, like caching
    }
}

Then in your Observers

<?php namespace App\Observers;
class Quotation extends BaseObserver{
   //you can override any of the methods if you wish
}
like image 40
Emeka Mbah Avatar answered Sep 19 '22 22:09

Emeka Mbah