章: 第2章: データベース応用
$post['user_id'] からユーザーを取得するために毎回クエリを書いていませんか?
投稿の著者を取得するたびに WHERE id = ? を書くのは非効率です。Eloquentのリレーションを使えば、$post->user->name と書くだけで関連データを取得できます。
hasMany・belongsToなどのリレーションメソッドを定義することで、テーブルのJOINをPHPのオブジェクト関係として表現できます。
リレーションの実装
<?php
class User extends Model {
public function posts(): HasMany {
return $this->hasMany(Post::class);
}
}
class Post extends Model {
public function user(): BelongsTo {
return $this->belongsTo(User::class);
}
}
$user = User::find(1);
foreach ($user->posts as $post) {
echo $post->title;
}
リレーションの種類と使いどころ
| リレーション | 方向 | 例 |
hasOne |
1対1(所有側) | User → Profile |
belongsTo |
1対1・1対多(従属側) | Post → User |
hasMany |
1対多(所有側) | User → Posts |
belongsToMany |
多対多 | Post ↔ Tag |
チェックポイント:
$user->postsはプロパティアクセスで「全件コレクション」を取得します。$user->posts()はリレーションのクエリビルダを返すので、.where('status', 'published')->get()のように条件を追加できます。
イーガーローディングでN+1を防ぐ
<?php
// NG: N+1が発生する
$posts = Post::all();
foreach ($posts as $post) {
echo $post->user->name; // ループのたびにクエリ発行
}
// OK: withで一括取得
$posts = Post::with('user')->get();
foreach ($posts as $post) {
echo $post->user->name; // 追加クエリなし
}
チェックポイント:
with('user')を忘れると前回学んだN+1問題がリレーションで発生します。常にイーガーローディングを意識しましょう。
まとめ & 次のステップ
hasMany/belongsToでテーブルの関連をモデルに定義する- プロパティアクセスでコレクション取得、メソッドアクセスでクエリビルダを取得
with()イーガーローディングでN+1問題を防ぐ
次回はEloquentスコープとキャストを学びます。クエリの条件をモデルに封じ込め、型変換を自動化する方法です。