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