Migrate from michaeldyrynda/laravel-model-uuid to native Laravel uuids

For many years I have used michaeldyrynda/laravel-model-uuid without any issues. Its a great package that served me well. But since version 9 Laravel has native support for uuids. So today let do the long overdue migration.

Changes to your eloquent models

  1. Change the trait from
use Dyrynda\Database\Support\GeneratesUuid;

to

use Illuminate\Database\Eloquent\Concerns\HasUuids;
  1. Change the cast from
Dyrynda\Database\Support\Casts\EfficientUuid

to

Illuminate\Database\Eloquent\Casts\AsBinary

If you are still using the property, also migrate to using a function like so:

/**
 * Get the attributes that should be cast.
 *
 * @return array<string, string>
 */
protected function casts(): array
{
    return [
        'uuid' => AsBinary::uuid(),
    ];
}
  1. Add a function to configure the uuid field as a unique identifier
/**
 * Get the columns that should receive a unique identifier.
 *
 * @return array<int, string>
 */
public function uniqueIds(): array
{
    return ['uuid'];
}

$table->efficientUuid in migrations

In order to keep using the efficientUuid helper in your migrations you can add the following to the boot function of your AppServiceProvider

Blueprint::macro('efficientUuid', function (string $columnName) {
    return $this->binary($columnName, length: 16, fixed: true);
});

whereUuid scope

If you still want to make use of the whereUuid helper that Michael Dyrynda's package provided you'll have to implement it yourself. You can do this by extending the HasUuids trait and adding a helper function. In the example below there are 2 options:

  • Convert the string uuid to binary in PHP. This will make your code a little more flexible against different databases.
  • Convert the string uuid to binary in MySQL. This will offload the calculation to your MySQL. If you have no specific reason to convert in PHP, use this one.
<?php

namespace App\Traits;

use Ramsey\Uuid\Uuid;
use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Concerns\HasUuids as Base;

trait HasUuids
{
    use Base;

    /**
     * @param array<string>|string $uuid
     */
    public function scopeWhereUuid(Builder $query, $uuid): Builder
    {
        $uuids = is_array($uuid) ? $uuid : [$uuid];

        return $this->convertInMysql($query, $uuids);
    }

    private function convertInPhp(Builder $query, array $uuids): Builder
    {
        if (empty($uuids)) {
            return $query->whereRaw('0 = 1');
        }

        $uuids = array_map(function ($uuid) {
            return Uuid::fromString($uuid)->getBytes();
        }, $uuids);

        $placeholders = implode(', ', array_fill(0, count($uuids), '?'));

        return $query->whereRaw(
            "uuid IN ({$placeholders})",
            $uuids
        );
    }

    private function convertInMysql(Builder $query, array $uuids): Builder
    {
        $uuids = array_filter($uuids, function ($uuid) {
            return Str::isUuid($uuid);
        });

        if (empty($uuids)) {
            return $query->whereRaw('0 = 1');
        }

        $placeholders = implode(', ', array_fill(0, count($uuids), 'UUID_TO_BIN(?)'));

        return $query->whereRaw(
            "uuid IN ({$placeholders})",
            $uuids
        );
    }
}