Installation
composer require 21torr/feature-flags
Add the bundle to config/bundles.php:
return [
// ...
FeatureFlagsBundle::class => ['all' => true],
];
Configuration Publish the default config:
php bin/console feature-flags:install
Edit config/packages/feature_flags.yaml to define your flags:
feature_flags:
flags:
new_ui: true
experimental_search: false
First Use Case Check a flag in a controller:
use FeatureFlagsBundle\FeatureFlags;
class HomeController extends AbstractController {
public function index(FeatureFlags $featureFlags) {
if ($featureFlags->isEnabled('new_ui')) {
return $this->render('new_ui.html.twig');
}
return $this->render('old_ui.html.twig');
}
}
Flag Management
# .env
FEATURE_FLAGS_NEW_UI=true
FlagProvider to fetch flags from a DB:
class DatabaseFlagProvider implements FlagProviderInterface {
public function getFlags(): array {
return Flag::query()->pluck('enabled', 'name')->toArray();
}
}
Dependency Injection
FeatureFlags into services, controllers, or middleware:
public function __construct(private FeatureFlags $featureFlags) {}
Twig Integration Use the Twig extension for templates:
{% if feature_flags.isEnabled('experimental_search') %}
<div class="experimental-search">
{{ include('experimental_search.html.twig') }}
</div>
{% endif %}
Middleware for Routing Dynamically route based on flags:
$router->add('/admin', AdminController::class)
->withRequirement('feature_flags.admin_access', true);
user_id % 2 == 0).feature_flags:
new_checkout: { enabled: 30 } # 30% rollout
Extend the FlagProvider to handle numeric values.Caching Headaches
php bin/console cache:clear
feature_flags.yaml for development:
feature_flags:
cache: false
Namespace Collisions
app.new_ui vs. new_ui).Environment Overrides
FEATURE_FLAGS_ (e.g., FEATURE_FLAGS_NEW_UI).false.Log Flag Evaluations
Enable debug mode in feature_flags.yaml:
feature_flags:
debug: true
Check logs for flag resolution details.
Test Flag Isolation
Use FeatureFlags::setFlag() in tests:
$featureFlags->setFlag('new_ui', true);
$this->assertTrue($featureFlags->isEnabled('new_ui'));
Custom Providers
Implement FlagProviderInterface for dynamic sources (e.g., Redis, API):
class ApiFlagProvider implements FlagProviderInterface {
public function getFlags(): array {
return json_decode(file_get_contents('https://api.example.com/flags'), true);
}
}
Register in feature_flags.yaml:
feature_flags:
providers:
- FeatureFlagsBundle\Provider\YamlFlagProvider
- App\Provider\ApiFlagProvider
Event Listeners Listen for flag changes (e.g., log updates):
use FeatureFlagsBundle\Event\FlagUpdatedEvent;
public static function getSubscribedEvents(): array {
return [
FlagUpdatedEvent::class => 'onFlagUpdated',
];
}
Validation
Add validation rules to flags in feature_flags.yaml:
feature_flags:
flags:
payment_gateway:
enabled: true
validator: 'is_string|max:255'
How can I help you explore Laravel packages today?