routes/web.php
Route::get('/user/{id}',function($id){
$user = User::with('profile')->findOrFail($id);
return view('user',compact('user'));
});
Route::get('/profile/{id}',function($id){
$profile = Profile::with('user')->findOrFail($id);
return view('profile',compact('profile'));
});
如下圖:
resources/views/user.blade.php
<h1>{{ $user->profile->id }}</h1>
<p>{{ $user->profile->bio }}</p>
<p>{{ $user->profile->phone }}</p>
如下圖:
resources/views/profile.blade.php
<h1>{{ $profile->user->id }}</h1>
<p>{{ $profile->user->name }}</p>
<p>{{ $profile->user->email }}</p>
如下圖:
(6)用 Seeder 建立 10 筆資料
指令:php artisan make:seeder UserSeeder
for ($i = 1; $i <= 10; $i++) {
$user = User::create([
'name' => 'User ' . $i,
'email' => 'user' . $i . '@example.com',
'password' => bcrypt('admin'.$i),
]);
$user->profile()->create([
'bio' => 'This is bio for user ' . $i,
'phone' => '09000000' . $i,
]);
}
如下圖:
執行seeder
指令:php artisan db:seed --class=UserSeeder
如下圖:
此時,http://127.0.0.1:8080/phpmyadmin/ 可看到
在127.0.0.1:8000/profile/1 與 127.0.0.1:8000/user/1 可看到
2.Laravel 12 一對多關聯教學|掌握 Eloquent 關聯
以 User(使用者)→ Post(文章) 範例說明,一個 User 可以有多篇 Post。
一個 User 有多篇 Post;一篇 Post 屬於某個 User
(1)利用Chatgpt 來建立範例
a.請給我一個 laravel 12 範例,關於Laravel 12 一對多關聯教學|掌握 Eloquent 關聯。
b.那如何在上述範例中,建立10筆資料。請詳加說明。
(2)繼續利用原先的OneToOne 的專案,users table 已經完成。
接下來,建立posts table 語法:php artisan make:migration create_posts_table
如下圖:
編輯內容:
$table->id();
$table->unsignedBigInteger('user_id');//外鍵
$table->string('title');
$table->text('content');
$table->timestamps();
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
如下圖:
(3)建立 Models 與 關聯
a.建立Post Model指令:php artisan make:model PostPost Model — 一篇 Post 屬於 User
app/Models/Post.php
protected $fillable = [
'user_id','title','content'
];
public function user() {
return $this->belongsTo(User::class);
}
如下圖: b.User Model — 一個 User 有多個 Post
app/Models/User.php
public function posts() {
return $this->hasMany(Post::class);
}
如下圖:

(4)用 Route + Controller +Blade 顯示示範
routes/web.php
Route::get('/posts/{id}',function($id){
$user = User::with('posts')->findOrFail($id);
return view('posts',compact('user'));
});
如下圖:

resources/views/posts.blade.php <h1>{{ $user->name }}</h1>
<h2>Posts</h2>
<ul>
@foreach ($user->posts as $post)
<li>{{ $post->title }}</li>
@endforeach
</ul>
如下圖:

(5) 清除原先的users table 與 profiles table 資料 並重新建立users table、profiles table 與 posts table 資料指令:php artisan migrate:reset 與 php artisan migrate
a.建立 10 筆 User +10 筆 Profile + 多筆 Post(一對多示範)
database/seeders/UserSeeder.php
// 每個user 建立3篇文章
for ($j = 1;$j <= 3; $j++) {
$user->posts()->create([
'title' => "User $i - Post $j",
'content' => "Content for post $j of User $i.",
]);
}
如下圖:

b.執行seeder
指令:php artisan db:seed --class=UserSeeder
此時,http://127.0.0.1:8080/phpmyadmin/ 可看到

在127.0.0.1:8000/posts/1

