Product Decisions This Supports
- Build vs. adopt on an extension seam. This package answers one narrow architectural question: when a Laravel package ships Eloquent models, how does the host application substitute its own subclass without forking vendor code? For a PM, that's decision input for "do we build an override mechanism or adopt a pattern?" — and the honest answer here is reference design, not dependency. The code surface is small and MIT-licensed, which makes "copy the pattern" a first-class option rather than a compromise.
- Plugin, partner, and SDK architecture. If the roadmap includes third-party add-ons, white-label deployments, or an internal SDK consumed by other product teams, this repo is a concrete data point on how to shape the seam where consumers swap domain models. A uniform, config/registry-driven override point is cleaner than scattering
config('foo.model') lookups across the codebase and hoping every package author agrees.
- White-label and multi-tenant customization policy. Whether customers may replace core entities (custom
Order, User, Invoice subclasses) or are constrained to config-driven behavior has real support, upgrade, and compatibility implications. This package sits firmly on the "override the class" end of the spectrum and makes the cost of that choice legible: each override is a surface you now own against every vendor upgrade, and relationship graphs get half-overridden unless you're disciplined.
- Support-burden modeling. For any team publishing packages internally, adopting this means owning the override contract in docs, upgrade notes, and contract tests. That's a scoping input for the SDK team's roadmap — a named owner, a CI assertion that every registered override resolves, and an upgrade matrix — not just an engineering ticket.
- Closing out an evaluation cheaply. Archived, 93 stars, zero dependents, last release May 2024, Laravel 11 only. That profile is decision input in itself and supports a "document the pattern, retire the investigation" conclusion without further research spend.
- Risk posture on silent failure. The dominant failure mode is resolving to the base model with no error — subtly wrong behavior discovered by users. That's a product-risk framing that belongs in any decision about how much test coverage an extension seam deserves, and it argues for treating the seam contract test as a first-class artifact rather than nice-to-have.
When to Consider This Package
Consider it when:
- You are the author of a Laravel package that ships Eloquent models and need a documented convention for consumers to substitute their own classes — and you want a minimal reference implementation of that convention to study or copy.
- You need identical override behavior across multiple packages and want one resolution mechanism rather than per-package config strings.
- You are prototyping an extension or marketplace system and want a reference to evaluate before designing your own.
- You are willing to vendor or fork the source — the license permits it, the surface is small, and you'll assign a named owner plus a contract test in CI.
Look elsewhere when:
- You need a production dependency in the model-instantiation path. Archived means no security patch channel, no Laravel-major compatibility work (Laravel 12 unverified), and no maintainer response. That's a hard blocker for anything customer-facing.
- Your need is really data customization (extra fields, tenant-specific columns, configurable behavior) rather than class substitution. Config-driven models or schema extension is the cheaper, more supportable answer; reach for a class override only when behavior genuinely differs.
- The vendor package already exposes a model class in its config or accepts one as a parameter — use that and skip this entirely. In practice the number of models you actually must substitute is 0–1.
- Nobody will own the fork, the CI contract test, and the upgrade matrix. An archived dependency with no CVE channel has exactly one safety net, and if it's unstaffed, don't install it.
- You expect heavy Octane/long-lived-worker usage, IDE-driven developer ergonomics, or strict static analysis. Runtime class substitution degrades all three: Octane persistence needs explicit verification, go-to-definition goes stale, and PHPStan/Larastan will report false positives that need stubs (don't disable the rule).
How to Pitch It (Stakeholders)
To executives: This is a small, MIT-licensed Laravel library that solves one problem — letting an application replace a vendor package's database model with its own subclass without forking vendor code. It's archived, unmaintained, and has zero known dependents, so we should not take it as a production dependency. What we should take is the pattern: it's a cheap reference for how to design extension points if we build a plugin, partner, or white-label offering. The recommendation is to document the pattern, spend no further research budget, and route any real need into our own thin implementation behind a single wrapper class, with a named owner and one CI test that proves every override actually resolves.
To engineering: The mechanism is a trait the vendor model opts into plus a container-aware resolution step, so $blog->posts()->first() returns the app's subclass without any call-site changes. The value is that vendor code stays pristine and upgrades stay safe. The cost is a silent-failure surface: if registration is missed, config is cached incorrectly, or the model resolves before the override is registered, you get the base class with no error. Also watch factories that new the base class directly, policies registered against the base class name, get_class() === ... comparisons, and relationship methods that still point at the vendor's User. The migration path is deliberate: wrap the registration in our own ModelOverrides registry, add a contract test asserting each base resolves to its override under config:cache, and keep the reimplementation — roughly a hundred lines — a one-file change.
To the package/SDK team: Treat the repo as specification. It codifies what a uniform override seam looks like and why per-package config strings don't scale across multiple packages. If we publish packages internally, adopting this convention means we own the override contract in documentation and upgrade notes, and we should assume each override is a surface we maintain against vendor changes — so override two models, not eight.