🙆‍♀️

Laravel8で主キーをランダム文字列にする方法

2021/11/17に公開

ライブラリを使用して主キーにuuidを入れる方法もあるのですが、僕は英数字大文字だけのランダム文字列みたいな感じにしたかったので、自分で実装してみました。

ユーザーの主キーをランダム文字列にしてみます。

マイグレーション

ユーザーにマイグレーションです

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->string('id')->primary();  // 主キーをユニークな文字列にする
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
            $table->softDeletes();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

2. ランダム文字列を作るヘルパー関数を作ります

こちらの をもとに独自のヘルパー関数を作ります。

ヘルパー関数ではこのように記述しました。

/**
 * ランダム文字列を生成する
 *
 * @return string ランダム文字列
 */

if (! function_exists('randomSring')) {
    function randomSring($length)
    {
        return substr(str_shuffle('ABCDEFGHJKLMNPQRSTUVWXYZ0123456789-_'), 0, $length - 1);
    }
}

str_shuffleで文字をシャッフルしてくれるので、文字数を入れたらその文字数でランダム文字列を取得してくれます。

3. データ作成時にランダム文字列をidに入れる

データの作成時に、ランダム文字列をidに入れれば、ランダム文字列の主キーが完成です。

モデル内にこのように記述します。

class User extends Authenticatable
{
    use HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $guarded = [];

    // プライマリーキーの型
    protected $keyType = 'string';

    // プライマリーキーは自動連番かどうか
    public $incrementing = false;

    // グローバルスコープ
    protected static function boot()
    {
        parent::boot();

        static::creating(function ($model) {
            for ($i = 0; $i < 5; $i++) {
                $randomStr = randomSring(10); / ランダム文字列生成
                $exists = User::where('id', $randomStr)->exists(); // 被ってはいけないのでDBに存在チェック

                if (!$exists) {
                    $model->id = $randomStr;
                    break;
                }
                if ($i === 4) {
                    Log::alert('正しくユーザーIDが作成できませんでした');
                    throw new \Exception('正しくユーザーが作成できませんでした。');
                }
            }
        });
    }
    .
    .
    .
}

ランダム文字列を生成しても被ることがあるかもしれないので、その場合はfor文でループを回します。
ただ、無限ループに陥らないように5回で諦めるように設定しています。

こちらでランダム文字列の主キーの完成です!

Discussion