vladab/featuretogglebundle
FeatureToggleBundle is a Symfony/PHP bundle for defining and managing feature toggles. Enable or disable features via configuration, control rollouts by environment or custom conditions, and ship changes safely without redeploying code.
Reality check first: vladab/FeatureToggleBundle is a Symfony bundle, not a Laravel package. It is published with 0 stars and 0 dependents, and the description is a single line ("Feature toggling"). Treat anything below as integration guidance, not verified API documentation — open the repo and read composer.json, the README, and src/ before you write application code. If the README is thin (likely), the DependencyInjection/Configuration.php file is your real documentation: it tells you the exact config keys, and the DependencyInjection/*Extension.php tells you the service IDs you can inject.
Minimal steps to evaluate it:
composer require vladab/featuretogglebundle in a scratch Symfony app first — not in your Laravel app. Confirm it installs against a current Symfony version. A bundle this small is often pinned to an old Symfony major, which is a hard blocker.src/ in this order: the toggle service class (the thing that answers "is feature X on?"), the DI extension (service ID + aliases), the config tree (available options), then any Twig extension or annotation/attribute listener.#[Feature('new_checkout')], or a Twig {% if feature('x') %} function. That primary path is the only one that will be well-tested.FeatureFlags::enabled(string $flag): bool) and a thin adapter that calls the bundle. Every call site depends on your interface, never on the bundle's class names.Your first meaningful use case should be a single, low-risk, reversible branch — e.g. gating one controller action's response shape — so you learn how the toggle actually behaves (defaults when unset, caching, exception behavior) without betting a release on it.
Config-declared toggles with an app-level default. Define toggles in the bundle's config file, but decide in your adapter what happens when a flag is missing. Default to false (fail closed) for new features and true for anything mid-rollout. Missing-flag behavior is the single most common source of "it worked in staging" incidents.
Adapter / anti-corruption layer. This is the pattern that makes an obscure dependency safe:
interface FeatureFlags { public function enabled(string $flag): bool; }
final class BundleFeatureFlags implements FeatureFlags
{
public function __construct(private object $toggleService) {}
public function enabled(string $flag): bool
{
try { return (bool) $this->toggleService->isEnabled($flag); }
catch (\Throwable $e) { report($e); return false; }
}
}
Bind the interface in a Laravel service provider. Swapping to Laravel Pennant or LaunchDarkly later becomes a one-line rebind instead of a grep-and-replace.
Environment-scoped configuration. Keep the toggle definitions in config/features.php (Laravel side) and map them into whatever the bundle expects at boot. Do not read env vars deep inside controllers. Use config('features.checkout_v2', false) at the boundary.
Gating at the edges, not the core. Check toggles in middleware, controllers, Blade directives, or job dispatch — not inside domain services or models. A toggle check buried in a repository makes the code untestable and the flag impossible to remove cleanly.
Blade integration. If the bundle ships a Twig extension, do not try to bridge Twig into Blade. Register a Blade directive (@feature('x') ... @endfeature) that calls your FeatureFlags interface. This is a five-line Blade::directive() call and avoids dragging Twig into a Laravel app.
Testing. Never let tests depend on the real bundle resolution. Bind a fake FeatureFlags implementation in the test container and set flags explicitly per test. Add a separate, small integration test that exercises the real adapter against the bundle's service so a version bump that breaks resolution fails loudly.
Flag lifecycle. Every flag you add should have an owner and a removal date in a comment or a config/features.php entry. Toggles that stay enabled forever are just dead if statements; without this discipline the integration becomes permanent cruft within a quarter.
*Bundle classes; you will hand-wire the container. If the bundle's extension expects Symfony's ContainerBuilder, EventDispatcherInterface, or annotation reader, you may end up pulling symfony/dependency-injection and symfony/config into a Laravel app. That is a lot of surface area for a boolean check — weigh it against ~30 lines of your own config-backed toggles.composer.json's require block. If it caps at Symfony 3 or 4, modern PHP 8.1+ will fight it. Don't discover this in CI.config:cache and route:cache behave differently. If the bundle reads config at compile time, cached configs can serve stale toggle state. Test php artisan config:cache explicitly.false, another throws, another returns null that a loose if treats as false. Pin the behavior in your adapter and cover it with a test.vladab.*) can clash or be ambiguous. Resolve services by explicit ID in your provider, not by type-hinting a class name you guessed.Log::debug('feature', [...]) line in BundleFeatureFlags::enabled() will save you hours. To introspect the service, app()->make(FeatureFlags::class) via php artisan tinker is faster than dumping the container.composer.json, and if you adopt it, wrap it so tightly (the adapter pattern above) that forking or replacing it is a half-day task, not a rewrite.How can I help you explore Laravel packages today?