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.
Please install the package via Composer:
composer require verbanent/eloquent-binary-uuid
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');
});
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';
}
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'];
}
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',
];
}
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ÔƒÅþ"
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"
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"
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ÔƒÅþ"
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