3.Laravel 12 多對多關聯教學|Eloquent Pivot 樞紐表詳解
User ↔ Role 範例
一個 User 可以有多個 Role;一個 Role 可以屬於多個 User
(1)利用Chatgpt 來建立範例 a.請給我一個 laravel 12 範例,關於Laravel 12 多對多關聯教學|Eloquent Pivot 樞紐表詳解
b.那如何在上述範例中,建立10筆資料。請詳加說明。
(2)繼續利用原先的OneToOne 的專案,users table 已經完成。
接下來,建立roles table 語法:php artisan make:migration create_roles_table
編輯其內容:
$table->id();
$table->string('name');
$table->timestamps();
如下圖:
(3)建立 pivot:role_user 樞紐表
Laravel 多對多慣例使用 role_user(字母順序)
指令:php artisan make:migration create_role_user_table 編輯其內容:
$table->id();
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('role_id');
// 樞紐表額外欄位(可加可不加)
$table->boolean('is_active')->default(true);
// pivot 也可以有 timestamps
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
如下圖:
(4)Model 設定(belongsToMany)a.User Model app/Models/User.php
public function roles() {
return $this->belongsToMany(Role::class)
->with(['is_active']) // Pivot 額外欄位
->withTimestamps(); // Pivot timestamps
}
如下圖:
b.Role Model
app/Models/Role.php
指令:php artisan make:model Role編輯其內容:
protected $fillable = ['name'];
public function users() {
return $this->belongsToMany(User::class)
->withPivot(['is_active'])
->withTimestamps();
}
如下圖:
(5)Route+Controller 範例 a.Route
routes/web.php
編輯內容:
Route::get('/assign-role',[RoleController::class,'assignRole']);
如下圖:指令:php artisan make:controller RoleController
app/Http/Controllers/RoleController.php
public function assignRole() {
$user = User::find(1);
$user->roles()->attach([
1 => ['is_active' => true],
2 => ['is_active' => false],
]);
return "Roles assigned!";
}
如下圖:

(6)清除原先的users table、profiles table 與 posts table 資料
指令:php artisan migrate:reset 與 php artisan migrate
a.Seeder 建立 10 個 User + 3 個 Role + 關聯
database/seeders/DatabaseSeeder.php
//建立角色
$admin = Role::create((['name' => 'Admin']));
$editor = Role::create(['name' => 'Editor']);
$viewer = Role::create(['name' => 'Viewer']);
//建立10 個 user
for ($i = 1;$i <= 10;$i++) {
$user = User::create([
'name' => "User $i",
'email' => "User$i@gmail.com",
'password' => bcrypt('User'.$i),
]);
// 隨機給 user 賦予角色
$user->roles()->attach([
$admin->id => ['is_active' => rand(0,1)],
$editor->id => ['is_active' => rand(0,1)],
]);
}
如下圖:
b.執行,指令為 php artisan db:seed (7) 在http://127.0.0.1:8080/phpmyadmin/ 可看到
4.Laravel 12 Has One Through 關聯|Eloquent 間接一對一關聯
透過中介 Model,間接取得另一個 Model 的單一資料。
Country → User → Post
一個國家(Country)有很多使用者(Users)
一個使用者(User)有一篇主要文章(Post)
我們希望:
Country 可以直接取得它底下的某個 User 的 Post(間接一對一)如圖:
因此,使用 hasOneThrough()。
(1)利用Chatgpt 來建立範例
a.請給我一個 Laravel 12 範例,關於Has One Through 關聯|Eloquent 間接一對一關聯詳解
b.那如何在上述範例中,建立10筆資料。請詳加說明。
(2)建立hasOneThrough專案語法:composer create-project laravel/laravel hasOneThrough (3)建立資料表結構(migrations)
a.此時已內建create_users_table,編輯其內容:$table->foreignId('country_id')->constrained()->onDelete('cascade');
如下圖:

b.建立create_countries_table,指令:php artisan make:migration create_countries_table,編輯其內容:
如下圖:

c.建立create_posts_table,指令:php artisan make:migration create_posts_table,編輯其內容:
$table->foreignId('user_id')->constrained()->onDelete('cascade');
如下圖:

(4)Model 設定(hasOneThrough)
a.建立 Country Model,指令:php artisan make:model Country,編輯內容如下:
public function post() {
return $this->hasOneThrough(
Post::class,// 最後要取得的 Model
User::class,// 中間 Model
'country_id',// users.country_id(中介 model 外鍵)
'user_id',// posts.user_id(最後 model 外鍵)
'id',// countries.id(本身 PK)
'id'// users.id(與 posts.user_id 連接)
);
}
如下圖:
b.已有 User Model,不需要建立,編輯內容如下:
public function country() {
return $this->belongsTo(Country::class);
}
public function posts() {
return $this->hasMany(Post::class);
}
如下圖:

