ECNFeatureToggleBundle
, (*1)
This bundle adds feature toggle functionality to your Symfony project., (*2)
Requirements
In order to install ECNFeatureToggleBundle, you need at least, (*3)
- PHP 8.0 or greater
- Symfony 5.4 or greater
Installation
Step 1: Install via composer
$ composer require ecn/featuretoggle-bundle
Functionality of twig is only optional. Require it to your composer if you need it to use it., (*4)
$ composer require twig/twig
Step 2: Activate the bundle
Add the bundle to the AppKernel.php:, (*5)
<?php
// in AppKernel::registerBundles()
$bundles = array(
// ...
new Ecn\FeatureToggleBundle\EcnFeatureToggleBundle(),
// ...
);
Configuration
The idea behind Feature Toggle development is that features are defined on a local basis. Because of this it is
a good idea to have your feature definitions in a separate config file, which shouldn't be under version control:, (*6)
Create a new yml file, e.g. features.yml
and make your SCM ignore this file., (*7)
Then add the following configuration to your features.yml:, (*8)
``` yaml
ecn_feature_toggle:
features:, (*9)
Import the features.yml file into your configuration:
``` yaml
imports:
- { resource: features.yml, ignore_errors: true }
Usage
Step 1: Add a feature toggle
Define a new feature toggle inside your feature configuration:, (*10)
``` yaml
ecn_feature_toggle:
features:
MyNewFeature:, (*11)
### Step 2: Check for a feature toggle inside the code
Now you can check inside your code, if this feature is defined.
Inside a twig template:
``` jinja
{% if feature('MyNewFeature') %}
<p>Here is my new feature!</p>
{% endif %}
Or using the tag:, (*12)
``` jinja
{% feature MyNewFeature %}
, (*13)
Here is my new feature!, (*14)
{% endfeature %}
Inside an action:
``` php
if ($this->get('feature')->has('MyNewFeature')) {
// Your new feature here
}
Voters
In order to decide if a feature is available or not, voters are being used. Currently, there are five voters included., (*15)
AlwaysTrueVoter
This is the default voter, and it will always pass. So if you have a feature defined, it will always be displayed., (*16)
The full configuration for using this voter looks like this:, (*17)
``` yaml
ecn_feature_toggle:
features:
MyNewFeature:
voter: AlwaysTrueVoter, (*18)
Because this is the default voter, the voter part in the configuration can be omitted.
### AlwaysFalseVoter
This voter will always fail. If you have a feature defined that uses this voter, it will never be displayed.
The full configuration for using this voter looks like this:
``` yaml
ecn_feature_toggle:
features:
MyNewFeature:
voter: AlwaysFalseVoter
RatioVoter
This voter passes on a given ratio between 0 and 1, which makes it suitable for A/B testing. The default ratio is 0.5., (*19)
The higher the ratio, the more likely the voter will pass. A value of 1 will make it pass every time, 0 will make it
never pass., (*20)
Additionally, the result of the first check can be bound to the users' session. This is useful if you need a feature
to be persistent across multiple requests. To enable this, just set sticky
to true
., (*21)
If you want to use this voter, this is the full configuration:, (*22)
``` yaml
ecn_feature_toggle:
features:
MyNewFeature:
voter: RatioVoter
params: { ratio: 0.5, sticky: false }, (*23)
### ScheduleVoter
This voter passes on a given schedule being after now.
If you want to use this voter, this is the full configuration:
``` yaml
ecn_feature_toggle:
features:
MyNewFeature:
voter: ScheduleVoter
params: { schedule: '2015-10-23' }
The name of the request header itself is by design case-insensitive., (*24)
Request header values are always treated as strings, so equal (==) checks are used and not identical matching (===)., (*25)
Request header keys are by design case-insensitive., (*26)
The Voter does not pass if the request stack contains no current requests., (*27)
a. Specify key/value pairs
This voter passes, when all of the specified headers and their corresponding values are found and equal
to that of the current request headers., (*28)
Example for key/value config:, (*29)
``` yaml
ecn_feature_toggle:
features:
FooRequestFeature:
voter: RequestHeaderVoter
params: { headers: { foo: bar, x-cdn: 'akamai', x-location: 'cn' } }, (*30)
#### b. specify request header keys only
You can also specify a list of request header keys without values.
In this case, only the existence of *all* of the specified request headers is checked.
All request header names are by the standard case-insensitive.
Example:
``` yaml
ecn_feature_toggle:
features:
FooRequestFeature:
voter: RequestHeaderVoter
params: { headers: { x-mobile, x-foo-debug-header } }
Mixing the two configurations is discouraged as it will lead to unexpected results by treating the config as key/value pairs,
and will most likely cause the Voter to not pass., (*31)
Overriding the default voter
You can override the default voter like this:, (*32)
``` yaml
ecn_feature_toggle:
default:
voter: RatioVoter
params: { ratio: 0.1, sticky: true }, (*33)
## Adding your own voters
Adding voters is straight forward. First make sure, that your voter implements `\Ecn\FeatureToggleBundle\Voters\VoterInterface`.
Then define your voter as service, tag it as ``ecn_featuretoggle.voter`` and give it an alias:
``` xml
<!-- Example Voter -->
<service id="ecn_featuretoggle.voter_example" class="My\Example\Voter">
<tag name="ecn_featuretoggle.voter" alias="ExampleVoter" />
</service>
Testing
bash
$ composer test
, (*34)
License
The MIT License (MIT). Please see License File for more information., (*35)