@Mick79 It’s not the default because probably more than 90% of projects use auto-incrementing integers as primary keys in databases.
You can use UUIDs as your Eloquent models’ ID. You need to set the $keyType property to string, and then $incrementing to false. You’ll also need to set $primaryKey if you call your primary key column something other than id. Finally, hook into your model’s creating method to generate a UUID:
use Ramsey\Uuid\Uuid;
class Foo extends Model
{
protected $primaryKey = 'uuid';
protected $keyType = 'string';
public $incrementing = false;
protected static function boot()
{
parent::boot();
static::creating(function (Model $model) {
$model->setAttribute($model->getKeyName(), Uuid::uuid4());
});
}
}
Thanks a lot Martin. I was under the impression that using UUID was a much better idea than standard increments due to potential problems if you ever need to copy tables to another database at any point in the future.
Exports of databases should be unaffected - you can always restore with the same primary key values from when you backed up.
UUIDs can have advantages if you have a distributed system (IDs being generated across several separate machines/databases) and need a (near enough) guarantee of uniqueness across the whole system.
There are several drawbacks though.
It's 16 bytes instead of an integer's 4 or bigint's 8. That takes up more disk for the data and the indexes.
...it therefore requires more RAM to hold cached UUIDs in memory.
...and any joins that involve UUIDs require more memory.
"UUID index fragmentation" ... as the UUIDs are not generated sequentially like integer primary keys the index will be messier and tend to suffer from more bloat.
If you want to sort by the order records were generated, sorting by primary key is the easiest if you use integers: UUIDs won't sort into a logical order as they generated at random.
I have actually been having some issues with it when configuring the primary key using the creating observer. Specifically that the id would be cast to int and I therefore moved to overwriting the methods rather. I use a trait now as follow:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
trait HasUuid
{
/**
* Get the value indicating whether the IDs are incrementing.
*
* @return bool
*/
public function getIncrementing()
{
return false;
}
/**
* Get the auto-incrementing key type.
*
* @return string
*/
public function getKeyType()
{
return 'string';
}
public static function booted()
{
static::creating(function (Model $model) {
// Set attribute for new model's primary key (ID) to an uuid.
$model->setAttribute($model->getKeyName(), Str::uuid());
});
}
}
// In migration file
Schema::create('users', function (Blueprint $table) {
$table->uuid('id')->primary();
// ....
});
Starting from Laravel 9, you can now add the HasUuids trait in model to automatically assign uuid to the primary key column:
// In model
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
class User extends Authenticatable
{
use HasFactory, Notifiable;
use HasUuids; // Add this trait
// ....
}