Observer in Laravel - Laravel Advanced Topics - Beyond the documentation
Categories - Laravel PHP Framework Tags - PHP Laravel   Maniruzzaman Akash   2 years ago   4515   7 minutes   3

Observer in Laravel - Laravel Advanced Topics - Beyond the documentation

Today, we'll learn a beautiful feature of Laravel PHP Framework - Model Observer. Let's dive into this quickly.

 

What is Observer


Observer is an event listening class that will listen and can do action of any changes of that regarding Model.

That means, when we need to do something after a Model changes or after a model event occurs. Then, we can use Observer to listen to that change and can do any database operation easily with that model. It's super useful for big projects, where you need to do many stuffs after a model is being created.

 

How to create an Observer in Laravel


Observer can be created very easily with an Artisan command. Like, we want to create an UserObserver, which will listen to any changes on User Model.

// Demo to Create a UserObserver for User Model
php artisan make:observer UserObserver --model=User

So, here we're giving an Observer name and specifying which Model it will listen. In the above case, it will create an UserObserver and will listen any changes on User Model.

 

How is an Observer class look like

 

This will create a fresh UserObserver in app/Observers/UserObserver.php. Let's take a look at the UserObserver class.

<?php

namespace App\Observers;

use App\Models\User;

class UserObserver
{
    /**
     * Handle the User "created" event.
     *
     * @param  \App\Models\User  $user
     * @return void
     */
    public function created(User $user)
    {
        //
    }

    /**
     * Handle the User "updated" event.
     *
     * @param  \App\Models\User  $user
     * @return void
     */
    public function updated(User $user)
    {
        //
    }

    /**
     * Handle the User "deleted" event.
     *
     * @param  \App\Models\User  $user
     * @return void
     */
    public function deleted(User $user)
    {
        //
    }

    /**
     * Handle the User "restored" event.
     *
     * @param  \App\Models\User  $user
     * @return void
     */
    public function restored(User $user)
    {
        //
    }

    /**
     * Handle the User "force deleted" event.
     *
     * @param  \App\Models\User  $user
     * @return void
     */
    public function forceDeleted(User $user)
    {
        //
    }
}

Look, there are some functions like created, updated and so all. It's self-explanatory in the class name by itself.

For example - created will be called when Modal User is being created.

 

How many events in an Observer class

Observer class actually has more events, not only limited to the above events. Let's grab the default of here.

  1. created - When a modal is created, this function will be called simultaneously. For example, when an $user->save(); function will be called, A user will saved and then it will come here with User model in it's $user variable. So, we can get access the last changed model data here. Like, we can get $user->name here easily and also can modify and re-save the data again and do whatever we want with that data.
  2. updated - Called when a model is being updated. For example, when called the above function - save() and update(), this event will fired.
    1. $user = User::find(1);
    2. $user->save()
    3. or, User::where()->update([//...]);
  3. deleted - It's self-explanatory, when a delete() function will called on any model, it will be fired up.
  4. restored - It's used when we use SoftDelete in our model. When we use trash system of data in our model, this will be fired up after a restore of a specific modal data.
  5. forceDeleted - It'll be fired up, when we use forceDelete() function on any model. 

 

These are by default event. There's more we can get in Laravel observer. Let's grab them all.

  1. creating
  2. created
  3. saving
  4. saved
  5. deleting
  6. deleted
  7. updating
  8. updated
  9. restoring
  10. restored
  11. forceDeleted
  12. retreived

And I think, these functions are self-explanatory to self-learn.

 

Next,

We need to register this observer in EventServiceProvider class inside the boot() function of app/Providers/EventServiceProvider.php

<?php

namespace App\Providers;

use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;

// Import the classes
use App\Models\User;
use App\Observers\UserObserver;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
    ];

    /**
     * Register any events for your application.
     *
     * @return void
     */
    public function boot()
    {
        User::observe(UserObserver::class); // Use Here
    }
}

That's done. Our User model is now registered to UserObserver. UserObserver can detect everything and can take action of User model.

 

How to use Observer in a real-life project

 

Problem 1:

We need to add a Mr text before user's name when registered. Like after saved to database, we will update user name to something else.

It's very simple to do that.Here is our created() function inside UserObserver.

/**
* Handle the User "created" event.
*
* @param  \App\Models\User  $user
* @return void
*/
public function created(User $user)
{
    $user->name = "Mr. " . $user->name;
    $user->save();
}

So, to test it, create a User model. I'll use tinker commands to do that.

Open tinker terminal - 

php artisan tinker

Now, save a new user.

$user = new User();
$user->name = "Akash";
$user->email = "akash@gmail.com";
$user->password = Hash::make('123456');
$user->save();

Now check the database. Name is not Akash. Name is - modified to Mr. Akash.


That's pretty awesome, right.

 

Problem  2:

Assume, we're using Facebook. Where every time User updated his profile picture, a new post creates. And we can see that on post feed wall. 
So, we'll implement these things here.

  1. We'll create a user, and it would create a Post also with user ID and data
  2. We'll update a user, and it would create another post with updated information

 

