Documentation Index Fetch the complete documentation index at: https://kawax.biz/llms.txt
Use this file to discover all available pages before exploring further.
モデルイベントとは
Eloquentモデルはライフサイクルの各タイミングで自動的にイベントを発火します。これらのイベントにフックすることで、モデルの保存・削除などの前後に処理を差し込めます。
Eloquentが発火するイベントは以下のとおりです。
イベント 発生タイミング retrievedDBからモデルを取得したとき creating新規モデルを保存する直前 created新規モデルを保存した直後 updating既存モデルを更新する直前 updated既存モデルを更新した直後 saving新規作成・更新のどちらかで保存する直前 saved新規作成・更新のどちらかで保存した直後 deletingモデルを削除する直前 deletedモデルを削除した直後 trashedソフトデリートした直後 forceDeleting物理削除する直前 forceDeleted物理削除した直後 restoringソフトデリートを復元する直前 restoredソフトデリートを復元した直後 replicatingreplicate() を呼び出したとき
-ing で終わるイベントは変更がDBに永続化される前 に、-ed で終わるイベントは後 に発火します。
マスアップデートやマスデリート(User::where(...)->update(...) など)では、saving、saved、updating、updated、deleting、deleted イベントは発火しません。モデルが実際には取得されないためです。
クロージャを使ったイベントリスナー
イベントをシンプルに扱いたい場合は、モデルの booted メソッド内でクロージャを登録できます。
<? php
namespace App\Models ;
use Illuminate\Database\Eloquent\ Model ;
class User extends Model
{
protected static function booted () : void
{
static :: created ( function ( User $user ) {
// ユーザー作成後に実行される処理
});
static :: deleting ( function ( User $user ) {
// ユーザー削除前に実行される処理
});
}
}
処理をキューで非同期実行したい場合は queueable ヘルパーを使います。
use function Illuminate\Events\ queueable ;
static :: created ( queueable ( function ( User $user ) {
// キューで非同期実行される
}));
$dispatchesEvents プロパティ
Laravelのイベントシステムと連携したい場合は、$dispatchesEvents プロパティでモデルイベントを独自のイベントクラスにマッピングします。
<? php
namespace App\Models ;
use App\Events\ UserDeleted ;
use App\Events\ UserSaved ;
use Illuminate\Foundation\Auth\ User as Authenticatable ;
class User extends Authenticatable
{
/**
* モデルイベントとイベントクラスのマッピング
*
* @var array < string , string>
*/
protected $dispatchesEvents = [
'saved' => UserSaved :: class ,
'deleted' => UserDeleted :: class ,
];
}
マッピングしたイベントクラスには、コンストラクタでモデルのインスタンスを受け取ります。
<? php
namespace App\Events ;
use App\Models\ User ;
class UserSaved
{
public function __construct (
public readonly User $user ,
) {}
}
Observerクラスの作成
1つのモデルに対して複数のイベントを処理する場合、クロージャを並べるよりもObserverクラスにまとめるほうがすっきりします。
Artisanコマンドでクラスを生成する
make:observer コマンドで雛形を生成します。--model オプションでモデルを指定すると、対応するメソッドが自動で追加されます。php artisan make:observer UserObserver --model=User
app/Observers/UserObserver.php が生成されます。
各イベントのメソッドを実装する
メソッド名がイベント名に対応します。引数にはモデルのインスタンスが渡されます。 <? php
namespace App\Observers ;
use App\Models\ User ;
class UserObserver
{
public function created ( User $user ) : void
{
// ユーザー作成後の処理
}
public function updated ( User $user ) : void
{
// ユーザー更新後の処理
}
public function deleted ( User $user ) : void
{
// ユーザー削除後の処理
}
public function restored ( User $user ) : void
{
// ソフトデリート復元後の処理
}
public function forceDeleted ( User $user ) : void
{
// 物理削除後の処理
}
}
ObserverをModelに登録する
登録方法は2つあります。Laravel 13では #[ObservedBy] アトリビュートを使う方法が推奨されます。 方法1: #[ObservedBy] アトリビュート(推奨) モデルクラスにアトリビュートを付与するだけで登録が完了します。AppServiceProvider の変更が不要です。 <? php
namespace App\Models ;
use App\Observers\ UserObserver ;
use Illuminate\Database\Eloquent\Attributes\ ObservedBy ;
use Illuminate\Foundation\Auth\ User as Authenticatable ;
#[ ObservedBy ( UserObserver :: class )]
class User extends Authenticatable
{
//
}
複数のObserverを登録する場合はアトリビュートを繰り返すか、配列で渡します。 #[ ObservedBy ( UserObserver :: class )]
#[ ObservedBy ( AuditObserver :: class )]
class User extends Authenticatable
{
//
}
方法2: AppServiceProvider で登録する AppServiceProvider の boot メソッドで observe を呼び出します。<? php
namespace App\Providers ;
use App\Models\ User ;
use App\Observers\ UserObserver ;
use Illuminate\Support\ ServiceProvider ;
class AppServiceProvider extends ServiceProvider
{
public function boot () : void
{
User :: observe ( UserObserver :: class );
}
}
#[ObservedBy] アトリビュートは Illuminate\Database\Eloquent\Attributes 名前空間にあります。PHP 8.0以降のネイティブ構文で、Laravel 13で積極的に採用されています。
データベーストランザクション内でのObserver
モデルがトランザクション内で作成・更新される場合、トランザクションのコミット後にObserverを実行したいことがあります。ShouldHandleEventsAfterCommit インターフェースを実装するとその挙動になります。
<? php
namespace App\Observers ;
use App\Models\ User ;
use Illuminate\Contracts\Events\ ShouldHandleEventsAfterCommit ;
class UserObserver implements ShouldHandleEventsAfterCommit
{
public function created ( User $user ) : void
{
// トランザクションがコミットされた後に実行される
}
}
トランザクション外で実行された場合は、通常どおり即時実行されます。
イベントを一時的に無効化する
withoutEvents で特定の処理だけイベントを止める
User::withoutEvents() に渡したクロージャ内では、一切のモデルイベントが発火しません。
use App\Models\ User ;
$user = User :: withoutEvents ( function () {
User :: findOrFail ( 1 ) -> delete ();
return User :: find ( 2 );
});
saveQuietly で保存時のイベントを止める
イベントを発火させずにモデルを保存したいときは saveQuietly を使います。
$user = User :: findOrFail ( 1 );
$user -> name = 'Victoria Faith' ;
$user -> saveQuietly ();
同様のメソッドが削除・復元・レプリケートにも用意されています。
$user -> deleteQuietly ();
$user -> restoreQuietly ();
実践的なユースケース
キャッシュの自動クリア
モデルが更新・削除されたときに関連するキャッシュを自動でクリアします。
<? php
namespace App\Observers ;
use App\Models\ Post ;
use Illuminate\Support\Facades\ Cache ;
class PostObserver
{
public function saved ( Post $post ) : void
{
Cache :: forget ( "post:{ $post -> id }" );
Cache :: forget ( 'posts:latest' );
}
public function deleted ( Post $post ) : void
{
Cache :: forget ( "post:{ $post -> id }" );
Cache :: forget ( 'posts:latest' );
}
}
監査ログの記録
モデルの変更履歴を自動で記録します。getDirty() で変更前後の値を取得できます。
<? php
namespace App\Observers ;
use App\Models\ AuditLog ;
use App\Models\ User ;
class UserObserver
{
public function updating ( User $user ) : void
{
AuditLog :: create ([
'model_type' => User :: class ,
'model_id' => $user -> id ,
'changes' => $user -> getDirty (),
'user_id' => auth () -> id (),
]);
}
public function deleted ( User $user ) : void
{
AuditLog :: create ([
'model_type' => User :: class ,
'model_id' => $user -> id ,
'changes' => [ 'deleted' => true ],
'user_id' => auth () -> id (),
]);
}
}
updating イベントはDBへの保存前 に発火するため、getDirty() で変更予定の値を取得できます。updated イベント後に呼ぶと getDirty() は空になります。
関連モデルの自動更新
注文が完了したときに在庫数を自動で更新する例です。
<? php
namespace App\Observers ;
use App\Models\ Order ;
class OrderObserver
{
public function created ( Order $order ) : void
{
foreach ( $order -> items as $item ) {
$item -> product -> decrement ( 'stock' , $item -> quantity );
}
}
public function deleted ( Order $order ) : void
{
foreach ( $order -> items as $item ) {
$item -> product -> increment ( 'stock' , $item -> quantity );
}
}
}
次のステップ
上級: PHPアトリビュート #[ObservedBy] を含む、Laravel 13のPHPアトリビュートをまとめて学びます。