前言
在找尋與 UUID 相關的套件時,意外地發現了 Laravel Eloquent 內建的 boot trait 的機制,這是一個非常方便的功能,可以在 Model 在建立之前,自動執行某些操作,並且能夠有效的重複利用程式碼。
假設有一個 User 的 Eloquent Model,在建立新的 User 時,Model 需要建立對應的 UUID,可能會這麼做:
1 2 3 4 5 6 7 8 9 10 11
| class User extends Model { public static function boot() { parent::boot(); static::creating(function (Model $model) { $model->uuid = Str::uuid(); }); } }
|
Eloquent Boot Trait
接著,如果還有另一個 Order 的 Eloquent Model 也需要建立 UUID 時,可能就要再複製同樣的程式碼,最後造成相同的邏輯重複出現在各個 Model 當中,這很容易造成維護上的困難。
為了避免重複的程式碼出現,可以使用 Eloquent 內建的 boot 功能
可以先看一下 Model 相關方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
|
protected static function boot() { static::bootTraits(); }
protected static function bootTraits() { $class = static::class;
$booted = [];
static::$traitInitializers[$class] = [];
foreach (class_uses_recursive($class) as $trait) { $method = 'boot'.class_basename($trait);
if (method_exists($class, $method) && ! in_array($method, $booted)) { forward_static_call([$class, $method]);
$booted[] = $method; }
if (method_exists($class, $method = 'initialize'.class_basename($trait))) { static::$traitInitializers[$class][] = $method;
static::$traitInitializers[$class] = array_unique( static::$traitInitializers[$class] ); } } }
|
可以大概看出這裡有做一些操作
- 檢查有沒有
boot 開頭的 trait
- 如果存在則執行它
因此,可以透過這樣的機制為 Eloquent 做一些自動化的操作
所以調整一下開始的範例並使用 trait 的方式
1 2 3 4 5 6 7 8 9
| trait HasUuid { public static function bootHasUuid() { static::creating(function (Model $model) { $model->uuid = Str::uuid(); }); } }
|
並將這個 trait 套用到 Model 上
1 2 3 4
| Class User extends Model { use HasUuid; }
|
1 2 3 4
| Class User extends Model { use HasUuid; }
|
這樣就可以快速地讓 Model 擁有產生 UUID 的功能了
總結
在 Laravel 中,您可以透過使用 Eloquent 的 boot 機制和 trait 來有效地減少重複的程式碼,只需要在對應的 Trait 中以 bootTraitName 的方式命名即可,Eloquent 就會在建立時自動地使用的使用這個方法。這樣不僅可以提升程式碼的可讀性,還可以讓您更加輕鬆地管理多個類似的功能。
Reference