🐼

Laravel Observerを使ってみた

2023/11/29に公開

はじめに

Laravel 10のEloquentで提供されるObserverはモデルにおいてCRUD処理などを行う際に、毎回実行される処理を設定することができるので便利。

Observerの設定

Observerの生成

app/Observersフォルダ配下に生成される

php artisan make:observer UserObserver --model=User

作成されたObserverファイルの中身。生成時に指定したmodelがベースになっている

UserObserver.php
<?php

namespace App\Observers;

use App\Models\User;

class UserObserver
{
    /**
     * Handle the User "created" event.
     */
    public function created(User $user): void
    {
        //
    }

    /**
     * Handle the User "updated" event.
     */
    public function updated(User $user): void
    {
        //
    }

    /**
     * Handle the User "deleted" event.
     */
    public function deleted(User $user): void
    {
        //
    }

    /**
     * Handle the User "restored" event.
     */
    public function restored(User $user): void
    {
        //
    }

    /**
     * Handle the User "force deleted" event.
     */
    public function forceDeleted(User $user): void
    {
        //
    }
}

Observerの登録

モデルのobserveメソッドを呼び出す。

App\Providers\EventServiceProvider.php
use App\Models\User;
use App\Observers\UserObserver; // 追加
 
/**
 * Register any events for your application.
 */
public function boot(): void
{
    User::observe(UserObserver::class); // 追加
}

再利用できるObserverの設定

複数モデルで利用した場合の例

ファイル作成

App\Observers\FooBarObserver.php
<?php

namespace App\Observers;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;

class FooBarObserver
{
    /**
     * @param Model $model
     * @return void
     */
    public function creating(Model $model)
    {
        if (Auth::user()) {
            $model->created_by = Auth::user()->id;
            $model->updated_by = Auth::user()->id;
        }
    }

    /**
     * @param Model $model
     * @return void
     */
    public function updating(Model $model)
    {
        //
    }

    /**
     * @param Model $model
     * @return void
     */
    public function saving(Model $model)
    {
        //
    }

    /**
     * @param Model $model
     * @return void
     */
    public function deleting(Model $model)
    {
        //
    }
}

設定

boot{トレイト名}で作っておくとクラス呼び出し時に書かれた処理が行われる。
\Illuminate\Database\Eloquent\Model::bootTraitsがうまいことやってくれるようだ)

App\Traits\FooBarTrait.php
<?php

namespace App\Traits;

use App\Observers\FooBarObserver;

trait FooBarTrait
{
    public static function bootFooBarTrait()
    {
        static::observe(FooBarObserver::class);
    }
}

利用するモデルでロード

App\Models\Foo
<?php

namespace App\Models;

use App\Traits\FooBarTrait; // 追加
use Illuminate\Database\Eloquent\Model;

class Foo extends Model
{
    use FooBarTrait; // 追加
}

Eventメソッド

メソッド名の違い

creating(現在進行形):モデルがDBに保存される前に実行される
created (過去形):モデルがDBに保存される前に実行される

DBトランザクション

DBトランザクションがコミットされた後に変更を加えたい場合、ShouldHandleEventsAfterCommit インターフェースを利用できる。

UserObserver.php
<?phpnamespace App\Observers;use App\Models\User;
use Illuminate\Contracts\Events\ShouldHandleEventsAfterCommit; // 追加class UserObserver implements ShouldHandleEventsAfterCommit // ここ
{
    /**
     * Handle the User "created" event.
     */
    public function created(User $user): void
    {
        //
    }
}

課題

Model::insertには効かなかった問題の調査

OK

$user = new User;
$user->name = $request->name,
$user->email = $request->email,

$user->save();

NG

$users = [
    ['name' => 'Pikachu', 'email' => 'pikachu@example.com'],
    ['name' => 'Eevee', 'email' => 'eevee@example.com'],
];

User::insert($users);

参考

Observer
https://laravel.com/docs/10.x/eloquent#observers

Event
https://laravel.com/docs/10.x/eloquent#events

Discussion