First, Change Our UserObserver to this, so that we could add new Post after created() and updated() event.

<?php

namespace App\Observers;

use App\Models\Post;
use App\Models\User;

class UserObserver
{
    /**
     * Handle the User "created" event.
     *
     * @param  \App\Models\User  $user
     * @return void
     */
    public function created(User $user)
    {
        // $user->name = "Mr. " . $user->name;
        // $user->save();

        $title = 'New User ' . $user->name . ' Created successfully';
        $description = 'New User ' . $user->name . ' Created. Created - ' . $user->created_at->diffForHumans();

        Post::create([
            'title'       => $title,
            'description' => $description,
            'user_id'     => $user->id,
            'category_id' => 1
        ]);
    }

    /**
     * Handle the User "updated" event.
     *
     * @param  \App\Models\User  $user
     * @return void
     */
    public function updated(User $user)
    {
        $title = 'User ' . $user->name . ' Updated successfully';
        $description = 'User ' . $user->name . ' Updated. Updated time - ' . $user->updated_at->diffForHumans();

        Post::create([
            'title'       => $title,
            'description' => $description,
            'user_id'     => $user->id,
            'category_id' => 1,
        ]);
    }

    /**
     * Handle the User "deleted" event.
     *
     * @param  \App\Models\User  $user
     * @return void
     */
    public function deleted(User $user)
    {
        //
    }

    /**
     * Handle the User "restored" event.
     *
     * @param  \App\Models\User  $user
     * @return void
     */
    public function restored(User $user)
    {
        //
    }

    /**
     * Handle the User "force deleted" event.
     *
     * @param  \App\Models\User  $user
     * @return void
     */
    public function forceDeleted(User $user)
    {
        //
    }
}

 Before running Artisan command insert, let's check our Post model class to accept fillable property.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;

    protected $fillable = [
        'title',
        'description',
        'category_id',
        'user_id'
    ];
}

 

Great, all set up is done. Now just do some artisan command to check if Our desired posts added or not -

php artisan tinker;

// Create New User
$user = new User();
$user->name = "Fabliha";
$user->email = "fabliha@gmail.com";
$user->password = Hash::make('123456');
$user->save();

// Update a User
$user = User::orderBy('id', 'desc')->first();
$user->name = "Fabliha Afia";
$user->save();

 

Great, now check the database, or do the artisan command to check the last posts - 

php artisan tinker;

// Get last two latest post
Post::orderBy('id', 'desc')->limit(2)->get();


=> Illuminate\Database\Eloquent\Collection {#4136
     all: [
       App\Models\Post {#3412
         id: 20002,
         title: "User Fabliha Afia Updated successfully",
         description: "User Fabliha Afia Updated. Updated time - 1 second ago",
         user_id: 1004,
         category_id: 1,
         created_at: "2021-07-13 03:58:38",
         updated_at: "2021-07-13 03:58:38",
       },
       App\Models\Post {#4345
         id: 20001,
         title: "New User Afia Created successfully",
         description: "New User Afia Created. Created - 1 second ago",
         user_id: 1004,
         category_id: 1,
         created_at: "2021-07-13 03:53:59",
         updated_at: "2021-07-13 03:53:59",
       },
     ],
   }

Wow, we've added some posts based on this. And we can do many things in this observer.

 

I think it's pretty enough to start your advanced implementation using Laravel observer.

 

Next, Documented on Laravel

 

Scenario 1:

If we want to make a model and don't need to do any action on Observer, then we could use simply saveQuietly() function.

$user = User::findOrFail(1);

$user->name = 'Updated User';

$user->saveQuietly();

 

Scenario 2:

We want to run our Sales Transaction's observer after getting a valid commit() of Laravel Transaction

<?php

namespace App\Observers;

use App\Models\Transaction;

class TransactionObserver
{
    /**
     * Handle events after all transactions are committed.
     *
     * @var bool
     */
    public $afterCommit = true;

    /**
     * Handle the User "created" event.
     *
     * @param  \App\Models\Transaction  $transaction
     * @return void
     */
    public function created(Transaction $transaction)
    {
        //
    }
}

 

Laravel Observer Docshttps://laravel.com/docs/8.x/eloquent#observers

 

 

You can do the following things on Laravel Model Observer.

  1. Can Make a Log table where you would log of every activity of your site. After anything happens to model, you'll store that in Log. So, that you could make a log system easily with this.
  2. Sometimes, we need to process data after it's insertion on database.
  3. Like, we have some transactions and we would put total transaction amount to another Ledger balance of accounting. Then we could do it here. So transaction functionality could separate from Ledger Logic.
  4. We would update deleted_by, updated_by property of any model by using this.

 

Download Github Source Code - https://github.com/ManiruzzamanAkash/Laravel-Advanced-Topics/tree/observer-example

Thanks for staying with me about learning of Laravel Observer's advanced topic discussion.