Skip to content

Ordered binary UUID in Laravel / Eloquent based on UUID version 1

License

Notifications You must be signed in to change notification settings

verbanent/eloquent-binary-uuid

Repository files navigation

Ordered binary UUID in Laravel / Eloquent

Quality Gate Status Downloads StyleCI CodeFactor Maintainability Rating Lines of Code Coverage Packagist PHP Version Support Packagist License

Based on articles about the optimization of UUID storage in databases, I decided to write a simple library that allows this in my projects. I based on the information available here:
https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/
https://www.percona.com/community-blog/2018/10/12/generating-identifiers-auto_increment-sequence/

The package currently only supports MySQL.

Installation

Please install the package via Composer:

composer require verbanent/eloquent-binary-uuid

Migration

Your model will use an ordered binary UUID, if you prepare a migration:

Schema::create('table_name', function (Blueprint $table) {
    $table->uuid('id');
});

Or if you want to use a custom column name for the primary key:

Schema::create('table_name', function (Blueprint $table) {
    $table->uuid('uuid');
    $table->primary('uuid');
});

Using UUID in models

All what you have to do, is use a new trait in models with UUID as a primary key:

use Illuminate\Database\Eloquent\Model;
use Verbanent\Uuid\Traits\BinaryUuidSupportableTrait;

class Book extends Model
{
    use BinaryUuidSupportableTrait;
}

The above example works for the column id. If you use custom name for UUID column, you need to define it:

use Illuminate\Database\Eloquent\Model;
use Verbanent\Uuid\Traits\BinaryUuidSupportableTrait;

class Book extends Model
{
    use BinaryUuidSupportableTrait;

    public $uuidColumn = 'uuid';
}

Abstract model for model with UUID

For your convenience you can extend your model with AbstractModel:

use Verbanent\Uuid\AbstractModel;

class Lang extends AbstractModel
{
    //
}

The above example works for the column id. If you use custom name for UUID column, you need to define it:

use Verbanent\Uuid\AbstractModel;

class Lang extends AbstractModel
{
    public $uuidColumn = 'uuid';
    protected $primaryKey = 'uuid';
    protected $fillable = ['uuid'];
}

Foreign binary UUID

If you would like to use UUID as a foreign key, use another trait and set $uuidable property for this model:

use Verbanent\Uuid\AbstractModel;
use Verbanent\Uuid\Traits\ForeignBinaryUuidSupportableTrait;

class LangTranslation extends AbstractModel
{
    use ForeignBinaryUuidSupportableTrait;

    private $uuidable = [
        'lang',
        'one_lang_bucket',
    ];
}

Getting a string form of UUID

The library is kept as simple as possible, so if you want to get a string form of UUID, just use a method:

$book = new \App\Book;
$book->save();
dd($book->uuid());
// Output: "11e947f9-a1bd-f844-88d8-6030d483c5fe"

or use a property, if you need a binary value:

# If you use the default primary key:
dd($book->id);
// Output: b"\x11éGù¡½øDˆØ`0ÔƒÅþ"

# If you use `uuid` as a primary key:
dd($book->uuid);
// Output: b"\x11éGù¡½øDˆØ`0ÔƒÅþ"

Finding by primary UUID

For primary keys finding rows is simple and always return a model:

$lang = Lang::find('11e947f9-a1bd-f844-88d8-6030d483c5fe');
dd($lang->uuid());
// Output: "11e947f9-a1bd-f844-88d8-6030d483c5fe"

Finding by foreign UUID

For foreign keys finding rows requires a column name and returns collection of model:

$langTranslation = LangTranslation::findByUuid('lang', '11e947f9-a1bd-f844-88d8-6030d483c5fe');
dd($langTranslation[0]->uuid(), $langTranslation[1]->uuid(), $langTranslation[2]->uuid());
// Output: "11e94805-b94c-68e0-8720-6030d483c5fe"
//         "11e94805-b955-4e2e-b089-6030d483c5fe"
//         "11e94805-b957-af02-8bf8-6030d483c5fe"

Getting a foreign UUID string

You can print string form of your foreign UUID keys:

$translation = LangTranslation::findByUuid('lang', '11e947f9-a1bd-f844-88d8-6030d483c5fe')->first();
dd($translation->foreignUuid('lang'));
// Output: "11e947f9-a1bd-f844-88d8-6030d483c5fe"

Because trying to have access to the property directly will print binary form of UUID:

dd($translation->lang);
// Output: b"\x11éGù¡½øDˆØ`0ÔƒÅþ"

Unit tests

Run this command if you want to check unit tests:

./vendor/bin/phpunit

Or if you want to check code coverage:

phpdbg -qrr vendor/bin/phpunit --coverage-html coverage tests