eg-mohamed/referenceable
Laravel package to make Eloquent models referenceable with customizable reference numbers. Supports random, sequential and template-based formats (YEAR/MONTH/SEQ/RANDOM), collision handling, validation, reset rules (daily/monthly/yearly), multi-tenancy, artisan tools, caching and Laravel 10–13.
HasReference), allowing granular adoption per model without monolithic changes. This aligns well with Laravel’s modular architecture.config/referenceable.php) and model-specific overrides, enabling consistent yet flexible reference generation across the application.company_id), making it ideal for SaaS platforms or partitioned databases.model_reference_counters) for sequential strategies, which must be accounted for in migrations. Existing applications can adapt this with minimal effort.| Risk Area | Assessment | Mitigation |
|---|---|---|
| Collision Handling | Random strategies may require retries (configurable via referenceMaxRetries). Sequential strategies are collision-proof but require careful counter management. |
Use collision_strategy: 'fail' for critical paths and monitor retry logs. |
| Sequential Gaps | If references are deleted, sequential counters may leave gaps (e.g., INV-0001 deleted → INV-0002 skips INV-0001). |
Document this behavior in the system design. Use reset_frequency (e.g., yearly) to mitigate gaps. |
| Multi-Tenancy Overhead | Tenant-aware uniqueness adds complexity to queries (e.g., WHERE company_id = ? AND reference = ?). |
Ensure proper database indexing on (tenant_column, reference). Benchmark query performance under high concurrency. |
| Template Complexity | Custom templates (e.g., {PREFIX}{YEAR}{SEQ}) may introduce parsing errors or edge cases (e.g., leap years, timezone handling). |
Test templates thoroughly with edge cases. Use dry-run in Artisan commands to validate formats before deployment. |
| Migration Downtime | Adding the reference column to large tables may cause locks or slow migrations. | Run migrations during low-traffic periods. Use batch operations (--batch=500) for backfilling references. |
| Vendor Lock-in | Heavy reliance on package-specific traits/methods (e.g., generateReference(), validateReference()) may complicate future extraction. |
Abstract critical logic behind interfaces (e.g., ReferenceGenerator) to ease future decoupling. |
Business Requirements:
Technical Constraints:
tenant_id)?Operational Considerations:
Performance:
Future-Proofing:
ORD-****-1234)?findByReference() scopes).referenceable:generate) align with Laravel’s dev workflow.create(), factory()) simplify validation.| Phase | Actions | Tools/Commands |
|---|---|---|
| Assessment | Audit existing models for reference needs. Identify high-priority models (e.g., Order, Invoice). |
Manual review + php artisan make:model analysis. |
| Pilot | Implement in one model (e.g., Order) with default random strategy. Test generation, validation, and collision handling. |
composer require eg-mohamed/referenceable, php artisan referenceable:install, model trait addition. |
| Configuration | Define global defaults (e.g., prefix: "ORD", separator: "-") and model-specific overrides (e.g., Invoice uses sequential with yearly reset). |
config/referenceable.php + model-level config. |
| Backfill | Generate references for existing records using batch operations. | php artisan referenceable:generate App\Models\Order --batch=500. |
| Validation | Run dry-run validations to catch format/Uniqueness issues. | php artisan referenceable:validate App\Models\Order --dry-run. |
| Monitoring | Set up logging for reference generation failures (e.g., collision retries). | Laravel’s Log facade + referenceMaxRetries tuning. |
| Rollout | Gradually enable for other models. Replace auto-increment IDs with references in user-facing systems (e.g., emails, PDFs). | Feature flags for reference visibility. |
| Optimization | Add database indexes, tune cache TTL, and monitor performance under load. | EXPLAIN queries, Laravel Debugbar, Blackfire. |
// app/Providers/ReferenceableServiceProvider.php
public function register()
{
$this->app->extend('referenceable.strategy', function ($app) {
return new CustomStrategy();
});
}
How can I help you explore Laravel packages today?