第18回: Eloquentスコープとキャスト — 条件と型変換を「モデルに集める」

章: 第2章: データベース応用

->where('status', 'published') を何度も書いていませんか?

コントローラAでも、サービスクラスBでも、同じ ->where('status', 'published') を繰り返し書いていませんか?もし「公開済み」の定義が変わったら、すべての箇所を変更しなければなりません。

スコープはこうした繰り返す条件をモデルに閉じ込め、Post::published() と書くだけで条件を再利用できます。キャストはDBから取得した値の型変換を自動化し、コントローラで手動変換する必要をなくします。

スコープとキャストの実装


<?php
class Post extends Model {
    public function scopePublished(Builder $query): Builder {
        return $query->where('status', 'published');
    }
    protected $casts = [
        'meta'         => 'array',
        'published_at' => 'datetime',
    ];
}
$posts = Post::published()->get();

コントローラに書く vs モデルのスコープ

観点 コントローラに直書き モデルのスコープ
再利用性 各コントローラに同じコード Post::published() だけで使える
条件変更 全箇所を修正 モデルだけ修正
テスト コントローラごとにテスト スコープを単独でテスト
読みやすさ クエリの意図が埋もれる メソッド名が意図を表す

チェックポイント: スコープのメソッド名は scope プレフィックスを付けて定義しますが、呼び出し時は Post::published() と省略形で使います。

キャストの種類


<?php
class Post extends Model {
    protected $casts = [
        'meta'         => 'array',      // JSON文字列→配列
        'published_at' => 'datetime',   // 文字列→Carbonインスタンス
        'is_featured'  => 'boolean',    // "0"/"1"→true/false
        'price'        => 'decimal:2',  // 文字列→小数点2桁
    ];
}

$post = Post::find(1);
$post->meta['key'];          // 配列として直接アクセス
$post->published_at->format('Y/m/d'); // Carbonのメソッドが使える
$post->is_featured === true;  // boolean比較が正確

チェックポイント: 'datetime' キャストを使うと、$post->published_at が自動的に Carbon インスタンスになります。日付操作のコードが大幅にシンプルになります。

まとめ & 次のステップ

  • スコープはクエリの繰り返し条件をモデルに集めて再利用できる
  • キャストはDBから取得した値の型変換を自動化し、手動変換コードをなくす
  • どちらもコントローラを薄く保ち、モデルに責務を集中させる設計

次回はSeederとテストデータ管理を学びます。開発・テスト環境に一貫したデータを自動投入する仕組みです。

Related Articles