Referenceable: Flexible Template-Driven References for Laravel

Referenceable: Flexible Template-Driven References for Laravel

6 min read Mohamed Said Mohamed Said

Referenceable Laravel Package: Flexible Reference Number Generation for Eloquent Models

GitHub Repository: https://github.com/EG-Mohamed/Referenceable

Introduction

Referenceable is a powerful Laravel package that helps you generate unique, customizable reference numbers for Eloquent models.

It is useful for applications that need readable IDs for orders, invoices, bookings, tickets, products, assets, subscriptions, or any record that should have a human-friendly reference instead of relying only on database IDs.

With Referenceable, you can generate random references, sequential numbers, or fully customized template-based references using prefixes, dates, counters, and random strings.

Why Use Referenceable?

In many Laravel applications, using a plain auto-increment ID is not ideal for business-facing records. For example, an order number like ORD-2026-0001 is clearer, more professional, and easier to share with customers than #153.

Referenceable solves this by giving you a clean, configurable way to automatically generate and manage references for your models.

Key Features

  • Multiple reference generation strategies: random, sequential, and template-based
  • Custom prefixes, suffixes, separators, length, and character sets
  • Template placeholders such as {YEAR}, {MONTH}, {DAY}, {SEQ}, and {RANDOM}
  • Sequential numbering with optional daily, monthly, or yearly reset
  • Built-in validation and uniqueness checking
  • Automatic collision handling
  • Tenant-aware reference generation for multi-tenant applications
  • Artisan commands for generating, validating, and regenerating references
  • Batch processing support
  • Configuration caching and database transaction support
  • Compatible with modern Laravel applications

Installation

Install the package using Composer:

composer require eg-mohamed/referenceable

Then run the installation command:

php artisan referenceable:install

This command publishes the configuration file and creates the required database tables.

Quick Start

1. Add a Reference Column to Your Migration

Schema::create('orders', function (Blueprint $table) {
    $table->id();
    $table->string('reference')->unique()->index();
    $table->timestamps();
});

2. Use the Trait in Your Model

use MohamedSaid\Referenceable\Traits\HasReference;

class Order extends Model
{
    use HasReference;

    protected $fillable = ['total', 'customer_id'];
}

3. Create a Model Record

$order = Order::create([
    'customer_id' => 1,
    'total' => 99.99,
]);

echo $order->reference;

Example output:

AB12CD34

The reference is generated automatically when the model is created.

Reference Generation Strategies

Referenceable supports three main generation strategies.

Random Strategy

The random strategy is useful when you need short, unique, non-sequential references.

protected $referenceStrategy = 'random';
protected $referencePrefix = 'ORD';
protected $referenceLength = 6;
protected $referenceCase = 'upper';

Example output:

ORD-AB12CD

Sequential Strategy

The sequential strategy is ideal for invoices, orders, tickets, and other records that need ordered numbering.

protected $referenceStrategy = 'sequential';
protected $referencePrefix = 'INV';

protected $referenceSequential = [
    'start' => 1000,
    'min_digits' => 6,
    'reset_frequency' => 'yearly',
];

Example output:

INV-001000
INV-001001
INV-001002

Template Strategy

The template strategy gives you full control over the reference format.

protected $referenceStrategy = 'template';

protected $referenceTemplate = [
    'format' => '{PREFIX}{YEAR}{MONTH}{SEQ}',
    'sequence_length' => 4,
];

protected $referencePrefix = 'ORD';

Example output:

ORD2026060001
ORD2026060002

Available Template Placeholders

| Placeholder | Description | Example | |---|---|---| | {PREFIX} | Custom prefix | ORD | | {SUFFIX} | Custom suffix | 2026 | | {YEAR} | Four-digit year | 2026 | | {YEAR2} | Two-digit year | 26 | | {MONTH} | Two-digit month | 06 | | {DAY} | Two-digit day | 03 | | {SEQ} | Sequential number | 0001 | | {RANDOM} | Random string | AB12 | | {MODEL} | Model class name | Order | | {TIMESTAMP} | Unix timestamp | 1780459200 |

Model-Level Configuration

You can customize the reference behavior directly inside each model.

class Order extends Model
{
    use HasReference;

    protected $referenceColumn = 'order_number';
    protected $referenceStrategy = 'template';
    protected $referencePrefix = 'ORD';
    protected $referenceSuffix = '';
    protected $referenceSeparator = '-';

    protected $referenceLength = 8;
    protected $referenceCharacters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    protected $referenceExcludedCharacters = '01IOL';
    protected $referenceCase = 'upper';

    protected $referenceSequential = [
        'start' => 1,
        'min_digits' => 6,
        'reset_frequency' => 'yearly',
    ];

    protected $referenceTemplate = [
        'format' => '{PREFIX}{YEAR}{MONTH}{SEQ}',
        'random_length' => 4,
        'sequence_length' => 4,
    ];

    protected $referenceValidation = [
        'pattern' => '/^ORD-\d{4}-\w{6}$/',
        'min_length' => 8,
        'max_length' => 20,
    ];

    protected $referenceUniquenessScope = 'model';
    protected $referenceTenantColumn = 'company_id';
    protected $referenceCollisionStrategy = 'retry';
    protected $referenceMaxRetries = 100;
}

