Skip to content

mcandylab/laravel-cuid2

Repository files navigation

Laravel CUID2

🇬🇧 English | 🇷🇺 Русский

Latest Version on Packagist Total Downloads run-tests

Use CUID2 as primary keys for your Eloquent models in Laravel. The package provides a model trait, a global cuid2() helper and schema macros for migrations. Generation is delegated to the visus/cuid2 library.

Requirements

  • PHP >= 8.2
  • Laravel 12 or 13 (Laravel 13 requires PHP 8.3+)

Installation

composer require mcandylab/laravel-cuid2

The package uses auto-discovery. Publish the config if needed:

php artisan vendor:publish --provider="Mcandylab\LaravelCuid2\LaravelCuid2ServiceProvider" --tag="config"

Usage

Model trait

Add the HasCuid2 trait — the primary key will be automatically populated with a valid CUID2 when a record is created:

use Illuminate\Database\Eloquent\Model;
use Mcandylab\LaravelCuid2\Concerns\HasCuid2;

class Post extends Model
{
    use HasCuid2;
}

The trait sets keyType = 'string' and incrementing = false for you. To generate a cuid2 for more than just the primary key, override uniqueIds():

public function uniqueIds(): array
{
    return [$this->getKeyName(), 'public_id'];
}

Migrations

The cuid2() and foreignCuid2() macros declare char columns of the configured length:

Schema::create('posts', function (Blueprint $table) {
    $table->cuid2()->primary();      // id column
    $table->string('title');
    $table->timestamps();
});

Schema::create('comments', function (Blueprint $table) {
    $table->cuid2()->primary();
    $table->foreignCuid2('post_id')->constrained();
    $table->text('body');
});

For polymorphic relations use cuid2Morphs() (and nullableCuid2Morphs()), the CUID2 counterparts of Laravel's ulidMorphs(). They add a {name}_type string column, a {name}_id varchar column and a composite index:

Schema::create('tokens', function (Blueprint $table) {
    $table->cuid2()->primary();
    $table->cuid2Morphs('tokenable');          // tokenable_type + tokenable_id
    $table->string('token');
});

// nullable variant
$table->nullableCuid2Morphs('tokenable');

Helper

$id = cuid2();      // 24 characters (or config('laravel-cuid2.length'))
$short = cuid2(10); // exactly 10 characters (4..32 allowed)

Facade

use Mcandylab\LaravelCuid2\LaravelCuid2Facade as Cuid2;

Cuid2::generate();          // generate an id
Cuid2::isValid($someId);    // validate a string

Str macros

Aligned with the core Str::uuid() / Str::ulid() helpers:

use Illuminate\Support\Str;

Str::cuid2();          // generate (respects config('laravel-cuid2.length'))
Str::cuid2(10);        // exactly 10 characters (4..32 allowed)
Str::isCuid2($value);  // validate a value (false for non-strings)

Faker

A cuid2() Faker formatter is available for factories and seeders:

use App\Models\Post;

Post::factory()->create(['id' => fake()->cuid2()]);

fake()->cuid2();   // generate (respects config('laravel-cuid2.length'))
fake()->cuid2(10); // exactly 10 characters (4..32 allowed)

Validation

The cuid2 rule validates that a value is a well-formed CUID2 of any valid length (4..32). It is available in three forms:

use Illuminate\Validation\Rule;
use Mcandylab\LaravelCuid2\Rules\Cuid2;

$request->validate([
    'id'    => 'cuid2',          // string rule
    'ref'   => [new Cuid2],      // rule object
    'ext'   => [Rule::cuid2()],  // rule macro
]);

Prefixed identifiers (Stripe-style)

You can produce human-readable identifiers such as user_p6p168tx… by declaring a $cuid2Prefix property on the model. The prefix is just an envelope — the cuid2 part after the _ stays fully spec-compliant:

class User extends Model
{
    use HasCuid2;

    protected string $cuid2Prefix = 'user';
}

Size the column with cuid2WithPrefix() (and foreignCuid2WithPrefix() for foreign keys). They create a varchar column (using Laravel's Schema::defaultStringLength, 255 by default), which fits any {prefix}_{cuid2} value and is fully indexable:

Schema::create('users', function (Blueprint $table) {
    $table->cuid2WithPrefix('id')->primary();
    $table->string('name');
});

// a foreign key referencing a prefixed model
$table->foreignCuid2WithPrefix('user_id');

The generators accept an optional prefix too:

cuid2(prefix: 'user');            // user_…
Str::cuid2(prefix: 'user');       // user_…
fake()->cuid2(prefix: 'user');    // user_…

Validation can optionally check the prefix — it verifies the {prefix}_ and that the remainder is a valid CUID2. Without a prefix the rule is unchanged:

$request->validate([
    'id'  => 'cuid2:user',                 // string rule
    'id2' => [new Cuid2('user')],          // rule object
    'id3' => [Rule::cuid2(prefix: 'user')], // rule macro
]);

Str::isCuid2($value, 'user');              // and via the Str macro

Note: cuid2Morphs() / nullableCuid2Morphs() create a varchar {name}_id column, so a prefixed model can safely be a polymorphic target without truncation. The macros take no prefix argument — a polymorphic column may point at models with different prefixes, and the prefix is already implied by the {name}_type column.

Configuration

config/laravel-cuid2.php:

return [
    // Identifier length (4..32). The cuid2 standard is 24.
    'length' => (int) env('CUID2_LENGTH', 24),
];

Testing

composer test

Changelog

See CHANGELOG.

Contributing

See CONTRIBUTING.

Security

If you discover any security related issues, please open an issue.

Credits

License

The MIT License (MIT). See License File.

About

CUID2 support for Laravel

Resources

License

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages