fintem/feature-toggle-bundle
A PHP feature toggle bundle for managing feature flags in your application, letting you enable or disable features at runtime without redeploying code. Configure toggles centrally to support gradual rollouts, A/B tests, and safer releases across environments.
Reality check before you composer require: this is a Symfony bundle, not a Laravel package. There is no service provider, no auto-discovery, no config/feature_toggle.php. With 3 stars, 0 dependents, and a last release in September 2018, treat it as a reference implementation to read and port rather than a dependency you ship to production. The scoring signal (0.145) reflects the same thing: nobody is running this, so nobody is fixing it.
If you still want to evaluate it:
composer require fintem/feature-toggle-bundle in a scratch Symfony app (it will likely fight you on PHP 8 — the 2018 constraint set targets PHP 5.6/7.x, so pin --ignore-platform-reqs or use a PHP 7.4 container).AppKernel::registerBundles() or config/bundles.php if the bundle ships a modern Bundle class.DependencyInjection/Configuration.php first. That file is the actual API surface: it tells you every config key, default, and nesting level the bundle accepts. Skip the README if it's thin; the Configuration tree never lies.Resources/config/ to find the service ID of the toggle checker (conventionally something like fintem.feature_toggle or feature_toggle.manager). That ID is what you inject.First use case: a single boolean toggle guarding one new code path — a new checkout step, a redesigned nav, a beta endpoint. Declare it in config, inject the checker into one controller, branch on it. Don't start with percentage rollouts or user targeting; get the boolean path working end-to-end first so you understand how the bundle resolves a toggle name.
Laravel translation: if you're porting the idea rather than the package, you only need three pieces — a config file of toggle definitions, a Feature facade/service with isEnabled(string $toggle): bool, and a Blade directive. Everything else in this bundle is Symfony plumbing you'd rewrite as a service provider in under an hour.
Config-declared toggles. The bundle's model is static declaration in YAML plus runtime resolution. Your config file becomes the registry:
feature_toggle:
toggles:
new_checkout:
enabled: true
beta_dashboard:
enabled: false
# strategy/expression keys hang off here if the bundle supports them
Keep this file as the single source of truth and let it be reviewed in PRs — the diff is your release log.
Service injection at the boundary, not everywhere. Inject the toggle checker only into the class that owns the decision (a controller action, a job, a listener). Resist injecting it into domain entities or value objects; you'll regret coupling business logic to infrastructure the moment you swap the implementation.
Template gating. Old Symfony bundles of this vintage almost always ship a Twig extension. Look for a function like feature_enabled('new_checkout') in Resources/views or the Twig/ directory. Prefer gating at the template level for presentation toggles and at the service level for behavioral toggles — mixing them is how you get a half-rendered page when a toggle flips mid-request.
Annotation/attribute gating. If the bundle offers an @FeatureToggle("name") annotation (common in this era), use it on controller actions only. It's convenient for "this whole route is dark," but it's invisible at the call site and will confuse anyone debugging why a 404 appeared. Document every annotated route.
Strategy-based rollout. The pattern worth stealing regardless of the library: resolve a toggle in two stages — is the toggle on at all (kill switch), then does this context qualify (percentage bucket, user list, date window). Bucket users by a stable hash (crc32($userId . $toggleName) % 100 < $percentage) so a user doesn't flicker between variants across requests. If the bundle doesn't ship this, write it yourself; it's ten lines.
Test overrides. Every call site should be testable without touching YAML. Wrap the checker behind a small interface of your own (FeatureFlags::enabled($name)) and bind it to the bundle's service. Then in tests you can swap a fake that returns a fixed map. This one indirection is what makes the package usable even if it's abandoned — you can drop the bundle later without touching 200 call sites.
Laravel-side integration pattern. If you need this behavior inside Laravel, don't try to bridge the Symfony bundle. Reimplement: config/features.php, a FeatureServiceProvider binding a singleton, a Feature::enabled() facade, and a @feature('x') ... @endfeature Blade directive. You get the same semantics, zero abandoned dependencies, and full framework integration (config caching, Octane safety, testing helpers).
It is not a Laravel package. This is the biggest gotcha and the one that will burn the most time. No Feature facade, no php artisan vendor:publish, no auto-discovery. Any Laravel tutorial language ("add to providers array") does not apply. Budget for translation, not installation.
Abandoned since 2018. No security patches, no PHP 8 compatibility fixes, no maintainer. Check the composer.json php constraint before anything else; if it's ^5.6 || ^7.0 you'll hit deprecation noise or hard failures on modern runtimes. If you adopt it, fork it and vendor it — don't depend on Packagist resolution for something nobody owns.
Zero dependents is a signal, not trivia. There's no Stack Overflow corpus, no blog posts, no GitHub issues with answers. Every problem you hit is yours alone. Compare with symfony/feature-flags-style solutions or just rolling your own before committing.
Config caching. Symfony caches the compiled container. After editing feature_toggle config, you must clear cache (bin/console cache:clear) or you'll debug a toggle for twenty minutes that "isn't working." In dev this happens constantly. In Laravel terms: this is the php artisan config:cache trap, but worse because it's implicit.
Default-on vs default-off asymmetry. Decide early what happens when a toggle name doesn't exist in config. Failing open (return true) hides typos and ships unlaunched features; failing closed (return false) makes a missing config entry silently dark. Fail closed in production, and add a dev-only warning log on unknown toggle names — that's how you catch new_checkout vs new_checkoutt.
Toggle lifetime discipline. The package gives you no help here, so enforce it yourself: every toggle gets an owner and an expiry date in a comment next to its config entry. Feature toggles that live past ~2 sprints become permanent dead branches that nobody dares delete. Sweep them.
Extension points to look for. If you do adopt it: the strategy/expression resolver (to add your own targeting rules) and the Twig extension (to add helpers). Both are usually small classes you can subclass or decorate. Avoid modifying the bundle in vendor/ — the next composer update wipes it and there is no next release to merge upstream into anyway.
Debugging approach. Since docs are thin, instrument the resolution: temporarily log the toggle name, the matched config node, and the final boolean at the checker's entry point. Nine times out of ten the bug is a name mismatch or a stale config cache, not the resolution logic.
How can I help you explore Laravel packages today?