Search by

sashalenz / laravel-settings-ui

sashalenz

Declarative, nestable runtime settings for Laravel โ€” fluent schema, pluggable stores, secure secrets, resilient cache, config() overlay and bundled admin UI.

Package info

github.com/sashalenz/laravel-settings-ui

pkg:composer/sashalenz/laravel-settings-ui

Statistics

Installs: 432

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.3 2026-10-26 20:49 UTC

This package is auto-updated.

Last update: 2026-10-26 20:49:20 UTC


README

Latest Version on Packagist GitHub Tests Action Status Total Downloads License

Declarative, nestable runtime settings for Laravel โ€” fluent schema, pluggable stores, secure secrets, resilient cache, transparent config() overlay, and a bundled responsive admin UI built with Livewire and Tailwind CSS.

โœจ Features

  • Code-Authoritative Declarations: Settings are defined in strongly typed PHP classes, never in the database.
  • Zero-Coupling config() Overlay: Application code continues to read config('group.key') without any dependency on the settings machinery.
  • Deep Hierarchical Nesting: Groups, subgroups, cards, sections, and fields mirror full dotted paths (group.section.key).
  • Pluggable Storage Backends: Database, Encrypted Database, File (JSON/YAML), and external Secret Stores (Vault, AWS Secrets Manager, etc.).
  • Pluggable & Secure Secrets Engine:
    • Masked values in HTML and Livewire states.
    • Zero-plaintext leaks in logs and exception traces.
    • Rate-limited and permission-gated "Click to Reveal" action.
  • Resilient & Stampede-Protected Cache:
    • Stores primitive values only (zero risk of __PHP_Incomplete_Class serialization bugs).
    • Schema fingerprinting & version-stamped keys.
    • Cache stampede prevention via cache locks.
    • Queue worker / Octane auto-refresh hooks.
  • Full Audit History & Revert:
    • Automatically records user, timestamp, before/after values, and source.
    • One-click rollback to prior versions.
  • Modular & Domain Discovery:
    • Register settings from packages, modules, or domains (Settings::register(...) or Settings::discover(...)).
    • Composer extra.laravel-settings discovery.
  • Seeder Engine & CLI:
    • SettingsSeeder for idempotent seeding (syncMissing() and forceSync()).
    • Artisan commands: settings:sync, settings:seed, settings:doctor, settings:clear-cache.

๐Ÿ“ฆ Installation

Install via Composer:

composer require sashalenz/laravel-settings-ui

Publish configuration and migrations:

php artisan vendor:publish --tag="settings-config"
php artisan vendor:publish --tag="settings-migrations"
php artisan migrate

๐Ÿš€ Quick Start

1. Declare a Setting Schema

Create a schema class implementing DeclaresSettings:

namespace App\Settings;

use SashaLenz\SettingsUi\Contracts\DeclaresSettings;
use SashaLenz\SettingsUi\Schema\Field;
use SashaLenz\SettingsUi\Schema\Group;

final class GeneralSettings implements DeclaresSettings
{
    public function schema(): Group
    {
        return Group::make('general')
            ->label('General Settings')
            ->icon('heroicon-o-cog')
            ->fields([
                Field::text('site_name')
                    ->label('Website Name')
                    ->default('My App')
                    ->rules(['required', 'string', 'max:255']),

                Field::boolean('maintenance_mode')
                    ->label('Maintenance Mode')
                    ->default(false),

                Field::text('api_token')
                    ->label('API Secret Token')
                    ->secret()
                    ->store('secrets'),
            ]);
    }
}

2. Register the Schema

In your config/settings.php:

'schemas' => [
    \App\Settings\GeneralSettings::class,
],

Or programmatically in any ServiceProvider:

use SashaLenz\SettingsUi\Facades\Settings;

public function boot(): void
{
    Settings::register([
        \App\Settings\GeneralSettings::class,
    ]);

    // Or discover all settings across domain modules:
    Settings::discover([
        app_path('Domain/*/Settings'),
    ]);
}

3. Read Values Transparently

// Stored database value automatically overlays config file default:
$siteName = config('general.site_name');

// Or using the Settings facade:
$siteName = Settings::get('general.site_name');

๐Ÿ” Secrets Management

Mark fields as secret to encrypt them and prevent plaintext exposure in forms and logs:

Field::text('stripe_secret')
    ->secret()
    ->store('secrets')

Supported Drivers:

  • encrypted-db: Encrypted locally in your database using Laravel's APP_KEY.
  • env: Resolves from .env environment variables.
  • vault: HashiCorp Vault KV v1/v2 engine.
  • aws: AWS Secrets Manager.

๐ŸŒฑ Seeding Settings

Seed declared defaults safely without overwriting existing settings:

use SashaLenz\SettingsUi\Database\Seeders\SettingsSeeder;

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        $this->call(SettingsSeeder::class);
    }
}

Or via Artisan CLI:

php artisan settings:seed
php artisan settings:seed --group=general --force

๐Ÿ–ฅ Admin UI

Mount the routes in your routes file (e.g., routes/web.php):

use SashaLenz\SettingsUi\Facades\Settings;

Route::prefix('admin')->middleware(['web', 'auth'])->group(function () {
    Settings::routes();
});

Available routes:

  • /admin/settings โ€” List of setting groups
  • /admin/settings/{group} โ€” Group editor form
  • /admin/settings/history โ€” Audit change log & revert
  • /admin/settings/schema โ€” Read-only schema inspector

๐Ÿงช Testing

composer test
composer format
composer analyse

๐Ÿ“„ License

The MIT License (MIT). Please see License File for more information.

Lists and repeaters

Use a list for strings, or a repeater for objects with declared child fields:

Field::list('tags')->default(['news'])->minItems(1)->maxItems(10)->itemLabel('Tag'),

Field::repeater('links')
    ->schema([
        Field::text('label')->rules('required|string|max:100'),
        Field::text('url')->rules('required|url'),
    ])
    ->default([['label' => 'Home', 'url' => 'https://example.com']])
    ->minItems(1)->maxItems(5)->itemLabel('Link'),

Both default to an empty array. The UI offers add, remove, move up, and move down controls. itemLabel() accepts a literal or translation key followed by the row number. Child defaults initialize new repeater rows. Schemas contain unique, non-secret scalar fields; nested collections are not supported.

Collection rules include array and the configured item limits. Lists validate each data.path.* as a string; repeater child rules use data.path.*.child. Use rules() on a collection for additional array-level constraints. Empty lists are allowed unless a minimum or required rule is declared.

Values persist as JSON arrays through the existing database/file stores and remain PHP arrays in the config overlay. Removing or moving rows reindexes the array. Collection defaults must be arrays. secret(), encrypted(), and external secret bindings are not allowed on lists/repeaters.

The Livewire form actions addRow($path), removeRow($path, $index), and moveRow($path, $from, $to) accept paths relative to the group (without data.).