在 Laravel 7 中優雅使用 UUID 教程

最近我不得不在 Laravel 7 實現 通用唯一識別碼 ( UUIDs ),並遇到一些問題。我希望這帖子可爲其他正在做相同事情的人解惑。

使用 UUIDs 的高級理由

A) 它們從你的 統一資源定位符 移除編號的 身份識別號 ,故用戶不能看到你的應用已創建多少確定的對象。例如:

https://myapp.com/api/users/5 

對比:

https://myapp.com/api/users/0892b118-856e-4a15-af0c-66a3a4a28eed

B) 它們讓 身份識別號 遠難於猜測。這有益於安全性,但我們可能應當實現其他技術以防範之。

作爲主鍵實現 UUIDs

如何改變數據庫遷移

首先,在數據庫遷移中,你要將當前自動遞增的 ID 字段替換爲 UUIDs 。你還可以遵循以下方法:保留自動遞增 ID 並將 UUID 作爲表中的附加字段,在用戶展示 URL 時使用 (在這種情況下,你將 ID 隱藏到模型中),但這不是我們能在這裏做的。 讓我們看看假設的 employees 表是什麼樣子的。

public function up()
 {
 Schema::create('employees', function (Blueprint $table) {
 $table->uuid('id')->primary;
 $table->string('name');
 $table->string('email')->unique();
 $table->string('work_location')->nullable();
 $table->timestamps();
 });
 }

在這裏,注意我們用 uuid() 替換了 normal id() ;並使其成爲主鍵。

讓我們把它變成一種特質

接下來,我們可以實現 Laravel 生命週期掛鉤,以確保在創建此模型的新實例時分配了 UUID。我們可以直接在模型中編寫代碼,但是如果你要在多個模型中使用 UUID,我建議用 Trait (我在這篇開發文章中學到了這一點,非常感謝 Dev)。trait 基本上允許你創建功能,並通過 use 關鍵字調用它在多個模型中使用。

要創建新的 Trait,請創建一個 \App\Http\Traits\文件夾 (這僅僅是我的愛好,你也可以將其放到其他位置),併爲 Trait 創建一個新文件。我們將調用文件 UsesUuid.php。

這是 trait 的具體代碼:

<?php
namespace App\Http\Traits;
use Illuminate\Support\Str;
trait UsesUuid
{
 protected static function bootUsesUuid() {
 static::creating(function ($model) {
 if (! $model->getKey()) {
 $model->{$model->getKeyName()} = (string) Str::uuid();
 }
 });
 }
 public function getIncrementing()
 {
 return false;
 }
 public function getKeyType()
 {
 return 'string';
 }
}

使用 \Illuminate\Support\Str 輕鬆生成 UUID.。getIncrementing () 方法告訴 Laravel 該模型的主鍵不會自增 (因爲我們設置的是 false), 而 getKeyType () 方法告訴 Laravel 該模型的主鍵是字符串類型。bootUsesUuid () 方法允許我們使用 Laravel 強大的生命週期鉤子。你可以 在這來哦藕節更多詳細信息。基本上我們的代碼已經可以告訴 Laravel,當創建該模型的新實例時,爲其設置 UUID 主鍵!

現在,我們可以使用 use 關鍵字在模型上輕鬆實現此特徵。

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
...
class Employee extends Model
{
 ...
 use \App\Http\Traits\UsesUuid;
 ...
}

將 UUID 引用爲外鍵

要將表上的 UUID 引用爲外鍵,只需更改表上外鍵字段的類型。如下...

Schema::create('another_table', function(Blueprint $table) {
 $table->id();
 $table->unsignedBigInteger('employee_id');
 $table->string('some_field');
 $table->foreign('employee_id')
 ->references('id')
 ->on('shifts')
 ->onDelete('cascade');
 });

... 我們在引用 employee_id 外鍵時創建了一個無符號大整型的數據類型,對此進行如下修改:

Schema::create('another_table', function(Blueprint $table) {
 $table->id();
 $table->uuid('employee_id');
 $table->string('some_field');
 $table->foreign('employee_id')
 ->references('id')
 ->on('shifts')
 ->onDelete('cascade');
 }); 

那樣簡單!還有一件事...

UUID 和多態關係

您可能會發現自己通過自己的操作或要引入的包以多態關係引用了該模型。在遷移中,該表可能看起來像這樣:

public function up()
{
 Schema::create('some_package_table', function (Blueprint $table) 
 {
 $table->bigIncrements('id');
 $table->morphs('model');
 ...
 }
}

在這裏,morphs () 方法將在數據庫中創建兩個字段,即無符號大整型類型的 model_id 和字符串類型的 model_type。問題在於我們的模型現在使用的是 UUID 而不是遞增的整數 ID,因此這會給您帶來錯誤,並顯示類似以下內容::

Data truncated for column 'model_id' at row 1

我們現在需要 model_id 字段來支持我們的新 UUID,它的類型是 CHAR (36)。別擔心!Laravel 讓這件事變得超級簡單,你不需要手動做這件事。只需將遷移更改爲:

public function up()
{
 Schema::create('some_package_table', function (Blueprint $table) 
 {
 $table->bigIncrements('id');
 $table->uuidMorphs('model');
 ...
 }
} 

更多PHP內容請訪問:

騰訊T3-T4標準精品PHP架構師教程目錄大全,只要你看完保證薪資上升一個臺階(持續更新)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章