Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Settings Bundle Laravel Package

phpmob/settings-bundle

phpmob/settings-bundle is a Symfony bundle for centralized application settings, letting you define, persist, and retrieve configuration values through a clean, reusable API. It’s a practical fit for projects that need editable settings beyond static config files.

View on GitHub
Deep Wiki
Context7

Getting Started

Know what you are installing. This is a Symfony bundle, not a Laravel package. There is no extra.laravel.providers, no facade, no publishable config, and no auto-discovery. On a Laravel app you are consuming it as a plain library and doing the container wiring yourself. Plan for that from the first commit.

Minimal steps:

composer require phpmob/settings-bundle

Then, before writing any application code:

  1. Read composer.json first. Check the php floor and the symfony/* and doctrine/* constraints. The last release is 2018-06-09; if your app is on PHP 8.x you may get an install-time resolution failure rather than a runtime one. Decide now whether you need --ignore-platform-reqs (don't) or a fork with widened constraints.
  2. Open Resources/config/services.xml (or services.yaml). This is where the real API lives. Note the service IDs for the settings manager and the storage/driver interface it expects. Everything below depends on which interface you must implement.
  3. Look for the storage abstraction. "Flexible persistence through configurable storage" in the description means there is an interface you can implement. That interface is your integration point into Laravel — you will almost certainly write an Eloquent-backed implementation rather than pulling in the Doctrine one.
  4. Skim src/ for a SettingsInterface / Manager class. Prefer typing against that over the concrete class so you survive a future fork or replacement.

First use case: admin-editable site settings with code-level defaults. Site name, support email, pagination size, maintenance-mode flag. Defaults live in config/settings.php (versioned, deployable), overrides live in a settings table (editable in Filament/Nova/a simple CRUD). Reads go through the manager: setting('site.name') returns the DB override if present, otherwise the config default.

That single use case exercises every feature of the package — key-value read, write, defaults, overrides, persistence — and is the smallest thing worth wiring.

Implementation Patterns

Bind the manager once, in a dedicated provider. Don't resolve it with app() at call sites.

// app/Providers/SettingsServiceProvider.php
public function register(): void
{
    $this->app->singleton(SettingsStorageInterface::class, EloquentSettingsStorage::class);

    $this->app->singleton(SettingsManager::class, function ($app) {
        return new SettingsManager(
            $app->make(SettingsStorageInterface::class),
            config('settings.defaults', []),
        );
    });

    $this->app->alias(SettingsManager::class, 'settings');
}

If the bundle ships its own manager with a constructor you can't satisfy, decorate it instead of instantiating it — a thin Settings wrapper class in app/Support/ that owns the third-party type is cheaper to maintain than scattering the vendor class through your codebase.

Defaults in config, overrides in the database. Keep config/settings.php as the single source of truth for what keys exist and what they default to. Everything else is an override row keyed by the same string.

// config/settings.php
return [
    'defaults' => [
        'site.name'        => config('app.name'),
        'site.support'     => '[email protected]',
        'listing.per_page' => 20,
        'features.reviews' => false,
    ],
];

This gives you a working application with zero rows in the database, makes new installations trivial, and makes git diff the record of what settings were added when.

Storage adapter over the vendor's Doctrine driver. A settings migration plus a small repository keeps your stack clean:

Schema::create('settings', function (Blueprint $table) {
    $table->string('key')->primary();
    $table->text('value')->nullable();
    $table->timestamps();
});
class EloquentSettingsStorage implements SettingsStorageInterface
{
    public function get(string $key): ?string
    {
        return Cache::rememberForever("settings.{$key}", fn () =>
            Setting::find($key)?->value
        );
    }

    public function set(string $key, $value): void
    {
        Setting::updateOrCreate(['key' => $key], ['value' => $value]);
        Cache::forget("settings.{$key}");
    }
}

Cache reads, invalidate on write. Settings are read on nearly every request and written almost never — an uncached settings lookup is the classic accidental N+1 in this category of package.

Namespaced keys, not flat keys. site.name / mail.from.address / billing.tax_rate. The package is a flat key-value store; namespacing is a convention you enforce, and it's what makes a future "give me all mail.* settings" query possible without a schema change.

Typed accessors at the boundary. Store strings, expose typed getters:

class Settings
{
    public function bool(string $key): bool
    {
        return filter_var($this->raw($key), FILTER_VALIDATE_BOOLEAN);
    }

    public function int(string $key): int
    {
        return (int) $this->raw($key);
    }
}

Call settings()->bool('features.reviews') in application code, never (bool) setting('features.reviews') — (bool) "false" is true, and that bug will ship.

Blade and validation integration. One Blade directive or a view composer that shares a $settings array is enough; don't inject the manager into views. For the admin form that writes settings, validate against the known key list — Rule::in(array_keys(config('settings.defaults'))) — so a typo in a form field doesn't silently create an orphan row that never gets read.

Test with an in-memory storage. Because storage is an interface, bind an ArraySettingsStorage in TestCase::setUp() for feature tests. Settings tests then don't need a database, and you avoid the "test passes because of a leftover row" class of flake.

Feature-flag rollout pattern. features.* keys plus abort_unless(settings()->bool('features.reviews'), 404) around routes and a @if(settings()->bool(...)) in navigation is the cheapest flag system you'll get from this package. Because writes are cached-invalidated, toggling a flag in production takes effect on the next request without a deploy.

Gotchas and Tips

  • No Laravel auto-discovery. If you composer require and nothing happens, that's correct behaviour, not a broken install. The bundle expects a Symfony kernel with config/bundles.php; Laravel has no equivalent. Register services manually or use the classes standalone.
  • The 2018 release date is the real risk, not the code. Five stars and a single maintainer means no fixes coming. Before adopting, vendor the package or fork it into your own namespace if composer.json constraints block PHP 8+. A fork with only the php and symfony/* constraints widened is usually a ten-minute job and removes the EOL exposure entirely.
  • Watch what Doctrine drags in. Symfony settings bundles of this vintage commonly ship a Doctrine ORM/DBAL storage driver, and its service definitions may reference Doctrine classes unconditionally. If you don't instantiate those services you're fine — but if the bundle's extension is loaded eagerly, you can get a container-time "class not found" for a Doctrine class you never intended to install. Implementing your own storage adapter and never touching the Doctrine service is the clean escape.
  • Environment drift through config:cache. php artisan config:cache freezes config/settings.php. That is what you want for defaults (they're deploy-time constants), but it means a "default" can never be changed at runtime — only overrides can. Don't try to write to config at runtime; write to storage.
  • Cache invalidation across processes. Cache::forget only invalidates the local store. With Redis/database cache this is fine; with the array or file driver per-server, a queued job that writes a setting won't be visible to web workers. Use a shared cache store and Cache::tags() if your driver supports it.
  • Type coercion is on you. Values come back as strings (or null). Booleans, integers, arrays (JSON-encode and decode explicitly), and dates all need a typed accessor layer. The package will not do this for you, and it will not warn you.
  • null vs missing is ambiguous. "No row" and "row with null value" are easy to conflate in a storage adapter, and it matters when you want to explicitly unset an override and fall back to the default. Decide on a sentinel (throw, or treat null as "unset" and delete the row) and document it in the adapter.
  • Debugging a resolution failure: composer update phpmob/settings-bundle --dry-run -vvv prints the constraint chain. The blocking requirement is almost always your PHP version or a sibling package pinned to an older Symfony major, not this package.
  • Extension points worth knowing. The storage/driver interface (implement it for Eloquent), and the manager itself (decorate it to add caching, logging, or a getMany() bulk method your admin screen will want). Both are stable enough to build on; do not extend concrete vendor classes.
  • Have an exit plan. Given the maintenance profile, keep the vendor type out of your public API — a single App\Support\Settings wrapper with get/set/bool/int/forget means replacing this package later, with spatie/laravel-settings or thirty lines of your own, is a one-file change.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib