glorand/laravel-model-settings
Add per-model settings to Laravel Eloquent with an easy API to get/set/check/remove values. Choose storage via JSON field, separate settings table, or Redis. Supports defaults, validation, and persistence for user or entity preferences.
Installation:
composer require glorand/laravel-model-settings
Publish the config (optional):
php artisan vendor:publish --provider="Glorand\LaravelModelSettings\ServiceProvider" --tag="config"
First Use Case:
Define a settings model (e.g., UserSettings):
use Glorand\LaravelModelSettings\Traits\HasSettings;
class User extends Authenticatable
{
use HasSettings;
}
Create a migration for settings (e.g., user_settings):
php artisan make:migration create_user_settings_table
Define a settings schema (e.g., app/Models/UserSettings.php):
namespace App\Models;
use Glorand\LaravelModelSettings\Contracts\SettingsSchema;
class UserSettings implements SettingsSchema
{
public function schema(): array
{
return [
'theme' => 'light',
'notifications' => true,
'language' => 'en',
];
}
}
First Interaction:
// Set settings for a user
$user = User::find(1);
$user->settings()->set([
'theme' => 'dark',
'language' => 'es',
]);
// Get settings
$theme = $user->settings->theme; // 'dark'
Dynamic Settings Management:
Use settings() to access a fluent interface for nested or complex settings:
$user->settings()->set('preferences.email_notifications', true);
$user->settings()->increment('preferences.unread_messages');
Default Values & Fallbacks: Leverage the schema to enforce defaults:
class UserSettings implements SettingsSchema
{
public function schema(): array
{
return [
'privacy' => [
'share_location' => false,
'share_contacts' => false,
],
];
}
}
Access with:
$user->settings->privacy->share_location; // false (default)
Validation & Sanitization: Extend the schema to include validation rules:
class UserSettings implements SettingsSchema
{
public function schema(): array
{
return [
'account' => [
'max_upload_size' => [
'value' => 10,
'rules' => ['integer', 'min:1', 'max:100'],
],
],
];
}
}
Validate before saving:
$user->settings()->validate();
Caching & Performance: Enable caching for frequently accessed settings:
// In config/model-settings.php
'cache' => [
'enabled' => true,
'driver' => 'redis',
'prefix' => 'settings_',
],
Clear cache manually when needed:
$user->settings()->clearCache();
Multi-Tenant Support:
Use the tenant option to scope settings by tenant:
$user->settings(['tenant' => 'acme'])->set('theme', 'dark');
settings.saved or settings.updated events:
event(new SettingsSaved($user, $oldSettings, $newSettings));
toArray() or toJson():
return response()->json($user->settings->toArray());
Nova::resources([
\App\Nova\UserSettingsResource::class,
]);
Schema Mismatches:
// In a migration
Schema::table('user_settings', function (Blueprint $table) {
$table->json('settings')->nullable()->change();
});
schemaVersion in the settings table to track changes.Caching Conflicts:
clearCache() after manual updates or use touch():
$user->settings()->set('theme', 'dark')->touch();
Nested Array Overwrites:
set() overwrites entire nested arrays instead of merging.merge() for nested updates:
$user->settings()->merge('preferences', ['theme' => 'dark']);
Mass Assignment Risks:
fillable:
class UserSettings implements SettingsSchema
{
protected $fillable = ['theme', 'language'];
public function schema(): array { ... }
}
$user->settings()->getRaw(); // Returns the full JSON/array
// In config/model-settings.php
'debug' => env('APP_DEBUG', false),
json_encode() checks:
if (json_encode($value) === false) {
throw new \InvalidArgumentException('Value must be JSON-serializable');
}
Custom Storage: Override the default storage (e.g., database) by binding a custom repository:
$this->app->bind(
\Glorand\LaravelModelSettings\Contracts\SettingsRepository::class,
\App\Repositories\CustomSettingsRepository::class
);
Custom Serialization:
Extend the Settings model to handle custom types:
use Glorand\LaravelModelSettings\Models\Settings;
class CustomSettings extends Settings
{
protected $casts = [
'color_palette' => 'array',
'last_login' => 'datetime',
];
}
Policy Integration: Attach policies to settings models:
class UserSettingsPolicy
{
public function update(User $user, User $settingsOwner)
{
return $user->id === $settingsOwner->id;
}
}
Register in AuthServiceProvider:
$this->policy(Settings::class, UserSettingsPolicy::class);
Observer Hooks:
Extend the SettingsObserver for custom logic:
use Glorand\LaravelModelSettings\Observers\SettingsObserver;
class CustomSettingsObserver extends SettingsObserver
{
public function saving($settings)
{
// Custom logic before save
}
}
Bind in ServiceProvider:
$this->app->singleton(SettingsObserver::class, CustomSettingsObserver::class);
database. For other drivers (e.g., cache, redis), ensure the driver is configured in config/model-settings.php:
'driver' => env('SETTINGS_DRIVER', 'database'),
// In config/model-settings.php
'table' => 'custom_settings',
array columns instead:
$table->json('settings')->nullable(); // Default
$table->text('settings')->nullable(); // Alternative for large data
How can I help you explore Laravel packages today?