c.建立 Post Model,指令:php artisan make:model Post,編輯內容如下:
public function user() {
return $this->belongsTo(User::class);
}
如下圖:
(5)建立Seeder資料(建立 10 個 Country,其下自動建立 User + Post) a.建立CountrySeeder 指令:php artisan make:seeder CountrySeeder
編輯 database/seeders/CountrySeeder.php
for ($i=1;$i<=10;$i++) {
//建立國家
$country = Country::create([
'name' => "Country $i",
]);
//每個國家建立2個使用者
for ($u=1;$u<=2;$u++) {
$user = User::create([
'country_id' => $country->id,
'name' => "User {$i}-{$u}",
'email' => "user$i-$u@gmail.com",
'password' => bcrypt("demo1234"),
]);
//每個使用者建立1篇文章
Post::create([
'user_id' => $user->id,
'title' => "Post from User {$i}-{$u}",
]);
}
}
如下圖:
b.編輯 database/seeders/DatabaseSeeder.php
//註冊 seeder
$this->call(CountrySeeder::class);
如下圖:
c.執行 php artisan db:seed
注意,此時會一直出錯。
若是使用php artisan migrate:reset 回到初始狀態,再 php artisan migrate ,就會一直出錯,原因是順序。到 phpmyadmin,刪除 users ,再調整 migrations 的時間順序。如下圖:
處理完後,再 php artisan db:seed 就會順利。
(5) Route + Controller 範例
a.編輯 /routes/web.php
Route::get('/countries/{id}/post', [CountryController::class, 'post']);
如下圖:
b.建立CountryController ,指令:php artisan make:controller CountryController 編輯 /app/Http/Controllers , public function post($id)
{
$country = Country::with('post')->findOrFail($id);
return response()->json($country->post);
}
如下圖:
(6)輸入 http://127.0.0.1:8000/countries/1/post,就可以看到
5.Laravel 12 Has Many Through 關聯|透過 Eloquent 取得間接的相關資料
情境說明:
一個 Country(國家)有很多 User(使用者)而 User 有很多 Post(文章)
=> Country 可以透過 User 取得所有 Post
(1)利用Chatgpt 來建立範例
a.請給我一個 Laravel 12 範例,關於Has Many Through 關聯|透過 Eloquent 取得間接的相關資料
b.那如何在上述範例中,建立10筆資料。請詳加說明。
(2)建立hasManyThrough專案語法:composer create-project laravel/laravel hasManyThrough
(3)建立資料表結構(migrations)
a.此時已內建create_users_table,編輯其內容:
$table->foreignId('country_id')->constrained()->cascadeOnDelete();
如下圖:

b.建立create_countries_table,指令:php artisan make:migration create_countries_table,編輯其內容:
如下圖:

c.建立create_posts_table,指令:php artisan make:migration create_posts_table,編輯其內容:
$table->foreignId('user_id')->constrained()->onDelete('cascade');
如下圖:

(4)Model 設定(hasManyThrough)
a.建立 Country Model,指令:php artisan make:model Country,編輯內容如下:
protected $fillable = ['name'];
public function posts() {
return $this->hasManyThrough(
Post::class, // 最終要取得的 Model
User::class, // 中介 Model
'country_id', // users.country_id
'user_id', // posts.user_id
'id', // countries.id
'id' // users.id
);
}
public function users() {
return $this->hasMany(User::class);
}
如下圖:
b.已有 User Model,不需要建立,編輯內容如下:
protected $fillable = [
'name',
'country_id',
'email',
'password',
];
與
public function country() {
return $this->belongsTo(Country::class);
}
public function posts() {
return $this->hasMany(Post::class);
}
如下圖:
c.建立 Post Model,指令:php artisan make:model Post,編輯內容如下:
public function user() {
return $this->belongsTo(User::class);
}
如下圖: 注意:使用php artisan migrate:reset 回到初始狀態,再 php artisan migrate ,就會一直出錯,原因是順序。所以編輯migrations 的名稱,如下圖:(5).建立「10 筆完整資料」,而且會確保關聯正確(Country → User → Post)。我們會使用 Factory + Seeder(正式專案推薦)。
目標資料結構(最終成果):
1 個 Country,5 個 Users,每個 User 2 篇 Post。總共 10 篇 Posts。
這樣就可以完美測試 hasManyThrough
a.建立 Factory(產生假資料) (a).CountryFactory指令:php artisan make:factory CountryFactory
protected $model = Country::class;
public function definition(): array
{
return [
//
'name' => $this->faker->country(),
];
}
如下圖:
(b).UserFactory
指令:php artisan make:factory UserFactory
protected $model = User::class;
與
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => static::$password ??= Hash::make('password'),
'remember_token' => Str::random(10),
];
}
注意:不在 Factory 裡指定 country_id,因為我們要用「關聯方式」建立(比較乾淨)。
如下圖:
(c).PostFactory
指令:php artisan make:factory PostFactory
protected $model = Post::class;
public function definition(): array
{
return [
//
'title' => $this->faker->sentence(6),
];
}
}
如下圖:
b.撰寫 Seeder(重點)建立 DatabaseSeeder
public function run(): void
{
Country::factory()->has(
User::factory()->count(5)->has(
Post::factory()->count(2),
'posts'
),
'users'
)->create();
}
注意事項:
Country::factory()->has(User::factory()->count(5), 'users')
建立 Country,自動建立 5 個 User並自動填入 country_id
User::factory()->has(Post::factory()->count(2), 'posts')
每個 User,自動建立 2 個 Post並自動填入 user_id
如下圖:
(6).建立資料表,並建立假資料
指令: php artisan migrate
php artisan db:seed
此時,會出現錯誤
BadMethodCallException
Call to undefined method App\Models\Country::factory()
代表:Country Model 沒有啟用 Laravel 的 Factory 功能
檢查Country.php、User.php、Post.php 均要加入
如下圖: 重跑 Seeder 指令:
php artisan optimize:clear
php artisan db:seed
依舊出現錯誤BadMethodCallException
Call to undefined method App\Models\Country::users()
代表:
你在 Seeder / Factory 裡用了 users 關聯
但 Country Model 裡沒有定義 users() 方法
檢查如下圖:
再次出現錯誤
BadMethodCallException
Call to undefined method App\Models\User::post()
意思是:
Laravel 正在嘗試呼叫 User::post()
但你的 User Model 裡 只有 posts()(複數)
=>沒有 post()(單數)
檢查如下圖:
a.編輯 web.php
Route::get('/countries/{country}/posts', [CountryPostController::class, 'index']);
如下圖:
b.建立CountryPostController,並編輯
php artisan make:controller CountryPostController編輯如下
// 使用指定國家的所有貼文
public function index(Country $country) {
// 使用 hasManyThrough
$posts = $country->posts()->latest()->get();
return response()->json([
'country' => $country->name,
'total' => $posts->count(),
'data' => $posts,
]);
}
如下圖:
6.Laravel 12 多型關聯解說|一個模型對應多個資料表
評論(Comment)可以屬於「文章(Post)」或「影片(Video)」
這正是「一個模型對應多個資料表」的經典用法
情境說明(為什麼要用多型關聯)
假設你有:
文章(posts)
影片(videos)
評論(comments)
=>不用多型的話,你可能會變成這樣:
comments
├─ post_id
├─ video_id
=>不但欄位會一直加,結構也很難維護。
使用多型關聯後(正解)
comments
├─ commentable_id
├─ commentable_type
=>一個 Comment可以屬於 Post 或 Video 或未來更多模型
(1)利用Chatgpt 來建立範例
a.請給我一個 Laravel 12 範例,關於多型關聯解說|一個模型對應多個資料表
b.那如何在上述範例中,建立10筆資料。請詳加說明。
(2)建立Polymorphic專案語法:composer create-project laravel/laravel Polymorphic
(3)建立資料表結構(migrations)
a.建立posts table 指令:php artisan make:migration create_posts_table
$table->string('title');
如下圖:

b.建立videos table 指令:php artisan make:migration create_videos_table
$table->string('title');
如下圖:

c.建立comments table(關鍵)指令:php artisan make:migration create_comments_table
$table->text('content');
// 多型關聯關鍵欄位
$table->unsignedBigInteger('commentable_id');
$table->string('commentable_type');
如下圖:
此時,在資料庫的呈現如下圖:
(4)Model 設定(Polymorphic) a.建立 Comment Model 指令:php artisan make:model CommentComment Model(多型 belongsTo)
protected $fillable = ['content'];
public function commentable() {
return $this->morphTo();
}
如下圖:
morphTo()
Laravel 會自動使用:
commentable_id
commentable_type
b.建立 Post Model 指令:php artisan make:model Post
public function comments() {
return $this->morphMany(Comment::class,'commentable');
}
如下圖:
c.建立 Video Model 指令:php artisan make:model Video
public function comments() {
return $this->morphMany(Comment::class,'commentable');
}
如下圖:
資料來源:
1.Laravel 12 Eloquent Relationships Introduction | One to One, One to Many, Many to Many
2.Laravel 12 One to One Relationship Tutorial | Eloquent Relationship Explained
3.Laravel 12 One to Many Relationship Tutorial | Master Eloquent Relationships
4.Laravel 12 Many to Many Relationship Tutorial | Eloquent Pivot Table Explained