2024-10-19|閱讀時間 ‧ 約 0 分鐘

D10 - 深入 Laravel 的 Model,與資料庫暢快互動

哈囉,大家好!在上一篇文章中,我們成功地使用 Laravel 的 Migration 建立了資料庫結構。現在,是時候來探索 Laravel 中的另一個重要組件:Model(模型)。

透過 Model,我們可以輕鬆地與資料庫互動,實現資料的讀取、寫入和關聯操作。

一、什麼是 Laravel 的 Model?

在 Laravel 中,Model 是應用程式與資料庫之間的橋樑。它使用了 Eloquent ORM(Object-Relational Mapping),讓我們可以用物件的方式來操作資料庫,而不需要撰寫繁瑣的 SQL 語句。

為什麼要使用 Model?

  • 簡化資料庫操作:透過 Model,我們可以輕鬆地進行 CRUD(Create、Read、Update、Delete)操作。
  • 物件導向:將資料庫中的資料映射為 PHP 物件,符合現代開發的最佳實踐。
  • 關聯關係:方便地定義和使用資料表之間的關聯,如一對多、多對多關係。
  • 提高可讀性:程式碼更加直觀,易於理解和維護。

個人經驗分享:還記得剛開始接觸 Laravel 時,對 Eloquent ORM 感到驚艷。以前需要寫大量的 SQL 語句,現在只需幾行程式碼就能完成。同時,程式碼的可讀性也大大提升,讓開發變得更輕鬆有趣。

二、建立 Model

1. 使用 Artisan 指令建立 Model

Laravel 提供了 Artisan 命令列工具,讓我們可以快速地生成 Model。

在終端機中執行以下指令:

php artisan make:model User

這將在 app/Models 目錄下建立一個 User.php 的檔案。

小提醒:Laravel 8 之後,Model 預設存放在 app/Models 目錄下。如果你使用的是較舊的版本,Model 可能位於 app 目錄下。

2. 為其他資料表建立 Model

按照同樣的方式,為我們的資料表建立相應的 Model。

  • 建立 BankAccount Model:
php artisan make:model BankAccount
  • 建立 Category Model:
php artisan make:model Category
  • 建立 Transaction Model:
php artisan make:model Transaction

現在,我們已經為每個資料表建立了對應的 Model。接下來,讓我們來設定這些 Model,使其與資料表正確對應。

三、設定 Model 與資料表的關係

1. 基本設定

Laravel 的 Eloquent 會自動推斷資料表名稱,例如,User Model 對應到 users 資料表。但有時候,我們的資料表名稱可能與預設規則不符,這時需要在 Model 中明確指定。

舉例來說,如果我們的資料表名稱是 bank_accounts,Eloquent 會自動將 BankAccount Model 對應到 bank_accounts 資料表。但為了保險起見,我們可以在 Model 中指定:

class BankAccount extends Model
{
protected $table = 'bank_accounts';
}

2. 指定主鍵

如果資料表的主鍵名稱不是 id,需要在 Model 中指定主鍵欄位。例如:

class User extends Model
{
protected $primaryKey = 'user_id';
}

3. 關閉時間戳記

如果資料表中沒有 created_at 和 updated_at 欄位,可以在 Model 中關閉時間戳記:

class Category extends Model
{
public $timestamps = false;
}

四、定義 Model 之間的關聯

資料表之間的關聯可以透過 Model 來定義,這是 Eloquent 強大的地方。接下來,我們將為各個 Model 定義關聯關係。

1. User Model

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
// 一個使用者有多個銀行帳戶
public function bankAccounts()
{
return $this->hasMany(BankAccount::class);
}

// 一個使用者有多個分類
public function categories()
{
return $this->hasMany(Category::class);
}

// 一個使用者有多筆交易
public function transactions()
{
return $this->hasMany(Transaction::class);
}
}

2. BankAccount Model

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class BankAccount extends Model
{
// 屬於一個使用者
public function user()
{
return $this->belongsTo(User::class);
}

// 一個銀行帳戶有多筆交易
public function transactions()
{
return $this->hasMany(Transaction::class);
}
}

3. Category Model

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
// 屬於一個使用者
public function user()
{
return $this->belongsTo(User::class);
}

// 一個分類有多筆交易
public function transactions()
{
return $this->hasMany(Transaction::class);
}
}

4. Transaction Model

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Transaction extends Model
{
// 屬於一個使用者
public function user()
{
return $this->belongsTo(User::class);
}

// 屬於一個銀行帳戶
public function bankAccount()
{
return $this->belongsTo(BankAccount::class);
}

// 屬於一個分類
public function category()
{
return $this->belongsTo(Category::class);
}
}

五、使用 Model 進行資料庫操作

現在,我們已經設定好了 Model 和關聯關係。接下來,讓我們來看看如何使用 Model 進行資料庫操作。

