sitesource/laravel-polymorphic-settings
Laravel Polymorphic Settings lets you attach flexible key-value settings to any Eloquent model through a polymorphic relationship, with a simple API for storing, retrieving, updating, and managing configuration-like data per record.
Architecture fit. The package models settings as a polymorphic key-value relation (model_type/model_id → key → value), which is the canonical Laravel shape for "per-entity configuration without schema churn." It slots into Eloquent via a trait/interface on the owning model, so it composes with existing domain models rather than introducing a parallel persistence layer. For teams already storing per-user or per-tenant preferences in JSON columns, this is a direct, normalized substitute. Encryption is opt-in per key, which is the right default posture: sensitive values (API tokens, webhook secrets) get encrypted, non-sensitive values stay queryable.
Integration feasibility. Low-to-moderate. There is no external service, no queue dependency, and no front-end contract. Integration is a migration, a trait, and optionally a cache configuration change. The existence of a first-party-adjacent Filament adapter (laravel-polymorphic-settings-filament v0.1.0) is a positive signal that the API surface is usable by admin tooling, but it also means the only observed production consumer is a sibling project from the same author — not independent validation.
Technical risk. The dominant risk is maturity, not design. The package is at v0.1.3, has 0 stars and 0 dependents, and its most recent release is a bug-fix release for two correctness defects in the cache layer:
put() did not invalidate, serving stale data indefinitely (TTL-bounded).forget() was a no-op for cache invalidation when the underlying row was already absent, leaving orphaned cache entries with no public cleanup path.Both are now fixed (129 tests, 217 assertions), and the failure modes are the dangerous kind — silent staleness rather than exceptions. The fact that these were found by a downstream integration rather than by the package's own tests is the meaningful signal: the cache layer's invariants were underspecified at v0.1.2, and there is no guarantee a v0.1.4 does not reveal a third. The dotted-key contract is also subtle by design: put('a.b', x) stores literally, while get('a.b') falls back to root traversal, and v0.1.3's fix trades a cache hit for a DB round-trip on every literal dotted read. That is a correct trade, but it means "transparent caching" is not uniformly transparent.
Key questions for the maintainer / spike.
(model_type, model_id, key), and is the uniqueness constraint enforced at the DB level?APP_KEY?Stack fit. Best fit is a conventional Laravel monolith or modular monolith on Laravel 10/11+, using Eloquent, with Redis or a shared cache store. It is a poor fit if settings must be queried in aggregate (WHERE setting = x), joined into reports, or audited with per-change history — the package is a key-value accessor, not a settings domain model. It is also a poor fit where settings are owned by a service outside the Laravel app.
Migration path. Treat this as an additive, reversible change:
Compatibility. Pin exact versions (0.1.3), not ^0.1. Pre-1.0 semver permits breaking changes in patch releases, and the v0.1.2 → v0.1.3 change alters cache behavior for dotted keys. If the team cannot upgrade promptly, the documented escape hatch is POLYMORPHIC_SETTINGS_CACHE_ENABLED=false — acceptable for settings, which are typically low-QPS, but it must be a conscious, monitored setting rather than a silent fallback. Confirm the Filament adapter version is pinned against the same core version.
Sequencing. (a) One-week spike: table, trait on a scratch model, cache on/off comparison, concurrent-write test. (b) Write an ADR recording the decision and the pinning policy. (c) Pilot in a non-critical domain with cache enabled. (d) Observe for one release cycle. (e) Expand to additional models. Do not sequence encryption last; do not sequence cache-enable before the pilot, because the cache layer is the part with the observed defect history.
Maintenance. Small code surface, MIT license, no external runtime. The real maintenance burden is governance: a 0-star, 0-dependent package with a single author is a bus-factor-1 dependency. Mitigate by vendoring the source into the repo or maintaining a private fork with the ability to patch — at this size that is cheap insurance, and it converts an availability risk into a routine merge.
Support. No commercial support, no SLA. Support is GitHub issues plus reading the changelog. Budget for the team owning the integration to be the de facto maintainer. The Filament adapter is effectively the reference consumer; watch its issue tracker as an early-warning system for core defects.
Scaling. One row per key per model. Read cost is one query per uncached key, and dotted-literal reads are deliberately uncached in v0.1.3 — so a screen rendering 30 settings should be collapsed into a single root read or eager load, not 30 key lookups. Write cost includes cache invalidation. The composite index on (model_type, model_id, key) is mandatory; without it, polymorphic lookups degrade as the table grows. Cache store choice matters: a per-node file cache will produce inconsistent reads across app servers, so use a shared store.
Failure modes.
deleting hook.Ramp-up. Low for a Laravel-fluent engineer: half a day to read the source and tests, one to two days to integrate the first model. The TPM cost is front-loaded — the ADR, the version-pinning policy, the encryption/key-rotation decision, and the "all writes through the API" rule. Those four artifacts are what convert a plausible v0.1 package into something the team can operate. Given the maturity signals (0 stars, 0 dependents, defects found only by a sibling integration), the recommendation is pilot, don't standardize: adopt behind a pin and a fork-ready posture, and revisit for broader use once there is evidence of independent production consumers or a 1.0 release.
How can I help you explore Laravel packages today?