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.

v1.1.0 2025-09-30 13:25 UTC

This package is auto-updated.

Last update: 2025-09-30 14:11:35 UTC


README

Tests GitHub Release Total Downloads License

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

  • ๐Ÿ”ง 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 category
  • role - 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 for is_user_customizable = true settings)
  • If $userId is null:
    • For global unique settings (is_user_customizable = false): Modifies default_value directly
    • For user customizable settings (is_user_customizable = true): Modifies default_value directly (affects all users who haven't customized)
  • 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 values
  • boolean - True/false values
  • integer - Numeric values
  • json - JSON objects/arrays
  • select - 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:

  1. Cache is enabled but not working properly
  2. Database migration not run
  3. 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.