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.
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:
use Klaude\EloquentPreferences\HasPreferences;
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.
User, Team, Project, etc. Keep the trait on the model whose identity scopes the preference; the polymorphic relation handles the rest.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.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.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.setPreference() inside a transaction when several keys change together — partial writes on a settings page are a common source of user confusion.preferences relation up front to avoid an N+1; the trait's accessor will otherwise hit the database per model.null.composer why-not if the upgrade refuses to resolve."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.setPreference(). There is no model event wired up for you by default.getPreference() on a recycled ID can appear to "remember" old values.composer update.How can I help you explore Laravel packages today?