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

Config Bundle Laravel Package

gupalo/config-bundle

Symfony bundle for centralizing application configuration with typed settings, environment-specific overrides, validation, and cached container access. It simplifies managing flexible defaults and maintainable multi-environment deployments while keeping settings organized and consistent across servi...

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package — there is no service provider, no facade, and Composer auto-discovery will do nothing for you. Treat it as a reference implementation you either (a) run inside a Symfony kernel living alongside your Laravel app, or (b) port in an afternoon. The codebase is small enough that reading it is faster than reading docs, which is fortunate because there aren't any.

Minimal evaluation path:

  1. composer require gupalo/config-bundle in a scratch Symfony 6/7 app (not your Laravel app first — you want to see it work in its native habitat).
  2. Register the bundle in config/bundles.php, then check src/DependencyInjection/ for the extension alias and whether the config table is created via Doctrine migrations or auto-mapped entities.
  3. Run php bin/console doctrine:schema:update --dump-sql to see exactly what storage it expects. That schema is the contract you'll be reimplementing in Laravel.
  4. Look at the manager/repository class before anything else. Every question you have about caching, typing, and defaults is answered there.

First use case: runtime-editable site settings — site name, support email, maintenance mode flag, per-environment toggles — that an admin edits without a deploy. That is the only problem this class of bundle solves well, and it's the one worth evaluating against.

For the Laravel side, decide up front which of two shapes you want:

  • Bridge: a Laravel service provider that boots the Symfony container (or just instantiates the manager with a Doctrine connection) and exposes it as a singleton.
  • Port: a settings table plus a ConfigRepository bound to Illuminate\Contracts\Config\Repository, loaded once at boot and merged into config(). Roughly 80 lines. Most teams end up here.

Implementation Patterns

Typed getters over raw arrays. The value in this bundle is not the key/value table — you can write that in a migration — it's the accessor discipline. Wrap every read behind a typed method (getString, getBool, getInt, getArray) with an explicit default. Untyped get('key') returning null, '1', or 'false' depending on how the row was inserted is the #1 source of production bugs in DB-backed config.

Cache-on-read, invalidate-on-write. The bundle's manager almost certainly layers a cache pool over the storage layer. Mirror that in Laravel:

class SettingsRepository
{
    public function get(string $key, mixed $default = null): mixed
    {
        return Cache::rememberForever("settings.{$key}", fn () =>
            DB::table('settings')->where('key', $key)->value('value') ?? $default
        );
    }

    public function set(string $key, mixed $value): void
    {
        DB::table('settings')->updateOrInsert(['key' => $key], ['value' => $value]);
        Cache::forget("settings.{$key}");
    }
}

Cache the whole map under one key instead if your settings count is small — fewer round trips, one invalidation point.

Load-on-boot into the config repository. The pattern that keeps application code idiomatic: at AppServiceProvider::boot(), read all settings once and Config::set('settings', $map). Then call sites use config('settings.maintenance_mode'). Downside: settings changes need a cache clear or a queue-based refresh; don't do this for anything that must change mid-request.

Environment scoping. Store rows keyed by (environment, key) or (tenant_id, key) rather than maintaining separate tables per environment. Seed the table from config/ defaults in a seeder so a fresh checkout and a production DB agree on every key that exists.

Feature flags. Same table, separate namespace (feature.*). Cast to bool at the boundary and expose a single Feature::enabled('new_checkout') helper so call sites never touch the raw value. This is where DB config shines and where env vars get painful (you can't flip FEATURE_X without redeploying or restarting workers).

Admin editing. Build a simple resource form (Filament, Nova, or plain Blade) over the table with a per-key type hint in a companion config file. Whitelist editable keys — never let the admin UI write arbitrary keys, or app.key-adjacent values become editable by anyone with panel access.

Testing. Bind an in-memory implementation (array $values) of your settings interface in tests and never touch the database. This is the main reason to define an interface rather than injecting the Eloquent model directly.

Gotchas and Tips

  • No Laravel integration at all. No extra.laravel block, no auto-discovery, no facade. Anything you get from this package in a Laravel app is either a bridge you wrote or a port you wrote. Budget accordingly.
  • The Symfony container is not request-scoped like Laravel's. The bundle's services are compiled and shared; if you bridge into Laravel, bind it as a singleton and be aware that constructor-injected config is frozen for the worker's lifetime — an Octane worker will hold stale values indefinitely.
  • Cache warmup in production. Symfony warms container/cache at deploy; Laravel doesn't by default. After a settings edit in prod, verify the cache key was actually invalidated — Cache::forget silently does nothing on a key that doesn't exist, which is fine, but a tag-less cache means you cannot invalidate "all settings" cheaply.
  • Missing key vs null value. Decide the semantics explicitly. exists() and get() are different operations; conflating them causes defaults to be skipped whenever an admin clears a field.
  • Never store secrets here. DB-backed config is for values operators should be able to see and change. API keys, encryption keys, and DB passwords stay in .env/a secret manager. If you need both, keep secrets in env and reference them by name.
  • Doctrine coupling. The bundle leans on Doctrine. If you port it, you'll swap entities for Eloquent models; if you bridge it, you inherit a Doctrine DBAL connection alongside your Eloquent one. Prefer the port unless you genuinely need Symfony's console tooling too.
  • Very low adoption signal. Zero stars, zero dependents, a single release (May 2024). That's not a reason to avoid the pattern — DB-backed settings is a well-trodden problem — but it is a reason not to take a hard runtime dependency. Vendor the relevant classes into app/Support/Settings/ and pin nothing.
  • Extension points to check before porting: whether the manager is an interface or a concrete class, whether the cache pool is injectable (so you can substitute tags), and whether there's an event dispatched on save (ConfigChangedEvent or similar) — an event hook is the cleanest place to rebuild caches or broadcast to workers.
  • Debugging tip: when a setting "isn't taking effect," check three layers in order — the DB row, the cache key, and the compiled/bootstrapped config. In that order, every time; the answer is almost always layer two.
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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package