Eloquent ORM 是 Laravel 框架的官方物件關聯映射(ORM)系統,它提供了一個簡單的 Active Record 實現,可以用面向對象的方式操作數據庫。
使用 Eloquent 可以透過模型對象來處理數據庫操作,並且可以輕鬆地定義和管理數據表之間的關係。
主要特性:
💡 ORM 是一種技術,它把資料庫中的資料表格和記錄映射成程式中的對象,讓你可以像操作物件一樣操作資料庫中的資料,而不需要直接寫 SQL 查詢。
創建模型和遷移文件
💡 模型(Model) 是 Laravel Eloquent ORM 的核心組件之一,每個模型對應到資料庫中的一個表格,他也提供了進行 CRUD 操作的能力。
使用 Artisan 命令 php artisan make:model ModelName
來創建模型,通常會在 app/Models
目錄下創建一個模型類,然而每個模型通常對應一個數據表。
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
/**
* 使用 create 或 update 方法時,只有 name、email 和 password 欄位可以被批量賦值
* @var array
*/
protected $fillable = ['name', 'email', 'password',];
/**
* 不能被批量賦值
* @var array
*/
protected $guarded = ['id'];
/**
* The attributes that should be hidden for serialization.
*/
protected $hidden = ['password', 'remember_token',];
/**
* 定義模型屬性應如何轉換
* is_active 屬性轉換為布林值
* email_verified_at 屬性轉換為日期時間對象
* @var array
*/
protected $casts = ['is_active' => 'boolean', 'email_verified_at' => 'datetime',];
/**
* 自動轉換為 Carbon 實例的日期屬性
* @var array
*/
protected $dates = ['created_at', 'updated_at'];
}
💡 遷移文件(Migration) 用於定義資料表的結構,包括創建資料表、添加欄位、設置索引等操作。
使用 Artisan 命令 php artisan make:migration create_table_name
遷移文件用於定義數據表的結構,這些文件通常放在 database/migrations
目錄中,這會生成一個新的遷移文件,可以在裡面定義表的結構和欄位。
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations. -> 定義如何創建或修改資料表
*
* @return void
*/
public function up()
{
/**
* 用 Schema 的 create 方法建立一個新的資料表
* 第一個參數是表名
* 第二個參數是一個閉包,Blueprint 實例的 table 屬性代表的是資料表的名稱
*
*/
Schema::create('flights', function (Blueprint $table) {
$table->id(); // 自動增量的主鍵欄位
$table->string('name'); // 名稱欄位
$table->string('airline'); // 航線欄位
$table->timestamps(); // 自動生成 created_at 和 updated_at 欄位
});
}
/**
* Reverse the migrations. -> 取消 up 方法所做的變更
*
* @return void
*/
public function down()
{
Schema::dropIfExists('flight');
}
};
🔔 在
Blueprint
實例中,$table
屬性存儲了資料表的名稱。
修改更新模型和遷移文件
通常更新資料,是要看上下文使用 laravel 方法,模型和遷移文件比較不需要變更。
namespace App\Http\Controllers;
use App\Models\RegisterUsers;
RegisterUsers
模型查詢 id = 2 的資料,然後更新他的 email 變成 'aa@aa.com'update()
更新儲存 -> 需要一個表示應該更新的列的列和值對數組。
$user = RegisterUsers::query()->where('id', 2)->update(['email' => 'aa@aa.com']);
save()
更新 -> 更新資料庫中已經存在的模型
$user = RegisterUsers::query()->find(2);
$user->email = '123@aa.com';
$user->save();
updateOrCreate
新增或更新 -> 如果不存在匹配的模型,您可能需要更新現有模型或建立新模型
$user = RegisterUsers::query()->updateOrCreate(
['email' => 'aa@qwe.com', 'id' => 1],
['email' => 'no@qwe.com', 'password' => 'aa123']
);
sole()
檢索單一唯一的模型 -> 如果只要找出一條表中唯一的記錄
RegisterUsers::query()->where(['email'=>'123@123.com'])->sole()
刪除模型和遷移文件
delete
方法,然後可以呼叫 truncate
方法來刪除所有模型關聯的資料庫記錄。
use App\Models\RegisterUsers;
$user = RegisterUsers::find(1);
$user->delete();
RegisterUsers::truncate();
相同表單名稱
下(類似分支管理概念),下指令 php artisan make:migration add_soft_delete_on_register_users_table
建立新的遷移文件,然後建立欄位
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('register_users', function (Blueprint $table) {
// 軟刪除所需的 deleted_at 時間戳
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('register_users', function (Blueprint $table) {
$table->dropSoftDeletes($column = 'deleted_at', $precision = 0);
});
}
};
php artisan migrate
自動生成表格delete()
方法進行軟刪除,執行後可以看到表格的 'deleted_at' 欄位有多一個時間戳
$user = RegisterUsers::query()->where('email', 'no@qwe.com')->delete();
使用 Artisan 命令 php artisan migrate
運行遷移命令會根據遷移文件中的定義來創建或更新數據表結構,指令下後會執行所有尚未執行的遷移文件,並且將數據表創建或更新到數據庫中。
遷移指令
php artisan migrate:status
php artisan migrate:rollback
php artisan migrate:rollback --step=5
php artisan migrate
migrate
-> php artisan migrate:refresh
migrate
-> php artisan migrate:fresh
專案已經建好以下表格,目前在 'register_users' 需要新增欄位 'name',要怎麼操作呢?
方法一:延伸合併
step 1:下指令 php artisan make:migration add_column_on_register_users_table
新增一個遷移文件,並且新增需求
重點 1 -> 表格名稱,因為要在同一張表格新增欄位,所以表格名稱要一致
重點 2 -> 因為是同一張表格不用重新創建,只需要用Schema::table('表格名稱', 閉包放要新增的條件)
step 2:下指令 php artisan migrate
讓延伸表格合併
方法二:更新資料
step 1:下指令 php artisan migrate:rollback
回到過去,再新增欄位
step 2:下指令 php artisan migrate:fresh
通知他這個表格要重新確認更新
hasOne
:一對一關聯
模型 A 擁有一個模型 B。模型 B 只有一個模型 A 的實例。
例如,User 擁有一個 Profile。
// User.php
public function profile()
{
return $this->hasOne(Profile::class);
}
hasMany
:一對多關聯
模型 A 擁有多個模型 B。模型 B 可能對應到模型 A 的多個實例。
例如,Post 可以有多個 Comment。
// Post.php
public function comments()
{
return $this->hasMany(Comment::class);
}
belongsTo
:多對一關聯
模型 B 屬於模型 A。模型 A 可能擁有多個模型 B 的實例。
例如,Comment 屬於一個 Post。
// Comment.php
public function post()
{
return $this->belongsTo(Post::class);
}
belongsToMany
:多對多關聯
模型 A 和模型 B 之間有多對多的關聯。這種關聯通常需要一個中間表來存儲兩者之間的關係。
例如,Student 和 Course 之間的關係,學生可以選擇多門課程,每門課程也可以有多名學生。
// Student.php
public function courses()
{
return $this->belongsToMany(Course::class);
}
// Course.php
public function students()
{
return $this->belongsToMany(Student::class);
}
按照 laravel 9.x 的模型关联創建一個部落格系統作為練習。
任務步驟:
step - 1:規劃有哪些模型要建立,並且思考彼此間的關聯
這裡只規劃發文 post 和評論 comment,而且一篇文章可以對好多則評論。
step - 2:建立模型和遷移檔案
用指令 php artisan make:model Post -m
和 php artisan make:model Comment -m
產生 Post
和 Comment
模型及遷移檔案。
step - 3:定義資料表結構 & 定義模型關係
在 create_posts_table
遷移檔案中新增欄位:title, content。
在 create_comments_table
遷移檔案中新增欄位:post_id, content,並設定 post_id 為外鍵。
step - 4:運行遷移
指令:php artisan migrate
。
step - 5:測試 model 關聯
方法 1:控制器
$post = Post::query()->find(1); // 替換 1 為實際的 Post ID
$comments = $post->comments;
dd($comments->toArray());
方法 2:Laravel Tinker
php artisan tinker
啟動 Tinker// 取得一個 Post 實例,這是測試 hasMany 關係
$post = App\Models\Post::find(1); // 替換 1 為你實際的 Post ID
// 取得該 Post 相關聯的 Comments
$comments = $post->comments;
// 取得一個 Comment 實例,這是測試 belongsTo 關係
$comment = App\Models\Comment::find(1); // 替換 1 為實際的 Comment ID
// 取得與該 Comment 關聯的 Post
$post = $comment->post;
假設我們有一個學生和課程的系統。
每位學生可以選修多個課程,每個課程也可以有多位學生,這就是一個多對多的關係。
step - 1:規劃有哪些模型要建立,並且思考彼此間的關聯
學生和課程的系統,代表需要學生名單和一個課程表,所以需要創建兩個模型:Student 和 Course。
它們之間透過一個中間表 course_student
進行關聯。
step - 2:建立模型和遷移檔案
php artisan make:model Student -m
php artisan make:model Course -m
php artisan make:migration create_course_student_table --create=course_student
step - 3:定義資料表結構 & 定義模型關係
在 create_students_table.php
遷移文件中新增欄位:name。
在 create_courses_table.php
遷移文件中新增欄位:title。
在中間表 create_course_student_table.php
的遷移文件中新增欄位:外鍵約束。
這裡不能再定義 id,定義後做遷移會提醒
「course_student」有多個主鍵
step - 4:運行遷移
指令:php artisan migrate
。
step - 5:測試 model 關聯
方法 1:控制器
// 創建學生和課程
$student = Student::create(['name' => 'John Doe']);
$course = Course::create(['title' => 'Math 101']);
// 關聯課程和學生
$student->courses()->attach($course->id);
// 檢查學生的課程
$studentCourses = $student->courses;
$studentCoursesTitles = $studentCourses->pluck('title')->toArray();
// 檢查課程的學生
$courseStudents = $course->students;
$courseStudentsNames = $courseStudents->pluck('name')->toArray();
return response()->json([
'student_courses' => $studentCoursesTitles,
'course_students' => $courseStudentsNames
]);
方法 2:Laravel Tinker
php artisan tinker
啟動 Tinker// 創建學生和課程
$student = App\Models\Student::create(['name' => 'John Doe']);
$course = App\Models\Course::create(['title' => 'Math 101']);
// 關聯課程和學生
$student->courses()->attach($course->id);
// 檢查學生的課程
$studentCourses = $student->courses;
foreach ($studentCourses as $course) {
echo $course->title . "\n";
}
// 檢查課程的學生
$courseStudents = $course->students;
foreach ($courseStudents as $student) {
echo $student->name . "\n";
}
延續第 5 天:數據模型與遷移知道模型之間有所謂的關聯,在建立中「後來」才需要加上關聯,可以用
php artisan migrate
-> 萬一失敗不要殺他!直接上 php artisan migrate:rollback --step=1
🔔 非必要,千萬不要輕易嘗試 php artisan migrate:refresh
🔔 使用了外鍵,要留意在遷移文件中設定的條件...