#06 Laravel基礎
Eloquentリレーション — hasOne / hasMany / belongsTo
リレーションとは
データベースの複数のテーブルを関連づける仕組みを リレーション? テーブルとテーブルの関係のこと。「1人のユーザーは複数の投稿を持つ」のような関係をコードで表現できる。 と呼びます。例えば:
- 1人のユーザーは複数の投稿を持つ(1対多)
- 1つの投稿は1つのサムネイルを持つ(1対1)
- 1つの投稿は1人のユーザーに属する(多対1)
Eloquentを使うと、これらの関係をシンプルなメソッドで表現できます。
マイグレーションで外部キーを作る
まず前提として、リレーションにはデータベースの 外部キー? 別のテーブルの主キーを参照するカラム。テーブル間の関係を表す。例:投稿テーブルの`user_id`でユーザーテーブルを参照。 が必要です。
<?php
// 📁 database/migrations/xxxx_create_posts_table.php
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id') // ← 外部キーカラムを追加
->constrained() // ← users.id を参照すると自動認識
->cascadeOnDelete(); // ← ユーザーが削除されたら投稿も削除
$table->string('title');
$table->text('body');
$table->timestamps();
});
foreignId('user_id')->constrained() は users テーブルの id を参照する外部キーを作ります。constrained() に引数を渡せば別テーブルも指定できます(例:constrained('admins'))。
1対多:hasMany
「1人のユーザーは複数の投稿を持つ」関係です。
<?php
// 📁 app/Models/User.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function posts()
{
return $this->hasMany(Post::class);
// デフォルトで posts.user_id = users.id として検索する
}
}
使い方:
// あるユーザーのすべての投稿を取得
$user = User::find(1);
$posts = $user->posts; // → Post のコレクション
多対1:belongsTo
「投稿はユーザーに属する」という逆方向の関係です。
<?php
// 📁 app/Models/Post.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
public function user()
{
return $this->belongsTo(User::class);
// posts.user_id を使って users.id を検索する
}
}
使い方:
// ある投稿の作者を取得
$post = Post::find(1);
$author = $post->user; // → User モデル
1対1:hasOne
「ユーザーは1つのプロフィールを持つ」関係です。
// 📁 app/Models/User.php
public function profile()
{
return $this->hasOne(Profile::class);
// profiles.user_id = users.id として検索する
}
// 📁 app/Models/Profile.php
public function user()
{
return $this->belongsTo(User::class);
}
使い方:
$user = User::find(1);
$bio = $user->profile->bio;
リレーションを使ったクエリ
リレーションはそのままプロパティとしてアクセスできますが、メソッドとして呼び出すとクエリビルダーとして使えます。
// プロパティアクセス(結果のコレクションを返す)
$posts = $user->posts;
// メソッド呼び出し(クエリをさらに絞り込める)
$publishedPosts = $user->posts()->where('status', 'published')->latest()->get();
whereHas でリレーションを条件にする
// 公開済み投稿を持つユーザーだけを取得
$activeUsers = User::whereHas('posts', function ($query) {
$query->where('status', 'published');
})->get();
リレーション先のデータを保存する
// ユーザーに紐づいた投稿を作成
$user = User::find(1);
// create() を使う方法(user_id が自動でセットされる)
$post = $user->posts()->create([
'title' => '新しい投稿',
'body' => '本文です',
]);
まとめ
hasMany()→ 1対多の「持つ側」(User has many Posts)belongsTo()→ 多対1の「属する側」(Post belongs to User)hasOne()→ 1対1の「持つ側」(User has one Profile)- マイグレーションで
foreignId()->constrained()を使うと外部キーを簡単に定義できる $user->posts()とメソッド呼び出しにするとクエリを追加できる
次回はEagerロードとN+1問題の解決を学びます。