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

Eloquent Preferences Laravel Package

klaude/eloquent-preferences

Add flexible key-value preferences to any Eloquent model with klaude/eloquent-preferences. Store per-model settings polymorphically, read and write them through a simple API, and keep configuration data organized without extra tables or boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

klaude/eloquent-preferences adds per-model key/value preferences to Eloquent via a HasPreferences trait. As of v0.6.0 the package supports PHP 8.1 and Laravel 9, so the first step after composer require klaude/eloquent-preferences is to confirm your app's PHP/Laravel versions fall inside that matrix and that your composer.json constraint is bumped to ^0.6 if you were pinned to ^0.5.

Minimal setup:

  1. Publish/run the package migration (it creates the preferences table holding a morph relation, a key, and a serialized value).
  2. Add the trait to any model that needs settings:
    use Klaude\EloquentPreferences\HasPreferences;
    
  3. Start with the simplest use case: storing a UI preference on your User model.
    $user->setPreference('timezone', 'Europe/Berlin');
    $user->getPreference('timezone'); // 'Europe/Berlin'
    

Where to look first: the trait itself (HasPreferences) for the available methods and the default-value mechanism, then the migration to confirm table/column names before you write queries against it. The release notes for v0.6.0 are compatibility-only (PHP 8.1 + Laravel 9), so there is no new API to learn if you are upgrading from 0.5.x.

Implementation Patterns

  • Trait on the owning model, not a separate service. Preferences belong on User, Team, Project, etc. Keep the trait on the model whose identity scopes the preference; the polymorphic relation handles the rest.
  • Defaults via the model, not the database. Define sensible defaults on the model and let getPreference() fall back to them so callers never have to null-check. Store only values that deviate from the default; this keeps the preferences table small and makes adding new defaults a non-migration change.
  • Group related keys with a naming convention. Use dotted keys (notifications.email, notifications.push, dashboard.layout) so you can reason about them as a namespace and later add bulk read/write helpers around the prefix.
  • Wrap reads in a small accessor on your model. Instead of scattering getPreference('x') across controllers and Blade, expose typed methods ($user->wantsEmailNotifications(): bool). This gives you one place to change storage later and keeps casts consistent.
  • Pair with a settings form request. Validate incoming preference payloads in a FormRequest, then loop and setPreference() inside a transaction when several keys change together — partial writes on a settings page are a common source of user confusion.
  • Eager-load for list screens. If an admin table renders a preference per row, load the preferences relation up front to avoid an N+1; the trait's accessor will otherwise hit the database per model.
  • Integration with policies/gates. Preferences are a natural fit for notification opt-outs and per-tenant feature flags that are user-scoped rather than global. Read them inside the policy, not the controller, so both web and API paths get identical behavior.

Gotchas and Tips

  • This release is compatibility-only. v0.6.0 fixes PHP 8.1 compatibility and adds Laravel 9 support — no new features, no deprecations, no API changes. Treat the upgrade as low-risk, but do run your test suite: a PHP 8.1 fix can change behavior on code paths that previously errored or silently returned null.
  • Pin the constraint deliberately. If you are on Laravel 8, stay on the version that supports it; v0.6.0's matrix targets PHP 8.1/Laravel 9. Check composer why-not if the upgrade refuses to resolve.
  • Value serialization surprises. Preference values are stored serialized, so "1" and 1 can round-trip differently and booleans may come back as 1/0. Cast explicitly at the accessor boundary rather than trusting the raw return type.
  • Cache invalidation. If you cache rendered settings pages, remember to bust the cache in the same place you call setPreference(). There is no model event wired up for you by default.
  • Cleanup on delete. Confirm the migration's foreign key uses cascade deletes for the morph relation; otherwise orphaned preference rows accumulate when models are removed, and getPreference() on a recycled ID can appear to "remember" old values.
  • Debugging missing values. When a preference "disappears", check the morph type string first — a renamed or namespaced model class will no longer match existing rows and every read will fall through to your default.
  • Extension point. Rather than editing the package, subclass or wrap the trait in your own base model so you can layer caching, casting, and typed accessors without forking; that keeps future compatibility bumps (like this one) to a one-line composer update.
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.
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
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle