Your Guide to Laravel Excellence

Laravel 11.30 Introduces HasUniqueStringIds for Simple Unique IDs

Laravel 11.30 Introduces HasUniqueStringIds for Simple Unique IDs

Laravel 11.30 introduces the HasUniqueStringIds trait, which offers custom unique string identifiers for your models is easier than ever and alternatives to standard auto-incrementing IDs. This trait simplifies handling unique string IDs, making it especially useful for applications requiring non-integer IDs without the hassle of complex route-binding adjustments. In this post, we’ll learn the capabilities of HasUniqueStringIds, review practical applications, and provide real-world examples to illustrate its flexibility and ease of use.

What Is the HasUniqueStringIds Trait?

The HasUniqueStringIds trait in Laravel 11.30 provides a way to add unique, customizable, unique string-based IDs (such as UUIDs or ULIDs) for your models without modifying route binding logic.Previously, the HasUuids and HasUlids traits were available for such needs, but HasUniqueStringIds now unifies these into a more flexible approach.

Practical Use of HasUniqueStringIds with Examples

Let's explore HasUniqueStringIds with some common scenarios where custom string IDs can enhance your application.

1. Basic Usage with Custom UUID

A common use case is generating UUIDs (Universally Unique Identifiers) for each model instance. Using HasUniqueStringIds, you can easily generate UUIDs while keeping your routes compatible.


<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;

class Product extends Model
{

   use \Illuminate\Database\Eloquent\Concerns\HasUniqueStringIds;
   protected function newUniqueId(): string
   {
       return (string) Str::uuid();
   }

   protected function isValidKey(string $key): bool
   {
       return Str::isUuid($key);
   }

}

In this example:

The newUniqueId() method generates a UUID as a unique ID whenever a new Product is created.

The isValidKey() method checks that the ID is in a valid UUID format, ensuring compatibility across routes and validations.

2. Custom ID with ULID Format

ULIDs (Universally Unique Lexicographically Sortable Identifiers) provide an alternative to UUIDs, especially useful when chronological ordering is necessary. Here’s how to set up HasUniqueStringIds for ULID generation:

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Symfony\Component\Uid\Ulid;

class Order extends Model
{
    use \Illuminate\Database\Eloquent\Concerns\HasUniqueStringIds;
    protected function newUniqueId(): string
    {
        return (string) new Ulid();
    }

    protected function isValidKey(string $key): bool
    {
        return Ulid::isValid($key);
    }
}

In this example:

newUniqueId() returns a new ULID for each Order instance.

isValidKey() ensures IDs match the ULID format. This is helpful if you want IDs that are unique, lexicographically sortable, and more readable.

3. Custom Format (e.g., Product Codes)

For some applications, it’s helpful to use readable IDs, like product codes or custom tags, that follow a specific format. Here’s an example of generating an ID in the format PRD-XXXXX (where XXXXX is a random alphanumeric string):

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;

class InventoryItem extends Model
{

    use \Illuminate\Database\Eloquent\Concerns\HasUniqueStringIds;
    protected function newUniqueId(): string
    {
        $random = strtoupper(Str::random(5));
        return "PRD-{$random}";
    }

    protected function isValidKey(string $key): bool
    {
        return preg_match('/^PRD-[A-Z0-9]{5}$/', $key) === 1;
    }
}

In this example:

newUniqueId() creates a product ID in the PRD-XXXXX format, making IDs more readable and recognizable.

isValidKey() checks for adherence to the format, allowing consistent IDs that fit a specific business logic.

4. Tenant-Scoped Unique IDs (Multi-Tenant Applications)

In multi-tenant applications, it’s often necessary to scope unique IDs by tenant. For instance, an ID could include both a tenant prefix and a unique suffix. Here’s an example that generates an ID in the format TENANT-ID-XXXXXX:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;

class TenantModel extends Model
{
    use \Illuminate\Database\Eloquent\Concerns\HasUniqueStringIds;
    protected function newUniqueId(): string
    {
        $tenantId = tenant()->id;  // Assuming tenant() helper returns the current tenant ID
        $random = strtoupper(Str::random(6));
        return "{$tenantId}-{$random}";
    }

    protected function isValidKey(string $key): bool
    {
        return preg_match('/^[A-Z0-9]+-[A-Z0-9]{6}$/', $key) === 1;
    }

    // Optionally override uniqueIds() to ensure uniqueness within each tenant scope
    public function uniqueIds(): array
    {
        return ['id', 'tenant_id'];
    }
}

In this example:

newUniqueId() incorporates a tenant ID prefix, making the ID globally unique within the context of each tenant.

isValidKey() verifies that the generated ID meets the desired format.

Why HasUniqueStringIds Matters

The new HasUniqueStringIds trait is a significant addition to Laravel, offering the following advantages:

  • Simplified ID Management: By centralizing ID generation and validation, HasUniqueStringIds removes the need for complex workarounds or custom route-binding logic.

  • Enhanced Flexibility: This trait allows applications to easily adapt to unique ID needs, whether it’s for SEO-friendly URLs, readable product codes, or compliance with third-party systems.

  • Backward Compatibility: Legacy code using HasUuids and HasUlids still functions without modifications, making it easier to adopt this trait in existing projects.

Using HasUniqueStringIds in Routes

Suppose you want routes to include these unique string-based IDs for better readability and SEO benefits. With the new trait, you can bind these custom IDs directly in routes without adjusting resolveRouteBindingQuery(). Example:

Route::get('/products/{product}', function (Product $product) {
    return view('product.show', ['product' => $product]);
});

Why This Trait Matters

By using HasUniqueStringIds, Laravel enables you to:

  • Define unique, complex ID patterns without impacting route binding or other core model behaviors.

  • Simplify model creation by eliminating the need for custom binding logic.

  • Adopt a flexible, backward-compatible trait that can evolve with Laravel’s future releases.

Recommeded Posts

Model Change Tracking in Laravel 11 - Laravel Auditing

Model Change Tracking in Laravel 11 - Laravel Auditing

Model Change Tracking in Laravel 11 - Laravel Auditing

1 month ago Read article →
Introduction to Multiple Authentication Guards in Laravel

Introduction to Multiple Authentication Guards in Laravel

Introduction to Multiple Authentication Guards in Laravel

1 month ago Read article →
Upload Huge File - Mastering Chunked File Uploads in Laravel

Upload Huge File - Mastering Chunked File Uploads in Laravel

Upload Huge File - Mastering Chunked File Uploads in Laravel

1 month ago Read article →
Laravel custom login and register Tutorial

Laravel custom login and register Tutorial

Laravel custom login and register Tutorial

1 month ago Read article →