dmn013/eloquence
Eloquence extends Laravel's Eloquent ORM with a suite of opt-in traits: fuzzy searchable models, sortable and sluggable records, soft deletes, cacheable queries, mappable attributes, and more. Drop-in behaviors that keep your models clean and your code expressive.
What the package is. A grab-bag of opt-in Eloquent traits (Sluggable, Sortable, Searchable, Mappable, Metable, Cacheable, Recursive/tree helpers, SoftDeletes extensions) delivered as a single Composer dependency. It is not a framework layer — each model opts in per-trait, which is the right architectural shape for an ORM extension. The value proposition is real: it consolidates 6–8 small concerns most Laravel apps hand-roll badly.
Architecture fit. Good on paper. Trait-based mixins into Illuminate\Database\Eloquent\Model are idiomatic Laravel and require no service container wiring, no config publishing in most cases, and no migration on the host application beyond the tables Metable needs. Two design decisions are architectural liabilities, however: Sortable reads from the global HTTP Request, coupling the persistence layer to the request lifecycle (breaks in queue workers, console commands, and tests unless callers explicitly inject sort state), and Mappable overrides __get/__set to expose virtual attributes, which sits directly on Eloquent's most-refactored internal surface.
Integration feasibility. Low for a Laravel 5.x–6.x codebase: composer require, add traits, done. Low-to-moderate for Laravel 8+; the last tagged release is September 2019, which aligns with the Laravel 6 cycle, and there is no evidence of maintenance since. Expect work in: PHP 8 signature/return-type mismatches, deprecated $dates/$casts interactions, event-dispatcher boot differences, and Mappable's magic-method overrides colliding with newer getAttribute/setAttribute internals.
Technical risk (ranked).
| Risk | Severity | Notes |
|---|---|---|
| Unmaintained upstream (last release 2019) | High | No Laravel 9/10/11 compatibility work, no security response path |
| Package provenance mismatch | Medium | Composer name is dmn013/eloquence while the repo lives under jarektkaczyk — a community fork, not the canonical publisher. Treat as third-party code requiring vetting and vendoring. |
| Trait collision / boot order | Medium | Multiple traits hook saving/saved/creating; SoftDeletesExtended layers on core events. Silent double-fire is plausible and hard to trace. |
Request coupling in Sortable |
Medium | Non-HTTP contexts produce wrong or default ordering with no error |
Concurrency in Sluggable |
Medium | Uniqueness is enforced by a read-then-write loop; concurrent inserts race into the DB unique constraint |
Metable N+1 exposure |
Medium | Polymorphic meta relation requires disciplined eager loading |
| Zero tracked dependents | Low/Informational | For a ~1.1k-star package this is a weak ecosystem signal — either a registry gap or genuinely narrow adoption; either way it means no crowd-sourced compatibility fixes |
Key questions for the team.
Sluggable and Sortable; Metable and Mappable are the risky ones and are the easiest to replace with JSON columns and explicit accessors.Sortable's request coupling acceptable, or are we wrapping it?Stack fit. Green light only for Laravel ≤7 / PHP ≤7.4 legacy services. For Laravel 9+ the honest recommendation is: do not add this as an unvetted dependency. Either fork it in-house, or substitute maintained equivalents per concern (dedicated slugging package, spatie/laravel-query-builder for sorting/filtering, native JSON columns for metadata).
Migration path.
^2.0 with an explicit supported-version matrix.Compatibility work items (fork scenario). PHP 8 type-safety pass; Mappable re-implementation against getAttribute/setAttribute or, preferably, deprecation in favour of accessors and Attribute casts; decouple Sortable from the global request behind an injected sort-state object; verify Metable migration schema against our DB engine and add a composite index on (model_type, model_id); confirm SoftDeletesExtended does not double-dispatch against core's restoring/restored.
Sequencing.
Mappable and Sortable first; leave Sluggable semantics untouched to avoid a data migration.Sluggable → Searchable → Sortable → Metable → Mappable. Never cut over all traits in one release.Metable and Sluggable, run a reconciliation job comparing generated values against expected output on a production snapshot before enabling writes.Maintenance. The dominant cost is ownership transfer. Upstream is dormant; every Laravel upgrade becomes our problem, and each one has a nonzero chance of surfacing a Mappable-shaped break that only manifests at runtime. Budget a recurring maintenance line item rather than a one-off integration cost. If we vendor without a fork, pin hard and accept that the package becomes a permanent upgrade blocker — which, in practice, is how packages like this quietly cap a platform's Laravel version.
Support. No upstream security process, no CVE response, no maintainer to escalate to. Internal on-call inherits every failure mode. The provenance mismatch (composer namespace ≠ repo owner) means we should verify the published artifact matches the source we reviewed before trusting it in a build pipeline; treat the first install as a supply-chain review, not a composer require.
Scaling.
Searchable generates LIKE '%term%' predicates — full scans, no index use. Fine to a few hundred thousand rows, unacceptable beyond that. If search is load-bearing, this trait is the wrong tool and should be replaced with a proper index (Scout/Meilisearch/Postgres FTS).Recursive/tree helpers issue per-level queries; deep hierarchies degrade linearly and can fan out badly under load.Metable is an EAV pattern: it scales in write flexibility, not in read performance. Plan eager loading as a hard rule and add a style/lint check for lazy access.Cacheable shifts the problem to invalidation. Without a disciplined key strategy, cache staleness becomes the top user-visible defect class.Failure modes to instrument for.
Mappable attribute masking a real column. Symptom: correct-looking code returning wrong data. Mitigate with integration tests that assert column values directly via the query builder.Sortable — background jobs silently receiving default ordering. Mitigate by wrapping sort state explicitly and asserting ordering in job tests.Metable sync — multi-row meta writes without a transaction leaving inconsistent state. Mitigate by wrapping sync calls in transactions.Ramp-up. Individual traits are learnable in an afternoon; the package ships readable code and examples. The real ramp-up cost is debugging cost — magic-method traits produce stack traces that point at framework internals rather than at the package, so engineers unfamiliar with the traits lose time. Onboarding should include a short internal note: which traits we use, which we've forked, and where the escape hatches are.
Verdict. High-utility, low-health dependency. Justified for existing Laravel ≤7 applications where the traits are already in use and the alternative is a disruptive rewrite. Not justified as a new dependency on a modern Laravel version without an explicit fork-and-own decision and a named maintainer. The score reflects opportunity, not readiness — the opportunity is real, but capturing it requires us to supply the maintenance the upstream no longer does.
How can I help you explore Laravel packages today?