在 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() ;并使其成为主键。

让我们把它封装成 Trait

接下来,我们可以实现 Laravel 生命周期挂钩,以确保在创建此模型的新实例时分配了 UUID。我们可以直接在模型中编写代码,但是如果你要在多个模型中使用 UUID,我建议用 Trait (我在这篇开发文章中学到了这一点,非常感谢 Dev)。trait 基本上允许你创建功能,并通过 use 关键字调用它在多个模型中使用。

要创建新的 Trait,请创建一个 \App\Http\Traits 文件夹(这仅仅是我的爱好,你也可以将其放到其他位置),并为 Trait 创建一个新文件。我们将调用文件 UsesUuid.php

FilePath

这是 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');
            ...
        }
    }

爱Laravel的另一个原因!编码愉快!

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://dev.to/cverster/uuids-in-laravel...

译文地址:https://learnku.com/laravel/t/44937

本帖已被设为精华帖!
本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 9

下一个项目用用看!

3年前 评论

改动太大 可以Aes加密解密来处理

3年前 评论

命名空间可以用这个 namespace App\Http\Model\Traits;,看到就知道模型用的,日后 trait 多了呢?

还有就是 DB::table(‘user’) 可以用 uuid 吗?create 可以吗?
这个时候需要手动指定 uuid 了吧?
个人意见,欢迎交流

3年前 评论

个人建议使用雪花id,第一还是bigint,数据库效率高,第二个并发可以用redis来解决,第三,相对系统改动不大,在model的creating里面加一个id生成的方法就行了。

3年前 评论
Marrigan (楼主) 3年前
自由与温暖是遥不可及的梦想

个人建议 多设置一个uuid 访问的时候 访问 uuid 关联的时候 走自增id

3年前 评论

我是继续用自增id 在出口进行自动加密id,核心不动,入口路由中间件自动解密

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!