Using Stripe-like, human-readable IDs in Laravel Models and Migrations. This will fully use Stripe-like IDs (like "usr_123123123" or "team_123123123") instead of auto-incrementing IDs or UUIDs in your models.
- In your migrations, change
$table->id();
to$table->string('id')->primary();
- Add the new
HasHashIds
trait toapp/Traits/HasHashIds.php
<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Concerns\HasUniqueStringIds;
use Illuminate\Support\Str;
trait HasHashIds
{
use HasUniqueStringIds;
/**
* Generate a new unique key for the model.
*
* @return string
*/
public function newUniqueId()
{
return (string) $this->hashPrefix . Str::ulid();
}
/**
* Determine if given key is valid.
*
* @param mixed $value
* @return bool
*/
protected function isValidUniqueId($value): bool
{
return Str::startsWith($value, $this->hashPrefix);
}
}
- In your model classes, use the trait and define a descriptive hash prefix to use (like "usr_", "team_" or "project_"):
<?php
namespace App\Models;
use App\Traits\HasHashIds;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Project extends Model
{
/** @use HasFactory<\Database\Factories\ProjectFactory> */
use HasFactory;
use HasHashIds;
protected $hashPrefix = 'proj_';
}
- Using
foreignIdFor
in your migrations will not work anymore since it only supports UUID and integer IDs. To reference tables, you will instead need to define a custom macro. For this, create a providerDatabaseServiceProvider
(or whatever you want to call it) and add this content:
<?php
namespace App\Providers;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\ServiceProvider;
class DatabaseServiceProvider extends ServiceProvider
{
/**
* Register services.
*/
public function register(): void
{
//
}
/**
* Bootstrap services.
*/
public function boot(): void
{
Blueprint::macro('foreignHashIdFor', function ($model, $column = null, $length = null) {
$instance = new $model;
$column = $column ?: $instance->getForeignKey();
$length = $length ?: 255;
$this->string($column, $length);
return $this->foreign($column)
->references($instance->getKeyName())
->on($instance->getTable());
});
}
}
This creates a new function foreignHashIdFor
that you can call with the model class, exactly like foreignIdFor.