codersandip/laravel-dynamic-settings

A professional Laravel package to store and manage application settings dynamically using the database with caching, multi-tenant support, and an admin panel UI.

Maintainers

Package info

github.com/codersandip/laravel-dynamic-settings

Language:Blade

pkg:composer/codersandip/laravel-dynamic-settings

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-03-09 22:51 UTC

This package is auto-updated.

Last update: 2026-03-09 22:57:59 UTC


README

Latest Version on Packagist PHP Version Require License

A professional Laravel package to store and manage application settings dynamically using the database instead of config files. Supports automatic caching, multi-tenant scoping, per-user overrides, and a beautiful admin panel UI.

Features

  • 📦 Database-driven settings — store any key/value with type casting
  • Automatic caching — configurable driver and TTL, cache invalidated on update
  • 🏢 Multi-tenant support — tenant-scoped settings with global fallback
  • 👤 Per-user overrides — priority: user → tenant → global
  • 🎨 Admin Panel UI — dark-mode Bootstrap 5 CRUD interface with search, filter, toggles
  • 🔄 Inline editing — AJAX quick-update widget on the edit page
  • 🛡️ Type supportstring, integer, float, boolean, json
  • 🖥️ Artisan commandssettings:cache, settings:clear, settings:seed
  • Fully tested — PHPUnit test suite included

Requirements

  • PHP 8.1+
  • Laravel 10.x / 11.x / 12.x

Installation

1. Install via Composer

composer require codersandip/laravel-dynamic-settings

Laravel auto-discovers the service provider. No manual registration needed.

2. Publish assets

Publish everything at once:

php artisan vendor:publish --tag=settings-all

Or selectively:

# Config only
php artisan vendor:publish --tag=settings-config

# Migrations only
php artisan vendor:publish --tag=settings-migrations

# Views only
php artisan vendor:publish --tag=settings-views

# Routes only
php artisan vendor:publish --tag=settings-routes

3. Run migrations

php artisan migrate

4. (Optional) Seed default settings

php artisan settings:seed

Configuration

After publishing, edit config/settings.php:

return [
    // Cache driver (file, redis, memcached, array)
    'cache_driver' => env('SETTINGS_CACHE_DRIVER', 'file'),

    // Cache TTL in seconds (3600 = 1 hour)
    'cache_ttl' => env('SETTINGS_CACHE_TTL', 3600),

    // Cache key prefix
    'cache_prefix' => env('SETTINGS_CACHE_PREFIX', 'dyn_setting'),

    // Admin panel URL prefix
    'route_prefix' => env('SETTINGS_ROUTE_PREFIX', 'admin/settings'),

    // Middleware applied to admin routes
    'route_middleware' => ['web', 'auth'],

    // Available groups in the dropdown
    'groups' => ['general', 'email', 'payment', 'security'],
];

You can also set these in your .env file:

SETTINGS_CACHE_DRIVER=redis
SETTINGS_CACHE_TTL=7200
SETTINGS_ROUTE_PREFIX=dashboard/settings

Usage

Helper Function

// Get a setting
setting('site_name');                     // → 'My Application'

// Get with a default value
setting('site_name', 'Default App');      // → 'Default App' if not set

// Get with tenant context (falls back to global if not found)
setting('currency', 'USD', $tenantId);

// Get with tenant + user context
setting('theme', 'light', $tenantId, $userId);

Set a Setting

// Via helper (chained)
setting()->set('site_name', 'My App');

// With options
setting()->set('page_size', 20, [
    'type'        => 'integer',
    'group'       => 'general',
    'description' => 'Results per page',
]);

Facade

use Codersandip\DynamicSettings\Facades\Settings;

Settings::get('site_name');
Settings::get('site_name', 'Default');
Settings::set('site_name', 'New Name');
Settings::delete('site_name');
Settings::has('site_name');

Service (Dependency Injection)

use Codersandip\DynamicSettings\Services\SettingsService;

class MyController extends Controller
{
    public function __construct(private SettingsService $settings) {}

    public function index()
    {
        $siteName = $this->settings->get('site_name', 'My App');
        // ...
    }
}

Data Types

Type PHP Type Storage Example
string string As-is "Hello World"
integer int Numeric string 42
float float Numeric string 3.14
boolean bool "1" / "0" true / false
json array JSON string ["stripe", "paypal"]
setting()->set('enabled',  true,             ['type' => 'boolean']);
setting()->set('count',    100,              ['type' => 'integer']);
setting()->set('gateways', ['stripe', 'pp'], ['type' => 'json']);

setting('enabled');   // → true  (bool)
setting('count');     // → 100   (int)
setting('gateways');  // → ['stripe', 'pp']  (array)

Multi-Tenant Support

Settings resolve with this priority: user → tenant → global

// Store global setting
setting()->set('currency', 'USD');

// Store tenant-specific override
setting()->set('currency', 'GBP', ['tenant_id' => 5]);

// Store user-specific override (within a tenant)
setting()->set('currency', 'EUR', ['tenant_id' => 5, 'user_id' => 12]);

// Retrieval
setting('currency');              // → 'USD'  (global)
setting('currency', null, 5);    // → 'GBP'  (tenant 5 override)
setting('currency', null, 5, 12);// → 'EUR'  (user 12 override)
setting('currency', null, 5, 99);// → 'GBP'  (user 99 falls back to tenant)
setting('currency', null, 9);    // → 'USD'  (tenant 9 falls back to global)

Fluent API

use Codersandip\DynamicSettings\Facades\Settings;

// Set tenant context once
$tenantSettings = Settings::forTenant(5);

$tenantSettings->get('currency');    // uses tenant 5
$tenantSettings->get('locale');

// Chain tenant + user
Settings::forTenant(5)->forUser(12)->get('theme');

Artisan Commands

Command Description
settings:cache Pre-warm cache with all settings from DB
settings:clear Flush the settings cache
settings:seed Seed a set of default settings
php artisan settings:cache
php artisan settings:clear
php artisan settings:seed
php artisan settings:seed --force   # overwrite existing settings

Admin Panel

Access the admin panel at /admin/settings (configurable via route_prefix).

The panel includes:

  • 📋 Index — list all settings with search, group/type filter, boolean toggles
  • Create — add a new setting with type, group, scope options
  • ✏️ Edit — update a setting, with inline AJAX quick-update widget
  • 🗑️ Delete — remove a setting (with confirmation)

Protecting the Admin Panel

Set the middleware in config/settings.php:

'route_middleware' => ['web', 'auth', 'can:manage-settings'],

Or disable the built-in routes and define your own:

// config/settings.php
'disable_routes' => true,

Then publish routes:

php artisan vendor:publish --tag=settings-routes

And register the file in bootstrap/app.php or routes/web.php.

Database Schema

settings
├── id                  (bigint, auto-increment)
├── key                 (varchar 191, indexed)
├── value               (longtext, nullable)
├── type                (varchar 20 — string|integer|float|boolean|json)
├── group               (varchar 50, indexed, default: general)
├── tenant_id           (bigint unsigned, nullable, indexed)
├── user_id             (bigint unsigned, nullable, indexed)
├── description         (varchar, nullable)
├── is_public           (boolean, default: false)
├── created_at
└── updated_at

UNIQUE (key, tenant_id, user_id)

Testing

composer test

Changelog

See CHANGELOG.md.

License

The MIT License (MIT). See LICENSE for details.

Author

Sandipcontact@codersandip.com
GitHub: github.com/codersandip