23
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Laravel で主キー(プライマリキー)を ULID で登録する方法

Last updated at Posted at 2022-02-24

環境

Laravel Framework 8.54.0
PHP 8.0.9
docker-compose version 1.29.2
rorecek/laravel-ulid:^2.0

手順

rorecek/laravel-ulid

まずは、rorecek/laravel-ulidのインストールを行います。
ターミナルを開き、以下のコマンドを入力します。

ターミナル(sail)
$ ./vendor/bin/sail composer require rorecek/laravel-ulid:^2.0
ターミナル(composer)
$ composer require rorecek/laravel-ulid:^2.0

これで、インストールは完了しました。

マイグレーション

次に、マイグレーションから編集していきます。
今回はユーザに関しての変更を行おうと思うので、
デフォルトのdatabase/migrations/2014_10_12_000000_create_users_table.phpを編集します。

ULIDは、26 文字の文字列になります。
そのため、以下のように編集します。

database/migrations/2014_10_12_000000_create_users_table.php
// ...
class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
-           $table->bigIncrements('id');
+           $table->char('id', 26)->primary();
            // ...
        });
    }

    // ...
}

モデル

最後にモデルを編集します。

オートインクリメントを無効にして、
idを ULID で生成するように修正します。

traitを用意してくれているので、
以下のように、変更すれば大丈夫です。

app/User.php
// ...

use Rorecek\Ulid\HasUlid;

class User extends Authenticatable
{
    // ...

    use HasUlid;

    /**
     * IDが自動増分されるか
     *
     * @var bool
     */
    public $incrementing = false;
    
    /**
     * 自動増分IDの「タイプ」
     *
     * @var string
     */
    protected $keyType = 'string';

    // ...
}

これで、idが ULID で生成されます。

注意点

上記までの手順で大枠は解決なのですが、
主キー(プライマリキー)をid以外に設定しているときは上手く動作しません。

理由は、モデルの修正で使用したRorecek\Ulid\HasUlidが影響しています。
中身を見てみると原因がハッキリします。

vendor/rorecek/laravel-ulid/src/HasUlid.php
<?php
namespace Rorecek\Ulid;

trait HasUlid
{
    protected static function bootHasUlid()
    {
        static::creating(function ($model) {
            if (! $model->id) {
                $model->id = \Ulid::generate();
            }
        });

        static::saving(function ($model) {
            $originalUlid = $model->getOriginal('id');
            if ($originalUlid !== $model->id) {
                $model->id = $originalUlid;
            }
        });
    }

    public function getIncrementing()
    {
        return false;
    }

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

そうなんです。
idを直接指定してしまっているため、他のときは動かないようになってます。

解決方法

解決方法は、言葉にしてしまえば簡単ですが、
主キー(プライマリキー)が何のときでも動くようにしてあげればよいだけですね。

trait/HasUlid.php
<?php
use Rorecek\Ulid\Facades\Ulid;

trait HasUlid
{
    protected static function bootHasUlid()
    {
        static::creating(function (Model $model) {
            if (! $model->getKey()) {
                $model->setAttribute($model->getKeyName(), Ulid::generate());
            }
        });

        static::saving(function (Model $model) {
            $originalUlid = $model->getOriginal($model->getKeyName());
            if ($originalUlid !== $model->getKey()) {
                $model->setAttribute($model->getKeyName(), $originalUlid);
            }
        });
    }

    public function getIncrementing()
    {
        return false;
    }

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

    /**
     * IDが自動増分されるか
     *
     * @var bool
     */
    public $incrementing = false;
    
    /**
     * 自動増分IDの「タイプ」
     *
     * @var string
     */
    protected $keyType = 'string';
}

こんなtraitを作成してあげれば、汎用的に使えると思います。

さいごに

ということで、rorecek/laravel-ulid
\Rorecek\Ulid\Facades\Ulid::generate()とするだけで簡単にULIDを生成できるだけでなく、
主キー(プライマリキー)をULIDに変更する最低限の下地を既に作成してくれている訳です。

主キー(プライマリキー)を特別なものへと変更するにあたって、
createdsavingなどのhookに引っ掛けて特定の処理を行うことは常套手段でしたが、
毎回記述するのがとても煩わしかったのを覚えています。

なので、それも含めて準備してくれるのはとてもありがたい!!

あなたの実装ライフが少しでも楽になりますように~

23
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?