laravel-eloquent について
Laravel 13 Eloquent ORMを扱う開発者向けのリファレンススキルです。モデルメタデータにPHP 8.3 Attributesを使う方法を軸に、リレーション、クエリ、モデルのライフサイクルを解説します。
主な機能
- 01PHP Attributesによるモデルメタデータ宣言
- 02各種リレーションとイーガーロード
- 03スコープ、イベント、ソフトデリート
- 04コレクション、シリアライズ、APIリソース
- 05トランザクション、ページネーション、バッチ処理
- 06クエリデバッグとパフォーマンス指針
活用シーン
- 01旧式モデルをLaravel 13向けに移行
- 02関連モデルを構築しN+1クエリを防止
- 03モデルイベントやソフトデリート、API出力を実装
- 04ファクトリーテストの作成とクエリ調整
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ fusengine/ agents --skill laravel-eloquentインストール後、Claude Code で/laravel-eloquentを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/accessors-mutators.mdaggregates.mdbatch-operations.mdcasts.mdcollections.mdeager-loading.mdevents-observers.mdfactories.mdlegacy-properties.mdmodels.mdpagination.mdperformance.mdquery-debugging.mdrelationships-advanced.mdrelationships-basic.mdrelationships-many-to-many.mdrelationships-polymorphic.mdresources.mdscopes.mdserialization.mdsoft-deletes.mdtransactions.mdreferences/templates/EagerLoadingExamples.php.mdFactory.php.mdModelBasic.php.mdModelCasts.php.mdModelRelationships.php.mdObserver.php.mdResource.php.md詳細
Laravel 13 Eloquent ORM を対象に、PHP 8.3 Attributes を主要なメタデータの仕組みとして扱います(#[Table]、#[Fillable]、#[Hidden]、#[Visible]、#[Guarded]、#[Appends]、#[Touches]、#[Connection]、#[Refreshes])。下位互換性のための従来のプロパティ相当の設定も含みます。すべてのリレーションシップの種類(基本、多対多、高度なリレーションシップ、ポリモーフィック)、Eager Loading、スコープ、アクセサー/ミューテーター、イベント/オブザーバー、ソフトデリート、コレクション、シリアライズ、ファクトリー、API リソース、トランザクション、ページネーション、集計、バッチ操作、クエリのデバッグ/パフォーマンスも扱います。
Laravel Eloquent ORM(L13 — Attributes 優先)
エージェントのワークフロー(必須)
実装を始める前に、name を指定した Agent 呼び出しをそれぞれ 1 回行い、3 つのエージェントを並列で起動してください。
- fuse-ai-pilot:explore-codebase - 既存のモデルと、プロパティと Attributes が混在している箇所を調査します
- fuse-ai-pilot:research-expert - Context7 を使って Laravel 13 の Eloquent と Attributes のドキュメントを確認します
- mcp__context7__query-docs - Attribute のパターン(#[Fillable]、#[Table]、#[Scope])を検索します
実装後、検証のために fuse-ai-pilot:sniper を実行してください。
概要
Laravel 13 では、Eloquent モデルの主要なメタデータの仕組みとして PHP 8.3 Attributes が採用されています。下位互換性のため、従来のプロパティ($fillable、$hidden、...)も引き続きサポートされていますが、対応する Attribute と併用しないでください。
| 機能 | Attribute(L13 の主な方法) | 従来のプロパティ |
|---|---|---|
| テーブル名 | #[Table('users')] | protected $table |
| 一括代入 | #[Fillable([...])] | protected $fillable |
| 非表示/表示 | #[Hidden([...])] / #[Visible([...])] | protected $hidden / $visible |
| ガード対象 | #[Guarded([...])] / #[Unguarded] | protected $guarded |
| キャスト | Attribute なし — casts() メソッド | protected $casts |
| 追加項目 | #[Appends([...])] | protected $appends |
| タッチ対象 | #[Touches([...])] | protected $touches |
| 接続 | #[Connection('mysql')] | protected $connection |
| 主キー | #[Table(key: 'uuid', keyType: 'string', incrementing: false)] | $primaryKey / $keyType / $incrementing |
| タイムスタンプを無効化 | #[WithoutTimestamps] | public $timestamps = false |
| 書き込み後にリフレッシュ(13.33+) | #[Refreshes(['slug'])] | — |
重要なルール
- Attributes を信頼できる唯一の情報源にします - 新しいコードでは
#[Fillable]、#[Hidden]、#[Table]を使います(キャストはcasts()に記述します) - 同じ設定に Attribute とプロパティを併用しないでください(
#[Fillable]と$fillableの併用など) - リレーションシップを Eager Load します -
with()を使って N+1 クエリを防ぎます - モデル自身の
boot()/トレイトのboot*()内でnew static()/new Model()を使わないでください - L13 ではネストしたブートが禁止されているため、LogicExceptionがスローされます - テストではファクトリーを使います - テストデータをハードコードしないでください
アーキテクチャ
app/Models/
├── User.php # #[Table], #[Fillable], #[Hidden] + casts()
├── Post.php # #[Connection], #[Appends], relationships
└── Concerns/
└── HasUuid.php # Reusable trait
→ templates/ModelBasic.php.md を参照してください
リファレンスガイド
概念
- L12→L13 の移行: legacy-properties.md
- モデリング: models.md · casts.md · accessors-mutators.md · serialization.md · soft-deletes.md
- リレーションシップ: relationships-basic.md · relationships-many-to-many.md · relationships-advanced.md · relationships-polymorphic.md
- クエリ: eager-loading.md · scopes.md · aggregates.md · pagination.md · batch-operations.md · query-debugging.md
- ライフサイクル/出力: events-observers.md · collections.md · resources.md · factories.md · transactions.md · performance.md
テンプレート
| テンプレート | 使用する場面 |
|---|---|
| ModelBasic.php.md | 属性ベースのモデル |
| ModelRelationships.php.md | すべてのリレーションシップタイプ |
| ModelCasts.php.md | casts() とアクセサー |
| Observer.php.md | 完全なオブザーバー |
| Factory.php.md | 状態を持つファクトリー |
| Resource.php.md | API リソース |
| EagerLoadingExamples.php.md | N+1 の防止 |
クイックリファレンス
属性ベースのモデル(L13 MAIN)
use Illuminate\Database\Eloquent\Attributes\{Table, Fillable, Hidden};
use Illuminate\Database\Eloquent\Model;
#[Table('users')]
#[Fillable(['name', 'email', 'password'])]
#[Hidden(['password', 'remember_token'])]
final class User extends Model
{
protected function casts(): array
{
return ['email_verified_at' => 'datetime', 'is_admin' => 'boolean'];
}
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
}
スコープ(属性構文)
#[Scope]
protected function published(Builder $query): void
{
$query->whereNotNull('published_at');
}
// Usage: Post::published()->get();
Eager Loading
$posts = Post::with('author')->get(); // 2 queries, not N+1
13.x の追加機能
#[Refreshes(['slug'])] // 13.33+: re-read generated columns after insert/update
final class Post extends Model {}
DB::transaction(function () use ($flight) {
$flight->refreshForUpdate(); // 13.27+: reload with a FOR UPDATE lock
});
→ レガシーな $fillable / $hidden スタイルについては、legacy-properties.md を参照してください。
ベストプラクティス
すること
- メタデータは PHP Attributes(
#[Table]、#[Fillable]、#[Hidden]など)で宣言します - 継承しないモデルクラスには
finalを指定します with()で Eager Loading します- テストではファクトリーを使用します
casts()メソッドで日付、配列、列挙型をキャストします(#[Casts]属性はありません)
しないこと
- 同じモデルで
#[Fillable]と$fillableを混在させる(競合します。信頼できる情報源は1つにしてください) - モデル自身の
boot()/trait のboot*()内でモデルをインスタンス化する — L13 はLogicExceptionをスローします - ループ内でリレーションシップを遅延ロードする(N+1)
- 本番環境で
#[Unguarded]を使用する - アクセサー/ミューテーター内でクエリを実行する
- ビジネスロジックをモデルに記述する(サービス/アクションを使用してください)
コメント
Markdown 対応