novaway / feature-flag-bundle
Very KISS bundle to manage features flag
Installs: 246 540
Dependents: 0
Suggesters: 0
Security: 0
Stars: 19
Watchers: 6
Forks: 7
Open Issues: 3
Type:symfony-bundle
Requires
- php: >= 8.1
- ext-json: *
- symfony/console: ^5.4|^6.0|^7.0
- symfony/framework-bundle: ^5.4|^6.0|^7.0
- symfony/options-resolver: ^5.4|^6.0|^7.0
Requires (Dev)
- phpunit/phpunit: ^10.1
- symfony/asset: ^5.4|^6.0|^7.0
- symfony/browser-kit: ^5.4|^6.0|^7.0
- symfony/css-selector: ^5.4|^6.0|^7.0
- symfony/expression-language: ^5.4|^6.0|^7.0
- symfony/templating: ^5.4|^6.0|^7.0
- symfony/twig-bundle: ^5.4|^6.0|^7.0
- symfony/yaml: ^5.4|^6.0|^7.0
- twig/twig: ^3.0
Suggests
- twig/twig: To check feature in your Twig templates
README
The FeatureFlagBundle is a bundle to manage features flags in your Symfony applications.
Compatibility
This bundle is tested with at least all maintained Symfony version.
Documentation
Install it
Install extension using composer:
composer require novaway/feature-flag-bundle
If you don't use Flex, enable the bundle in your config/bundles.php
file:
<?php return [ // ... Novaway\Bundle\FeatureFlagBundle\NovawayFeatureFlagBundle::class => ['all' => true], ];
Configuration
To configure and register a feature manager you need a factory service. You may also need to change some options to the factory.
# ... novaway_feature_flag: default_manager: default managers: default: factory: 'novaway_feature_flag.factory.array' options: features: my_feature_1: false my_feature_2: true my_feature3: '%env(bool:FEATURE_ENVVAR)%'
The factories that come with this bundle can be found in the table below.
Factory service id | Options |
---|---|
novaway_feature_flag.factory.array | features |
Example configuration
# ... novaway_feature_flag: default_manager: default managers: default: factory: novaway_feature_flag.factory.array options: features: my_feature_1: enabled: false description: MyFeature1 description text my_feature_2: enabled: true description: MyFeature2 description text my_feature3: enabled: '%env(bool:FEATURE_ENVVAR)%' description: MyFeature3 description text
You can declare multiple managers. Multiple providers is useful if you want to use different storage providers or to isolate your features flags.
# ... novaway_feature_flag: default_manager: manager_foo managers: manager_foo: factory: novaway_feature_flag.factory.array options: features: my_feature_1: enabled: false description: MyFeature1 description text my_feature_2: enabled: true description: MyFeature2 description text my_feature3: enabled: '%env(bool:FEATURE_ENVVAR)%' description: MyFeature3 description text manager_bar: factory: novaway_feature_flag.factory.array options: features: my_feature_4: enabled: false description: MyFeature4 description text my_feature_5: [] my_feature_6: ~ my_feature_7: false
When several managers are defined, they are registered in the Symfony dependency injection container as services with the following naming convention: novaway_feature_flag.manager.<manager_name>
.
For example, the manager_bar
is accessible with the following service name: novaway_feature_flag.manager.manager_bar
.
Manager storage are also registered in the Symfony dependency injection container as services with the following naming convention: novaway_feature_flag.storage.<manager_name>
.
Use it as a service
The bundle adds a global novaway_feature_flag.manager
(also bind to FeatureManager
) service you can use in your PHP classes.
In the case you have defined several managers, the service use the ChainedFeatureManager
class to chain all declared managers.
use Novaway\Bundle\FeatureFlagBundle\Manager\FeatureManager; // ... class MyController extends Controller { public function myAction(FeatureManager $featureManager): Response { if ($featureManager->isEnabled('my_feature_1')) { // my_feature_1 is enabled } if ($featureManager->isDisabled('my_feature_2')) { // my_feature_2 is not enabled } // ... } }
In your Twig templates
You can also check a flag in your templates:
{% if isFeatureEnabled('my_feature_1') %} {% include 'feature1_template.html.twig' %} {% endif %} {% if isFeatureDisabled('my_feature_2') %} {% include 'feature2_template.html.twig' %} {% endif %}
In the routing configuration
The package allows you to restrict a controller access by adding some configuration in your routing definition.
# app/config/routing.yml my_first_route: path: /my/first/route defaults: _controller: AppBundle:Default:index _features: - { feature: my_feature_key, enabled: false } # The action is accessible if "my_feature_key" is disabled my_second_route: path: /my/second-route defaults: _controller: AppBundle:Default:second _features: - { feature: foo } # The action is accessible if "foo" is enabled ... - { feature: bar, enabled: true } # ... and "bar" feature is also enabled - { feature: feature-42, enabled: true, exceptionClass: Symfony\Component\HttpKernel\Exception\BadRequestHttpException } # will throw a BadRequestHttpException if "feature-42" is disabled - { feature: feature-44, enabled: true, exceptionFactory: Symfony\Component\HttpKernel\Exception\BadRequestHttpExceptionFactory } # will use the BadRequestHttpExceptionFactory registered factory class to create the exception to be thrown
As a controller attribute
You can also restrict a controller access with attributes, two attributes are available:
Novaway\Bundle\FeatureFlagBundle\Attribute\FeatureEnabled
Novaway\Bundle\FeatureFlagBundle\Attribute\FeatureDisabled
#[FeatureEnabled(name: "foo")] class MyController extends Controller { #[FeatureEnabled(name: "foo", exceptionClass: BadRequestHttpException::class)] public function annotationFooEnabledAction(): Response { return new Response('MyController::annotationFooEnabledAction'); } #[FeatureDisabled(name: "foo", exceptionFactory: MyExceptionFactory::class)] public function annotationFooDisabledAction(): Response { return new Response('MyController::annotationFooDisabledAction'); } }
Implement your own storage provider
- First your need to create your storage provider class which implement the
Novaway\Bundle\FeatureFlagBundle\Storage\StorageInterface
interface - Register it in the Symfony dependency injection container
- Specify the storage you want to use in a manager configuration
novaway_feature_flag: manager: manager_name: storage: your.custom.service.name options: # arguments need to create the storage service
When you create a storage, the static method create
is called to create the storage instance.
License
This library is published under MIT license