1. 新增資料(Create)

範例:新增一個使用者

$user = new User();
$user->username = 'john_doe';
$user->email = 'john@example.com';
$user->password = bcrypt('secret');
$user->save();

範例:為使用者新增一個銀行帳戶

$bankAccount = new BankAccount();
$bankAccount->account_name = '薪資帳戶';
$bankAccount->account_number = '123456789';
$bankAccount->bank_name = '台灣銀行';

// 關聯到使用者
$user->bankAccounts()->save($bankAccount);

2. 查詢資料(Read)

範例:取得使用者的所有銀行帳戶

$user = User::find(1);
$bankAccounts = $user->bankAccounts;

範例:取得一筆交易的詳細資訊,包括使用者、銀行帳戶和分類

$transaction = Transaction::with(['user', 'bankAccount', 'category'])->find(1);

3. 更新資料(Update)

範例:更新銀行帳戶的餘額

$bankAccount = BankAccount::find(1);
$bankAccount->balance += 5000;
$bankAccount->save();

4. 刪除資料(Delete)

範例:刪除一個分類

$category = Category::find(1);
$category->delete();

5. 使用關聯進行操作

範例:透過使用者新增交易

$transaction = new Transaction([
'type' => 'expense',
'amount' => 2000,
'transaction_date' => now(),
'description' => '購買書籍',
]);

$user->transactions()->save($transaction);

六、還有沒有?

1. 使用 Eloquent 查詢構建器

Eloquent 提供了強大的查詢構建器,可以方便地進行各種複雜查詢。

範例:取得特定期間的收入總額

$totalIncome = Transaction::where('user_id', $user->id)
->where('type', 'income')
->whereBetween('transaction_date', [$startDate, $endDate])
->sum('amount');

2. 建立 Scope 簡化查詢

可以在 Model 中定義 Scope,讓常用的查詢條件更簡潔。

範例:在 Transaction Model 中定義 Scope

public function scopeIncome($query)
{
return $query->where('type', 'income');
}

public function scopeExpense($query)
{
return $query->where('type', 'expense');
}

使用 Scope 進行查詢

$totalIncome = Transaction::income()->sum('amount');
$totalExpense = Transaction::expense()->sum('amount');



3. 善用 Mutators 和 Accessors

可以在 Model 中定義 Mutators 和 Accessors,對欄位的值進行修改或格式化。

範例:在 User Model 中定義密碼的 Mutator

在模型中定義了一個名為 setPasswordAttribute 的方法時,這個方法會被自動觸發,因為 Laravel 提供了一個特性,允許開發者為模型屬性定義 "setter" 方法。這個 "setter" 方法會在你試圖為模型的屬性賦值時自動調用。

public function setPasswordAttribute($value)
{
$this->attributes['password'] = bcrypt($value);
}

這樣,當我們設定使用者密碼時,會自動進行加密:

$user->password = 'new_password'; // 會自動加密

具體原因:

  1. Laravel 的 Mutator 特性:
    在 Laravel 中,當模型的屬性被設定時,會檢查是否有對應的 Mutator(即 set{AttributeName}Attribute 方法)。在這個例子中,屬性名稱是 password,因此 Laravel 會檢查模型中是否有一個名為 setPasswordAttribute 的方法。這個方法的命名遵循以下規則:
    • set:前綴,表示這是 “setter” 方法。
    • Password:這是屬性的名稱,也就是模型中的 password 屬性。
    • Attribute:固定的後綴,Laravel 用於識別這個方法是屬性 Mutator。
  2. 自動加密密碼:
    當你給 $user→password 設置一個值時,Laravel 會自動調用 setPasswordAttribute 方法。在這個方法中,你可以定義如何處理這個值。你使用 bcrypt() 函數將明文密碼加密,然後再將加密後的值存儲到模型的 attributes 數組中,這個數組是用來保存模型的實際屬性值的。

小結

透過本篇文章,我們深入了解了 Laravel 的 Model 以及如何使用 Eloquent ORM 與資料庫進行互動。我們明白了:

  • 建立 Model 並設定與資料表的關係。
  • 定義 Model 之間的關聯,方便進行關聯操作。
  • 使用 Model 進行資料的新增、查詢、更新和刪除。
  • 善用 Eloquent 的特性,優化程式碼。
  • 當你有一定要讓某個欄位進行相關處理時Mutators 和 Accessors是最好的控制點
    希望這些內容能夠幫助你在開發中更加得心應手,寫出乾淨、可維護的程式碼。

But… 光是Model 就有很多可以講,但我們不要讓篇幅太多冗長,所以內容未來有機會,會在某個環節提出分享

Next

我們將開始開發後端 API,這部分開始會連通幾個關鍵行為,這樣會比較有脈絡。讓我們繼續這段充滿挑戰與樂趣的開發之旅吧!

分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.