Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Referenceable Laravel Package

eg-mohamed/referenceable

Referenceable is a Laravel package that adds customizable reference numbers to Eloquent models. It offers random, sequential, and template-based generation with placeholders like {YEAR} and {SEQ}, plus collision handling, validation, multi-tenancy, and Artisan commands.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • Trait-based (HasReference) with Eloquent lifecycle hooks, a publishable config file, a counter table (model_reference_counters), and Artisan maintenance commands. This is idiomatic Laravel package design — low conceptual overhead, no service container gymnastics, no queue/event infrastructure required.
  • The model-level property API ($referenceStrategy, $referenceTemplate, $referenceUniquenessScope, etc.) keeps policy co-located with the domain model, which is good for discoverability and bad for central governance — we would want an internal convention doc so 20 models don't drift into 20 formats.
  • Three strategies (random / sequential / template) map cleanly onto the business cases TPMs usually get asked for: opaque IDs, human-readable invoice-style numbers, and date-partitioned document codes. The {YEAR}/{MONTH}/{SEQ}/{RANDOM}/{MODEL} placeholder set covers ~90% of reference-format tickets without custom code.

Integration feasibility

  • composer require + php artisan referenceable:install scaffolds config and tables; per-model work is one migration column, one trait line, and optional property overrides. Realistic estimate: half a day for a spike, one to two days to productionize the first model, then near-zero marginal cost per additional model.
  • The backfill path is pre-built: referenceable:generate --dry-run then --batch=500. That materially de-risks adoption on an existing table, which is usually the hardest part of reference-number projects.
  • Main friction is that we own the schema change: the package does not add the reference column or its unique index for us, so the rollout must be sequenced with our own migrations.

Technical risk

  • Bus factor of one. 87 stars, 0 dependents, single maintainer. Zero dependents is the loudest signal here — this is unproven in production anywhere we can observe. Treat as "adopt with a fork plan," not "adopt and forget."
  • Namespace churn. The package was renamed model-reference → referenceable at v2.0.0, and the README still contains a stale MohamedSaid\ModelReference\ModelReference import in the batch-operations section. Documentation drift of this kind usually correlates with untested code paths — the batch API in particular should be verified by hand before we rely on it.
  • Unverifiable compatibility claim. "Laravel 10–13 Ready" includes a version that does not exist yet. We must validate against our actual Laravel/PHP matrix rather than trust the badge.
  • Sequential-generation concurrency. A counter table plus use_transactions plus a retry collision strategy implies row-level contention. Under parallel writes this either serializes on the counter row or produces retries; with max_retries = 100 and no explicit advisory-lock language in the docs, I want to see the implementation before putting a high-throughput table behind it.
  • regenerateReference() is a loaded gun. It is a first-class public method and a referenceable:regenerate --all command exists. Any reference that has escaped the database (emails, PDFs, customer support tickets, external integrations) becomes permanently dangling. This needs policy, not just tooling.
  • Config semantics ambiguity. cache_ttl is commented "Cache for 60 minutes" against a value of 60, which is more plausibly seconds. Small, but it is the kind of ambiguity that turns into a production surprise.

Key questions

  1. Does generation run inside creating (same transaction as insert) or a separate step? What happens to the counter if the insert subsequently fails — do we get gaps, and is that acceptable to finance/audit?
  2. Is the sequential counter incremented under a DB lock (lockForUpdate / atomic update), or read-then-write? This determines whether we can use sequential on a high-write table at all.
  3. Is the counter table keyed per-model, per-model-per-reset-period, and per-tenant? The docs show a single counter_table config with no mention of tenant partitioning — how does uniqueness_scope = 'tenant' interact with sequence numbering?
  4. Does the package create the unique index, or does it rely purely on application-level uniqueness checks? (If the latter, we must add the DB constraint ourselves — non-negotiable.)
  5. What is the test suite / CI matrix, and does it run against our exact Laravel version?
  6. What is the maintainer's stated support window, and what is the project's policy on breaking changes within a major?

Integration Approach

Stack fit

  • Requires Laravel (10+ claimed), Eloquent, and a relational DB with transactional support. Fits a standard MySQL/Postgres Laravel monolith or modular app without adaptation. No Redis, no queue, no external service — which is a genuine operational advantage for a reference-number concern.
  • Multi-tenancy is first-class (uniqueness_scope = 'tenant', tenant_column), which is the deciding factor if we're on a shared-schema multi-tenant model. If we're on database-per-tenant, the feature is inert but harmless.
  • Poor fit if we need references generated outside Laravel (a separate Go service, a batch importer, a partner API writing directly to the DB). The generator is PHP-only, so cross-writer scenarios would need a DB sequence/trigger instead.

Migration path

  1. Prototype in a scratch branch against a non-critical model; verify trait behavior, event ordering, and the actual generated formats.
  2. Introduce an internal ReferenceGenerator interface with the package behind a thin adapter. This is the single highest-leverage TPM decision here: it costs ~1 day and makes the "maintainer abandons the package" scenario a swap, not a rewrite.
  3. Add reference as nullable with a plain index on the pilot table; deploy; backfill via referenceable:generate --dry-run → review → real run in batches; then add the UNIQUE constraint in a subsequent deploy (avoids a locking ALTER on a large table and avoids failing on pre-existing NULLs).
  4. Expand model by model. Each new model is an independent, reversible change.
  5. Document an exit path: a referenceable:export of formats and a one-page note on how to reimplement each strategy in ~100 lines if we fork.

Compatibility

  • Validate composer.json constraints against our pinned Laravel/PHP versions before committing — the "Laravel 13" claim suggests the constraint may be permissive (^10|^11|^12|^13) and permissive constraints are how untested combinations reach production.
  • The v1→v2 rename means any existing internal code or older tutorials referencing ModelReference will not work. Greenfield for us, so low impact — but do not copy README snippets verbatim; the batch-ops example is stale.

Sequencing

  • Week 1: spike + adapter + pilot model in staging.
  • Week 2: backfill dry-run, index strategy review, production rollout of pilot.
  • Week 3+: one model per sprint, prioritized by business visibility (invoices/orders first — those are the ones stakeholders ask about), with sequential reserved for low-to-moderate write-volume tables until the locking question is answered.

Operational Impact

Maintenance

  • We inherit a dependency maintained by one person with no visible commercial backing. Assume we will fork at least once. Budget: pin the minor version, review the changelog quarterly, and keep the adapter thin so a fork only touches one class.
  • The counter table is now our production data. It needs backups, monitoring, and a documented reconciliation procedure (referenceable:validate --fix helps but does not verify that the sequence matches the max existing reference — that check should be manual and periodic).

Support

  • No SLA, no vendor, issues-only support. Internal ownership must be explicit: one named engineer accountable for the dependency, or it silently rots.
  • Documentation is good enough to onboard without help, but is not authoritative in the corners (stale namespace, ambiguous TTL comment). Treat the README as a starting point and the source as truth.

Scaling

  • random and template-with-{RANDOM} strategies scale horizontally with no coordination — preferred default.
  • sequential is a single hot row per counter scope. At high insert rates (thousands/sec) expect contention and retry storms; at hundreds/sec it is fine. If reset_frequency is daily/monthly, also plan for a midnight boundary — a burst of writes at period rollover hits an uncontended-but-cold counter path that is worth load-testing.
  • cache_config on reduces per-request config resolution cost; ensure it is enabled in production and that config changes are followed by a cache clear (a stale TTL is a classic "why didn't my format change" incident).
  • Batch size of 100 in config is conservative; for backfills of millions of rows, drive the Artisan command with --batch=500 and run off-peak.

Failure modes

  • Collision exhaustion — retry strategy with max_retries = 100 on a short random reference is a silent saturation risk. Enforce a minimum entropy floor (length ≥ 6 with the excluded-character set) and monitor insert failures.
  • Duplicates from a missing DB constraint — if we rely on application-level uniqueness only, concurrent writes can produce duplicates that surface months later in customer-facing documents. Mitigation: always add the unique index ourselves.
  • Counter drift — restored backups, manual DB edits, or a failed transaction after increment produce gaps or, worse, reuse. Gaps are usually fine; reuse is a compliance incident. Add an invariant check.
  • Regeneration blast radius — a regenerate --all run breaks every externally distributed reference. Mitigate by not exposing the command in runbooks, and by restricting it to pre-go-live records.
  • Tenant leakage — misconfigured tenant_column or scope downgraded to model means two tenants can hold the same reference, and cross-tenant lookup by reference silently returns the wrong record. This is the highest-severity failure mode and deserves an integration test.
  • Silent trait no-op — a model using the trait without a reference column, or with the column in $guarded, fails quietly at the wrong moment. Assert on reference presence in model factories/tests.

Ramp-up

  • Genuinely low: a Laravel developer is productive in under a day. The learning that matters is not the API but the two policy decisions — which strategy per table, and what uniqueness scope — plus the transaction/lifecycle semantics. That warrants a short internal design note rather than training.
  • Recommend a single reference-format registry (a table in the internal wiki mapping model → strategy → format → scope) so the org's numbering scheme stays legible to support, finance, and audit without reading model classes.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator