Laravel и UUID

Laravel UUID

Что такое UUID?

UUID это универсальный уникальный идентификатор. 16-байтный (128-битный) номер, используемый для уникальной идентификации какого-либо объекта без общего центра координации. То есть мы самостоятельно генерируем UUID и уверены, что полученный идентификатор уникален. Общее количество уникальных ключей UUID составляет 2128 = 25616 или около 3,4 x 1038. Генерируя 1 триллион ключей каждую наносекунду, перебрать все возможные значения удастся лишь за 10 миллиардов лет. В шестнадцатеричной системе счисления UUID выглядит как:
9675e665-1923-4c6f-97c0-259b191fab24

Я не буду вдаваться в подробности плюсов и минусов UUID по сравнению с обычным автоматическим инкрементным идентификатором, про это есть отдельные статьи. Но я расскажу вам как можно использовать UUID в вашей Laravel.

Подготавливаем миграцию

Первым шагом использования UUID в вашей базе данных это настройка столбца идентификатора. По умолчанию в каждой миграция Laravel автоматически создается столбец $table->primary(‘id’);.

Использовать UUIDs так же просто, как обновить миграцию. Добавляем метод ->uuid(), доступный прямо из «коробки». Например миграция для сущности Post:

Schema::create('posts', function (Blueprint $table) {
    $table->uuid('id')->primary();
    $table->string('title');
    $table->text('body');
    $table->timestamps();
});

Обратите внимание на строку: $table->uuid(‘id’)->primary();. Мы используем метод uuid() вместо обычного increments().

Создание UUID

Если вы запустите php artisan migrate и попытаетесь создать новую запись, через фабрику или вручную, то получите ошибку, утверждающую, что столбец id не может быть null.

При использовании метода primary() в миграциях Laravel понимает, что это автоинкрементный столбец, и создает его таким. Но, поскольку мы перешли на использование UUID, нам нужно создавать ID самостоятельно.

Используем события модели Eloquent

Раз мы работает с Laravel, то скорей всего используем и Eloquent для взаимодействия с базой данных.

Eloquent имеет так называемую Событийная модель (Model Events). В общей сложности он запускает 11 событий в разных сценариях:

  • retrieved
  • creating
  • created
  • updating
  • updated
  • saving
  • saved
  • deleting
  • deleted
  • restoring
  • restored

Если вы хотите узнать о Событиях больше, то ознакомьтесь с документацией.

Вернемся к созданию UUID. Давайте посмотрим, как может выглядеть ваша модель Post:

class Post extends Model
{
    protected $guarded = [];

    protected static function boot()
    {
        parent::boot();

        static::creating(function ($post) {
            $post->{$post->getKeyName()} = (string) Str::uuid();
        });
    }

    public function getIncrementing()
    {
        return false;
    }

    public function getKeyType()
    {
        return 'string';
    }
}

Модель имеет 3 метода. В методе boot мы можем подключиться к нашей модели и прослушивать любые события Eloquent. Метод getIncrementing используется Eloquent, если идентификаторы в таблице инкрементны. Помните, мы используем UUID, поэтому устанавливаем false на автоинкремент. А метод getKeyType просто указывает, что идентификаторы в таблице должны храниться в виде строк.

В нашем методе boot мы ожидаем события creating. Оно запускается непосредственно перед тем, как запись сохраняется в базе данных. Мы подключаемся к этому событию и используем метод uuid(), предоставленный классом Str в Laravel.

Раньше, для генерации UUID необходимо было устанавливать дополнительный пакет через Composer, а сейчас это есть прямо в Laravel.

Обычно я делаю отдельный трейт (trait) под названием UsesUuid, где я храню логику, описанную выше. Это позволяет не повторять код для каждой модели, где нужно использовать UUID:

<?php

namespace App\Models\Concerns;

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';
    }
}

 

Обратите внимание, что всё обобщенно и не привязано к отдельной модели.

Теперь в любой модели, вы можете просто использовать трейт UsesUuid следующим образом:

class Post extends Model
{
  use App\Models\Concerns\UsesUuid;

  protected $guarded = [];
}

Вот и все. Всего за несколько простых шагов вы получили UUID для Laravel.

 

Автор: Wilbur Powery
Перевод: Demiurge Ash