alimarchal/id-generator
Generate unique, professional document IDs in Laravel (PREFIX-YYYYMMDD-XXXX) with transaction safety and race-condition protection. Ideal for invoices, complaints, orders, quotations, and more. Compatible with Laravel 11/12, scalable for high volume.
A powerful Laravel package to generate unique, prefixed IDs with database transaction safety and race condition protection. Perfect for invoices, complaints, quotations, orders, and any document that needs professional numbering.
// Generate professional IDs instantly
$invoiceId = generateUniqueId('invoice', 'invoices', 'invoice_no');
// Output: INV-20250814-0001
$complaintId = generateUniqueId('complaint', 'complaints', 'complaint_no');
// Output: CMP-20250814-0001
When building applications, you often need to generate unique document numbers like:
INV-20250814-0001CMP-20250814-0001ORD-20250814-0001Common challenges:
This package provides:
PREFIX-YYYYMMDD-XXXX formatcomposer require alimarchal/id-generator
That's it! Thanks to Laravel's auto-discovery, the package is immediately ready to use.
php artisan vendor:publish --tag=id-generator-migrations
php artisan migrate
This creates an id_prefixes table with sample data:
| id | name | prefix | created_at | updated_at |
|---|---|---|---|---|
| 1 | invoice | INV | ... | ... |
| 2 | complaint | CMP | ... | ... |
| 3 | quotation | QTN | ... | ... |
use Illuminate\Support\Facades\DB;
DB::table('id_prefixes')->insert([
['name' => 'order', 'prefix' => 'ORD'],
['name' => 'receipt', 'prefix' => 'RCP'],
['name' => 'estimate', 'prefix' => 'EST'],
]);
The simplest way to generate IDs anywhere in your application.
// Generate invoice number using 'invoice' type from database
$invoiceId = generateUniqueId('invoice', 'invoices', 'invoice_no');
// Output: INV-20250814-0001
// Generate complaint number
$complaintId = generateUniqueId('complaint', 'complaints', 'complaint_no');
// Output: CMP-20250814-0001
// Generate quotation number
$quotationId = generateUniqueId('quotation', 'quotations', 'quotation_no');
// Output: QTN-20250814-0001
// Generate ID with custom prefix (no database lookup)
$orderId = generateUniqueIdWithPrefix('ORD', 'orders', 'order_no');
// Output: ORD-20250814-0001
$customId = generateUniqueIdWithPrefix('CUST', 'customers', 'customer_id');
// Output: CUST-20250814-0001
Perfect when you need more control or are following SOLID principles.
<?php
namespace App\Http\Controllers;
use Alimarchal\IdGenerator\IdGenerator;
use App\Models\Invoice;
use Illuminate\Http\Request;
class InvoiceController extends Controller
{
public function store(Request $request, IdGenerator $idGenerator)
{
// Method 1: Using database prefix
$invoiceNumber = $idGenerator->generate('invoice', 'invoices', 'invoice_no');
// Method 2: Using direct prefix
$orderNumber = $idGenerator->generateWithPrefix('ORD', 'orders', 'order_no');
$invoice = Invoice::create([
'invoice_no' => $invoiceNumber,
'customer_name' => $request->customer_name,
'amount' => $request->amount,
]);
return response()->json(['invoice' => $invoice], 201);
}
}
class OrderController extends Controller
{
public function createOrder(Request $request, IdGenerator $idGenerator)
{
$orderNumber = $idGenerator->generate('order', 'orders', 'order_no');
// Output: ORD-20250814-0001
$invoiceNumber = $idGenerator->generate('invoice', 'invoices', 'invoice_no');
// Output: INV-20250814-0001
$trackingNumber = $idGenerator->generateWithPrefix('TRK', 'shipments', 'tracking_no');
// Output: TRK-20250814-0001
// Create order with all numbers...
}
}
class TicketController extends Controller
{
public function createTicket(Request $request)
{
$ticketNumber = generateUniqueId('ticket', 'tickets', 'ticket_no');
// Output: TKT-20250814-0001
$ticket = Ticket::create([
'ticket_no' => $ticketNumber,
'title' => $request->title,
'priority' => $request->priority,
]);
return response()->json(['ticket' => $ticket], 201);
}
}
<?php
namespace App\Http\Controllers;
use App\Models\Invoice;
use Illuminate\Http\Request;
class InvoiceController extends Controller
{
public function store(Request $request)
{
// Validate request...
$request->validate([
'customer_name' => 'required|string',
'amount' => 'required|numeric',
]);
// Generate unique invoice number
$invoiceNumber = generateUniqueId('invoice', 'invoices', 'invoice_no');
// Create invoice
$invoice = Invoice::create([
'invoice_no' => $invoiceNumber,
'customer_name' => $request->customer_name,
'amount' => $request->amount,
'created_at' => now(),
]);
return response()->json([
'message' => 'Invoice created successfully!',
'invoice' => $invoice
], 201);
}
}
// This package handles this scenario automatically:
// User A and User B create invoices at the EXACT same millisecond
// Without protection:
// User A gets: INV-20250814-0001
// User B gets: INV-20250814-0001 ❌ (DUPLICATE!)
// With this package:
// User A gets: INV-20250814-0001 ✅
// User B gets: INV-20250814-0002 ✅ (UNIQUE!)
This package is designed to work with current and future Laravel versions:
// Different prefixes for different environments
// In your AppServiceProvider boot method:
if (app()->environment('production')) {
DB::table('id_prefixes')->updateOrInsert(
['name' => 'invoice'],
['prefix' => 'INV']
);
} else {
DB::table('id_prefixes')->updateOrInsert(
['name' => 'invoice'],
['prefix' => 'TEST-INV']
);
}
// Add new prefix types dynamically
DB::table('id_prefixes')->insert([
'name' => 'purchase-order',
'prefix' => 'PO',
'created_at' => now(),
'updated_at' => now()
]);
// Use the new prefix
$poNumber = generateUniqueId('purchase-order', 'purchase_orders', 'po_number');
// Output: PO-20250814-0001
// The package includes built-in error handling
try {
$invoiceId = generateUniqueId('invoice', 'invoices', 'invoice_no');
} catch (\Exception $e) {
// If normal generation fails, package provides fallback
// Fallback format: INVOICE-1692012345-1234 (timestamp-based)
Log::error("ID generation failed: " . $e->getMessage());
// You still get a unique ID, just less pretty
}
// Solution: Add the prefix to your database
DB::table('id_prefixes')->insert([
'name' => 'your-type',
'prefix' => 'YOUR-PREFIX'
]);
// Solution: Ensure your table has the target column
Schema::table('your_table', function (Blueprint $table) {
$table->string('your_id_column')->unique();
});
generateUniqueId(string $type, string $table, string $column): stringParameters:
$type: Type name from id_prefixes table (e.g., 'invoice')$table: Target database table name$column: Target column name for the IDReturns: Formatted unique ID (e.g., 'INV-20250814-0001')
Throws: \Exception if type not found in database
generateUniqueIdWithPrefix(string $prefix, string $table, string $column): stringParameters:
$prefix: Direct prefix string (e.g., 'INV', 'CUSTOM')$table: Target database table name$column: Target column name for the IDReturns: Formatted unique ID with custom prefix
IdGenerator::generate(string $type, string $table, string $column): stringClass method equivalent to generateUniqueId() helper function.
IdGenerator::generateWithPrefix(string $prefix, string $table, string $column): stringClass method equivalent to generateUniqueIdWithPrefix() helper function.
PREFIX-YYYYMMDD-XXXX| Document Type | Generated ID | Description |
|---|---|---|
| Invoice | INV-20250814-0001 |
First invoice of August 14, 2025 |
| Complaint | CMP-20250814-0001 |
First complaint of August 14, 2025 |
| Order | ORD-20250814-0053 |
53rd order of August 14, 2025 |
| Custom | CUSTOM-20250814-0001 |
Custom prefix example |
We welcome contributions! Please see our Contributing Guide for details.
git clone https://github.com/alimarchal/id-generator.git
cd id-generator
composer install
If you find a bug or have a feature request, please open an issue on GitHub.
This package is open-sourced software licensed under the MIT license.
Made with ❤️ for the Laravel community by Ali Raza Marchal
How can I help you explore Laravel packages today?