nusje2000/feature-toggle-bundle
A Symfony bundle for adding feature toggles to PHP applications. Define toggles in configuration and enable or disable features at runtime, making gradual rollouts, testing, and safe deployment easier without code changes.
This package is a Symfony bundle (nusje2000/feature-toggle-bundle), not a native Laravel package — before adopting it, confirm whether you want it for a Laravel app (you'll be wiring the services/config by hand via a service provider) or for a Symfony service inside a monorepo. The v6.0.0 release is a major breaking release: myclabs/php-enum was removed in favour of native PHP enums, and classes were given return/param types throughout.
Minimal setup (Symfony-style registration, adapted for Laravel):
composer require nusje2000/feature-toggle-bundle:^6.0config/feature_toggle.php (or YAML if you're in Symfony), under the feature_toggle root key.FeatureToggleServiceProvider), or extend AbstractBundle/Bundle if you're inside a Symfony kernel.First use case: guard a risky code path behind a toggle, resolve the toggle once at the top of the request (middleware or controller), and pass a boolean into the domain layer. Don't let the toggle service leak into models.
Where to look first:
DependencyInjection/Configuration.php (the source of truth for config keys — this is what changes between majors).Toggle/ and Enum/ directories — the enum removal is the headline change in v6.Twig extension, only if you're rendering flags in templates.Config-driven toggles. Keep toggles declarative: each toggle gets a name, an enabled flag, and optional conditions (percentage rollouts, date windows, environment checks). Commit the config; treat it as the contract.
Resolve once, inject a boolean. Wrap the registry in a thin FeatureFlags class of your own:
final class FeatureFlags
{
public function __construct(private ToggleRegistry $registry) {}
public function enabled(string $name): bool
{
return $this->registry->get($name)->isEnabled();
}
}
Then bind an interface in a service provider so tests can swap in a fake. This insulates you from the v5→v6 enum/type churn.
Attribute/annotation-driven checks. If you use the bundle's attribute-based toggling on controller actions, keep those attributes on controllers only — never on domain services, or you'll bake HTTP concerns into the core.
Environment-scoped rollout. Pair the bundle's conditions with Laravel's app()->environment() or Symfony's %kernel.environment% in the toggle config so staging can enable everything while production rolls out gradually.
Testing pattern. Build a FakeFeatureFlags that returns a fixed map. Assert both branches of every toggle at least once — toggles that are never exercised in the "off" state rot silently. Add a test that iterates the configured toggle names and asserts each is declared, so a typo in a name fails CI rather than silently defaulting.
Integration tip (Laravel). Because this isn't a Laravel package, avoid Facade sugar. Register the registry as a singleton in a provider, and if you need request-scoped overrides (e.g. a query param for QA), use a scoped binding ($this->app->scoped()).
v6.0.0 breaking changes — read before upgrading:
myclabs/php-enum removed. Any code, config, or custom toggle class that referenced the package's Enum base class or passed myclabs enum instances must migrate to native PHP 8.1 enum (backed enums if you serialise the value). Config values that were previously enum constants may now need string/int literals matching the enum's backing value. Audit your config files, not just your PHP.Declaration must be compatible errors at autoload time. Grep your codebase for extends on bundle namespaces.php artisan optimize:clear && php artisan about, or bin/console cache:clear).^6.0 and check whether any transitive dependency still drags in myclabs/php-enum — if so, you have two enum systems alive at once and confusing type errors.Config key quirks. The bundle is strict about the feature_toggle root key; a mis-nested block typically results in "no toggles defined" rather than a validation error. Add a boot-time assertion that your expected toggle count is non-zero.
Debugging. When a toggle behaves unexpectedly, dump the resolved toggle (name, enabled, matched condition) rather than the raw config — conditions can short-circuit in non-obvious order. Log the decision once per request at debug level, not per call.
Default behaviour. Decide deliberately what an unknown toggle name does. If the bundle throws, wrap it and fail closed (feature off) for user-facing paths, but fail loudly in tests.
Extension points. Prefer the bundle's condition/toggle interfaces over forking the bundle. If you must customise, decorate the registry service in your container rather than editing vendor code — the v5→v6 jump shows how quickly internals move.
Performance. Resolve toggles lazily; a toggle that hits a database or remote store per call will hurt. Cache the resolved set per request, and if you later back toggles with a DB table, add a short TTL cache keyed by toggle name.
How can I help you explore Laravel packages today?