Global Configuration

You can define default behavior in:

config/referenceable.php

Example:

return [
    'strategy' => 'random',
    'column_name' => 'reference',

    'length' => 6,
    'prefix' => '',
    'suffix' => '',
    'separator' => '-',
    'characters' => '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',
    'excluded_characters' => '01IOL',
    'case' => 'upper',

    'sequential' => [
        'start' => 1,
        'min_digits' => 6,
        'reset_frequency' => 'never',
        'counter_table' => 'model_reference_counters',
    ],

    'template' => [
        'format' => '{PREFIX}{YEAR}{MONTH}{SEQ}',
        'random_length' => 4,
        'sequence_length' => 4,
    ],

    'validation' => [
        'enabled' => true,
        'min_length' => 3,
        'max_length' => 50,
    ],

    'uniqueness_scope' => 'model',
    'collision_strategy' => 'retry',
    'max_retries' => 100,

    'performance' => [
        'cache_config' => true,
        'cache_ttl' => 60,
        'use_transactions' => true,
        'batch_size' => 100,
    ],
];

Manual Reference Generation

You can generate, regenerate, and check references manually when needed.

$reference = $order->generateReference();

$newReference = $order->regenerateReference(save: true);

if ($order->hasReference()) {
    echo $order->reference;
}

Reference Validation

Validate the current model reference:

if ($order->validateReference()) {
    echo 'Valid reference';
}

Validate a custom reference:

if ($order->validateReference('ORD-123456')) {
    echo 'Valid format';
}

Query Scopes

Find a model by reference:

$order = Order::findByReference('ORD-123456');

Get models with references:

$ordersWithRefs = Order::withReference()->get();

Get models without references:

$ordersWithoutRefs = Order::withoutReference()->get();

Find references starting with a specific value:

$todayOrders = Order::referenceStartsWith('ORD-2026')->get();

Batch Operations

use MohamedSaid\ModelReference\ModelReference;

$modelReference = app(ModelReference::class);

$references = $modelReference->generateBatch(Order::class, 100);

$results = $modelReference->validateBulk($references->toArray());

$stats = $modelReference->getStats(Order::class);

Artisan Commands

Installation

php artisan referenceable:install
php artisan referenceable:install --force

Generate References

php artisan referenceable:generate "App\\Models\\Order"
php artisan referenceable:generate "App\\Models\\Order" --dry-run
php artisan referenceable:generate "App\\Models\\Order" --batch=500

Validate References

php artisan referenceable:validate "App\\Models\\Order"
php artisan referenceable:validate "App\\Models\\Order" --fix

Regenerate References

php artisan referenceable:regenerate "App\\Models\\Order" --id=123
php artisan referenceable:regenerate "App\\Models\\Order" --all --dry-run

View Statistics

php artisan referenceable:stats "App\\Models\\Order"
php artisan referenceable:stats "App\\Models\\Order" --json

Show Package Commands

php artisan referenceable
php artisan referenceable --list

Multi-Tenancy Support

Referenceable supports tenant-aware uniqueness, which is useful for SaaS and multi-company systems.

class Order extends Model
{
    use HasReference;

    protected $referenceUniquenessScope = 'tenant';
    protected $referenceTenantColumn = 'company_id';
}

With this setup, references can be unique per tenant instead of globally unique across the entire application.

Performance Optimization

For better performance, make sure your reference columns are indexed.

Schema::table('orders', function (Blueprint $table) {
    $table->index('reference');
    $table->index(['company_id', 'reference']);
});

You can also enable configuration caching and transactions:

'performance' => [
    'cache_config' => true,
    'cache_ttl' => 60,
    'use_transactions' => true,
    'batch_size' => 100,
],

Common Use Cases

Referenceable is suitable for:

  • Order numbers
  • Invoice numbers
  • Booking references
  • Ticket IDs
  • Product codes
  • Shipment tracking references
  • Customer account numbers
  • Asset tracking numbers
  • Subscription references
  • Multi-tenant business records

Example Reference Formats

ORD-2026-0001
INV-000125
TCK-AB92KD
BOOK-202606-0042
ASSET-2026-XY91

Migration Guide from v1.x to v2.x

1. Run the Installation Command

php artisan referenceable:install

2. Update Your Model Configuration

Old format:

protected $referenceLength = 8;

This is still supported, but you can also use the newer template configuration:

protected $referenceTemplate = [
    'format' => '{PREFIX}{RANDOM}',
    'random_length' => 8,
];

3. Validate Existing References

php artisan referenceable:validate "App\\Models\\Order"

Conclusion

Referenceable gives Laravel developers a clean and flexible way to generate professional reference numbers for Eloquent models.

It supports random references, sequential numbering, custom templates, validation, collision handling, tenant-aware uniqueness, and helpful Artisan commands. This makes it a strong choice for Laravel applications that need reliable reference generation for orders, invoices, tickets, bookings, assets, or any business-facing record.

For source code and installation details, visit the GitHub repository:

https://github.com/EG-Mohamed/Referenceable

Found this useful?

Continue reading

More Articles

View all