metalinked / laravel-settings-kit
A comprehensive Laravel package for managing global and user-specific settings, with role-based permissions, multi-language support, auto-creation, and a full REST API for headless and modern applications.
Requires
- php: ^8.1|^8.2|^8.3
- illuminate/support: ^9.0|^10.0|^11.0|^12.0
- laravel/framework: ^9.0|^10.0|^11.0|^12.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- mockery/mockery: ^1.4.4
- nunomaduro/collision: ^6.0|^7.0|^8.0
- orchestra/testbench: ^7.0|^8.0|^9.0|^10.0
- phpstan/phpstan: ^1.0
- phpunit/phpunit: ^9.5|^10.0
README
A comprehensive Laravel package for managing global and user-specific settings with role-based permissions, multi-language support, auto-creation capabilities, and a complete REST API for headless applications.
Table of Contents
- ๐ Features
- ๐ Requirements
- โ๏ธ Installation
- ๐ ๏ธ Creating Settings
- โก Quick Start
- ๐ Adding Translations
- ๐ REST API
- ๐จ Multilingual Interface Examples
- ๐ API Reference
- ๐ Global Overrides vs Default Values
- ๐ง Data Types
- ๐ก Advanced Examples
- ๐ง Troubleshooting
- ๐งช Testing
- ๐ค Contributing
- ๐ Security
- ๐ License
๐ Features
- ๐ง Global and User-specific Settings - Manage both application-wide and individual user preferences
- ๐ฅ Role-based Permissions - Control which settings are visible/editable by user roles
- ๐ Multi-language Support - Full multilingual support with automatic fallbacks and translation management
- ๐ Multiple Data Types - Support for string, boolean, integer, JSON, and select options
- โก Cache Support - Built-in caching to reduce database queries
- ๐จ Clean API - Simple and intuitive facade interface with auto-creation capabilities
- ๐ Auto-Creation - Automatically create settings on-the-fly with type detection
- ๐ REST API - Complete API for headless applications and JavaScript frameworks
- ๐ก๏ธ Flexible Authentication - Support for token, Sanctum, and Passport authentication
- ๐พ Database Agnostic - Works with any Laravel-supported database
๐ Requirements
- PHP 8.1 or higher
- Laravel 10.0 or higher
โ๏ธ Installation
Install the package via Composer:
composer require metalinked/laravel-settings-kit
Publish and run the migrations:
php artisan vendor:publish --provider="Metalinked\LaravelSettingsKit\SettingsKitServiceProvider" --tag="migrations" php artisan migrate
Optionally, publish the config file:
php artisan vendor:publish --provider="Metalinked\LaravelSettingsKit\SettingsKitServiceProvider" --tag="config"
๐ ๏ธ Creating Settings
The package supports two types of settings:
- ๐ Global Unique Settings: System-wide configurations that apply to everyone (e.g.,
maintenance_mode
,site_name
) - ๐ค User Customizable Settings: Settings with defaults that users can personalize (e.g.,
theme
,notifications_enabled
)
Using a Seeder (Recommended)
Create a seeder to define your settings:
// database/seeders/SettingsSeeder.php use Metalinked\LaravelSettingsKit\Models\Preference; public function run(): void { $settings = [ // Global unique setting - when changed, modifies the default value directly [ 'key' => 'maintenance_mode', 'type' => 'boolean', 'default_value' => '0', 'category' => 'system', 'is_user_customizable' => false, // Global unique ], [ 'key' => 'site_name', 'type' => 'string', 'default_value' => 'My Application', 'category' => 'general', 'is_user_customizable' => false, // Global unique ], // User customizable settings - users can override the default [ 'key' => 'theme', 'type' => 'select', 'default_value' => 'light', 'category' => 'appearance', 'options' => ['light', 'dark'], 'is_user_customizable' => true, // Users can customize ], [ 'key' => 'notifications_enabled', 'type' => 'boolean', 'default_value' => '1', 'category' => 'preferences', 'is_user_customizable' => true, // Users can customize ], [ 'key' => 'max_upload_size', 'type' => 'integer', 'default_value' => '2048', 'category' => 'files', 'is_user_customizable' => false, // Global unique ] ]; foreach ($settings as $setting) { Preference::firstOrCreate(['key' => $setting['key']], $setting); } }
โก Quick Start
Understanding Setting Types
๐ Global Unique Settings:
// When set without user ID, modifies the default value directly Settings::set('maintenance_mode', true); // All users see maintenance mode Settings::set('site_name', 'New Name'); // Changes the site name for everyone // These settings cannot be personalized by users
๐ค User Customizable Settings:
// Default value that users inherit Settings::get('theme'); // Returns 'light' (default) Settings::get('theme', 123); // Returns 'light' (user hasn't customized yet) // Change global default (affects all users who haven't customized) Settings::set('theme', 'dark'); // Modifies default_value to 'dark' Settings::get('theme'); // Returns 'dark' (new default) Settings::get('theme', 456); // Returns 'dark' (new default for all users) // User personalizes the setting (only then is UserPreference created) Settings::set('theme', 'custom', 123); // Creates UserPreference for user 123 Settings::get('theme', 123); // Returns 'custom' (user's preference) Settings::get('theme', 456); // Returns 'dark' (still global default)
Basic Usage
use Metalinked\LaravelSettingsKit\Facades\Settings; // Get a global setting (returns null if not found) $value = Settings::get('allow_comments'); // Get a user-specific setting $value = Settings::get('email_notifications', $userId); // Set a global setting (throws exception if preference doesn't exist) Settings::set('allow_comments', true); // Set a user-specific setting Settings::set('email_notifications', false, $userId); // Set a setting with auto-creation (creates preference if it doesn't exist) Settings::setWithAutoCreate('new_feature_enabled', true); // Check if a setting is enabled (boolean) if (Settings::isEnabled('maintenance_mode')) { // Application is in maintenance mode } // Get translated label and description $label = Settings::label('allow_comments'); $description = Settings::description('allow_comments');
Creating Settings with Auto-Detection
// Automatically create settings with type detection Settings::setWithAutoCreate('maintenance_mode', false); // Creates boolean preference Settings::setWithAutoCreate('items_per_page', 20); // Creates integer preference Settings::setWithAutoCreate('theme_config', ['dark' => true]); // Creates JSON preference // Check if a setting exists before using if (Settings::has('feature_enabled')) { $value = Settings::get('feature_enabled'); } // Create setting only if it doesn't exist Settings::createIfNotExists('new_feature', [ 'type' => 'boolean', 'default_value' => '0', 'category' => 'features' ]);
๐ Adding Translations
The package includes a powerful multilingual system that allows you to provide labels and descriptions for your settings in multiple languages:
use Metalinked\LaravelSettingsKit\Models\PreferenceContent; $preference = Preference::where('key', 'allow_comments')->first(); // Add English translation PreferenceContent::create([ 'preference_id' => $preference->id, 'locale' => 'en', 'label' => 'Allow Comments', 'description' => 'Enable or disable comments on posts', ]); // Add Catalan translation PreferenceContent::create([ 'preference_id' => $preference->id, 'locale' => 'ca', 'label' => 'Permetre Comentaris', 'description' => 'Activa o desactiva els comentaris a les publicacions', ]);
Creating Settings with Translations
// Create setting with multiple translations at once Settings::createWithTranslations('newsletter_enabled', [ 'type' => 'boolean', 'default_value' => '1', 'category' => 'marketing' ], [ 'en' => [ 'label' => 'Newsletter Subscription', 'description' => 'Enable newsletter signup form' ], 'ca' => [ 'label' => 'Subscripciรณ al Butlletรญ', 'description' => 'Activa el formulari de subscripciรณ al butlletรญ' ], 'es' => [ 'label' => 'Suscripciรณn al Boletรญn', 'description' => 'Habilita el formulario de suscripciรณn al boletรญn' ] ]); // Get all settings with translations for a specific locale $settings = Settings::allWithTranslations('ca'); // This returns an array like: [ 'maintenance_mode' => [ 'value' => false, 'type' => 'boolean', 'category' => 'system', 'label' => 'Mode Manteniment', 'description' => 'Activar el mode de manteniment...', 'key' => 'maintenance_mode' ] ]
๐ REST API
The package provides a complete REST API for managing settings, perfect for headless Laravel applications, mobile apps, or frontend JavaScript frameworks.
API Configuration
The API supports both development and production environments with different setup requirements.
๐ ๏ธ Development Setup (Quick Start)
For local development and testing, you can bypass authentication entirely:
# Enable API SETTINGS_KIT_API_ENABLED=true # Bypass authentication in local/testing environments SETTINGS_KIT_API_DISABLE_AUTH_DEV=true # Auto-create missing settings (recommended for development) SETTINGS_KIT_API_AUTO_CREATE=true # Optional: Custom API prefix SETTINGS_KIT_API_PREFIX=api/settings-kit
With this setup, you can immediately use the API without any authentication:
# Works immediately in development
curl http://your-local-app.test/api/settings-kit/global/site_name
๐ Production Setup
For production environments, configure proper authentication:
Token Authentication (Simple):
# Enable API SETTINGS_KIT_API_ENABLED=true # Disable development bypass (or remove the line) SETTINGS_KIT_API_DISABLE_AUTH_DEV=false # Authentication mode SETTINGS_KIT_API_AUTH=token # Secure API token SETTINGS_KIT_API_TOKEN=your-secure-random-token-here # Auto-create settings (optional) SETTINGS_KIT_API_AUTO_CREATE=false
Sanctum Authentication (User-based):
SETTINGS_KIT_API_ENABLED=true SETTINGS_KIT_API_DISABLE_AUTH_DEV=false SETTINGS_KIT_API_AUTH=sanctum
Passport Authentication (OAuth2):
SETTINGS_KIT_API_ENABLED=true SETTINGS_KIT_API_DISABLE_AUTH_DEV=false SETTINGS_KIT_API_AUTH=passport
API Authentication
The API supports multiple authentication methods:
Token Authentication (Simple):
curl -H "Authorization: Bearer your-secure-random-token-here" \
http://your-app.com/api/settings-kit
Sanctum Authentication (User-based):
SETTINGS_KIT_API_AUTH=sanctum
curl -H "Authorization: Bearer user-sanctum-token" \
http://your-app.com/api/settings-kit
Passport Authentication (OAuth2):
SETTINGS_KIT_API_AUTH=passport
Auto-Creation via API
The API can automatically create missing settings when they're accessed. This is perfect for API-first applications:
Global Configuration (affects all API requests):
# Enable auto-creation for all API requests SETTINGS_KIT_API_AUTO_CREATE=true
Per-request Control:
# Create setting on-the-fly with auto_create parameter POST /api/settings-kit/new_setting { "value": "some_value", "auto_create": true }
Behavior:
- Config enabled + no parameter: Auto-creates missing settings
- Config disabled +
auto_create=true
: Auto-creates missing settings - Config disabled + no parameter: Returns 404 for missing settings
API Endpoints
Core Endpoints
- GET
/api/settings-kit
- Get all settings with optional filtering - GET
/api/settings-kit/categories
- Get available categories - POST
/api/settings-kit/preferences
- Create new preference
Global Settings (System-wide)
- GET
/api/settings-kit/global/{key}
- Get specific global setting - POST
/api/settings-kit/global/{key}
- Create/update global setting - PUT
/api/settings-kit/global/{key}
- Update global setting - DELETE
/api/settings-kit/global/{key}
- Reset global setting to default
User Settings (User-specific)
- GET
/api/settings-kit/user/{key}
- Get specific user setting - POST
/api/settings-kit/user/{key}
- Create/update user setting - PUT
/api/settings-kit/user/{key}
- Update user setting - DELETE
/api/settings-kit/user/{key}
- Reset user setting to default
Legacy Endpoints (Backwards Compatibility)
- GET
/api/settings-kit/{key}
- Get specific setting (auto-detects global/user) - POST
/api/settings-kit/{key}
- Create/update setting value - PUT
/api/settings-kit/{key}
- Update setting value - DELETE
/api/settings-kit/{key}
- Reset setting to default
Query Parameters:
locale
- Language for translations (e.g.,ca
,es
,en
)user_id
- Specify user ID (required for user endpoints)category
- Filter by categoryrole
- Filter by role
Example Usage:
# Get all settings with Catalan translations GET /api/settings-kit?locale=ca # Get specific global setting GET /api/settings-kit/global/site_name # Get user-specific setting GET /api/settings-kit/user/theme?user_id=123 # Update global setting POST /api/settings-kit/global/maintenance_mode {"value": true} # Update user setting POST /api/settings-kit/user/notifications?user_id=123 {"value": false} # Set global setting (auto-created if SETTINGS_KIT_API_AUTO_CREATE=true) POST /api/settings-kit/maintenance_mode { "value": true } # Set global setting with explicit auto-creation POST /api/settings-kit/new_feature_enabled { "value": true, "auto_create": true } # Set user-specific setting (requires is_user_customizable=true) POST /api/settings-kit/email_notifications { "value": false, "user_id": 123 }
๐ Complete API Documentation: See examples/API_USAGE.md
for detailed examples, error handling, and JavaScript integration examples.
๐จ Multilingual Interface Examples
The package includes practical examples for creating multilingual settings interfaces:
- Admin Settings Panel -
examples/admin-settings.blade.php
- User Preferences -
examples/user-settings.blade.php
- Multilingual Admin Panel -
examples/admin-multilingual-settings.blade.php
- Controller Examples -
examples/SettingsControllerExample.php
๐ API Reference
Settings Facade
get(string $key, int $userId = null)
Get a setting value. Returns user-specific value if $userId
is provided and exists, otherwise returns global default.
set(string $key, mixed $value, int $userId = null, bool $autoCreate = false)
Set a setting value:
- If
$userId
is provided: Sets user-specific value (only foris_user_customizable = true
settings) - If
$userId
is null:- For global unique settings (
is_user_customizable = false
): Modifiesdefault_value
directly - For user customizable settings (
is_user_customizable = true
): Modifiesdefault_value
directly (affects all users who haven't customized)
- For global unique settings (
- Set
$autoCreate
to true to create the preference automatically if it doesn't exist
// Global setting change (modifies default_value directly) Settings::set('maintenance_mode', true); // User-specific setting (only for customizable settings) Settings::set('theme', 'dark', $userId);
setWithAutoCreate(string $key, mixed $value, int $userId = null)
Set a setting value, creating the preference automatically if it doesn't exist.
has(string $key)
/ exists(string $key)
Check if a preference exists in the database.
isEnabled(string $key, int $userId = null)
Check if a boolean setting is enabled.
label(string $key, string $locale = null)
Get the translated label for a setting.
description(string $key, string $locale = null)
Get the translated description for a setting.
create(array $data)
Create a new preference.
createIfNotExists(string $key, array $data)
Create a preference only if it doesn't already exist.
createWithTranslations(string $key, array $preferenceData, array $translations = [])
Create a preference with translations in multiple languages.
addTranslations(string $key, array $translations)
Add or update translations for an existing preference.
forget(string $key, int $userId = null)
Reset a setting:
- For user settings: Removes the user's custom value, reverting to the global default
- For global unique settings (
is_user_customizable = false
): Not applicable - these settings don't have user-specific values - For user customizable settings (
is_user_customizable = true
): Only removes user-specific customizations
// Example: Reset user's custom theme back to global default Settings::forget('theme', $userId); // Note: Global unique settings cannot be "reset" as they modify default_value directly
๐ Global Overrides vs Default Values
The package uses a simple and efficient approach based on the setting type:
๐ Global Unique Settings (is_user_customizable = false
)
These settings modify the default value directly and apply to everyone:
// Create a global unique setting Preference::create([ 'key' => 'maintenance_mode', 'default_value' => '0', 'is_user_customizable' => false ]); Settings::set('maintenance_mode', '1'); // Modifies default_value directly Settings::get('maintenance_mode'); // Returns '1' for everyone
๐ค User Customizable Settings (is_user_customizable = true
)
These settings allow users to personalize their experience:
- Global changes: Modify the
default_value
directly - affects all users who haven't customized - User customization: Creates entries in
user_preferences
table only when needed
Practical Example
// 1. Create user customizable preference Preference::create([ 'key' => 'theme', 'default_value' => 'light', 'is_user_customizable' => true ]); // 2. Change global default (modifies default_value to 'dark') Settings::set('theme', 'dark'); // All users without custom preferences see 'dark' // 3. User personalizes (creates UserPreference entry) Settings::set('theme', 'custom', 123); // Only user 123 gets 'custom' // 4. Results: Settings::get('theme'); // 'dark' (global default) Settings::get('theme', 123); // 'custom' (user's preference) Settings::get('theme', 456); // 'dark' (global default)
Benefits of This Architecture
- โก Performance: Users read directly from
preferences
table unless they have custom values - ๏ฟฝ๏ธ Clean Data:
user_preferences
only contains actual user customizations - ๐ก Simple Logic: Global changes update the default, user changes create personal preferences
- ๐ Data Integrity: Clear separation between global and personal settings
๐ง Data Types
The package supports the following data types:
string
- Text valuesboolean
- True/false valuesinteger
- Numeric valuesjson
- JSON objects/arraysselect
- Predefined options (stored as JSON in options field)
๐ก Advanced Examples
User Settings Interface
// Controller for user settings class UserSettingsController extends Controller { public function index() { $userId = auth()->id(); $settings = [ 'email_notifications' => Settings::get('email_notifications', $userId), 'theme' => Settings::get('theme', $userId), 'language' => Settings::get('language', $userId), ]; return view('settings.user', compact('settings')); } public function update(Request $request) { $userId = auth()->id(); foreach ($request->only(['email_notifications', 'theme', 'language']) as $key => $value) { Settings::set($key, $value, $userId); } return redirect()->back()->with('success', 'Settings updated!'); } }
Admin Global Settings
// Controller for admin global settings class AdminSettingsController extends Controller { public function update(Request $request) { // Set global settings (modifies default values directly) Settings::set('maintenance_mode', $request->has('maintenance_mode')); Settings::set('max_users', $request->input('max_users', 1000)); // Auto-create settings that might not exist Settings::setWithAutoCreate('new_feature_flag', $request->has('new_feature')); return redirect()->back()->with('success', 'Global settings updated!'); } public function reset($key) { // Reset to original default value Settings::forget($key); return redirect()->back()->with('success', "Setting '{$key}' reset to default!"); } }
๐ง Troubleshooting
API Authentication Issues
Problem: Getting 401/403 errors when accessing API endpoints in development
Solution: Enable development authentication bypass:
SETTINGS_KIT_API_ENABLED=true SETTINGS_KIT_API_DISABLE_AUTH_DEV=true
Problem: API not working in production with authentication
Solution: Ensure proper authentication setup:
# Check these settings SETTINGS_KIT_API_ENABLED=true SETTINGS_KIT_API_DISABLE_AUTH_DEV=false SETTINGS_KIT_API_AUTH=token SETTINGS_KIT_API_TOKEN=your-secure-token
Settings Not Persisting
Problem: Settings appear to save but don't persist
Possible Causes:
- Cache is enabled but not working properly
- Database migration not run
- Wrong user model configuration
Solutions:
# Clear cache php artisan cache:clear # Check migrations php artisan migrate:status # Test database connection php artisan tinker >>> \Metalinked\LaravelSettingsKit\Models\Preference::count()
Auto-Creation Not Working
Problem: Settings aren't being created automatically
Check Configuration:
# For API auto-creation SETTINGS_KIT_API_AUTO_CREATE=true # In your seeder/code Settings::set('new_setting', 'value', $userId); // Auto-creates with is_user_customizable=true Settings::set('global_setting', 'value'); // Auto-creates with is_user_customizable=false
Performance Issues
Problem: Slow settings retrieval
Solutions:
# Enable caching SETTINGS_KIT_CACHE_ENABLED=true SETTINGS_KIT_CACHE_TTL=3600
Environment Detection Issues
Problem: Development bypass not working
Check: Ensure your app environment is set to 'local' or 'testing':
APP_ENV=local # or APP_ENV=testing
The bypass only works in these environments for security.
๐งช Testing
Run the test suite:
composer test
๐ค Contributing
Please see CONTRIBUTING.md for details.
๐ Security
If you discover any security related issues, please email info@metalinked.net instead of using the issue tracker.
๐ License
The MIT License (MIT). Please see License File for more information.