An Unleash bundle for Symfony applications to provide an easy way to use feature flags

Overview

Unleash Bundle

Packagist PHP from Packagist License

An Unleash bundle for Symfony applications.

This provide an easy way to implement feature flags using Gitlab Feature Flags Feature.

Inspired by minds/unleash-client-php and mikefrancis/laravel-unleash.

Installation

composer require stogon/unleash-bundle

Configurations

Full configurations example:

# config/packages/unleash.yaml
unleash:
    # The full URL to your unleash-server instance.
    # Example with the "feature_flags" feature from Gitlab.com : https://gitlab.com/api/v4/feature_flags/unleash/<project_id>
    api_url: 'https://gitlab.com/api/v4/feature_flags/unleash/<project_id>'

    # Instance ID of your unleash application.
    # Example : VPQgqIdAxQyXY96d6oWj
    instance_id: '<some ID>'

    # Unleash application name.
    # For Gitlab feature flags, it can the the environment name.
    # default: '%kernel.environment%'
    environment: '%kernel.environment%'

    cache:
        # Enable caching of features fetched from Unleash server.
        # default: true
        enabled: true
        # Service ID to use for caching (must be a cache pool)
        # default: '%unleach.cache.service%' (which resolve to '@cache.unleash.strategies' service)
        service: '@cache.app'
        # The period of time from the present after which the item MUST be considered expired in the cache in seconds
        # default: 15
        ttl: 15

Usage

To use the client, simply inject Stogon\UnleashBundle\UnleashInterface into your service and use it like this:

<?php

namespace App\Controller;

use Stogon\UnleashBundle\UnleashInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class HomeController extends AbstractController
{
    #[Route('/', name: 'homepage')]
    public function index(UnleashInterface $unleash): Response
    {
        if ($unleash->isFeatureEnabled('my_awesome_feature')) {
            // do something awesome !
        }

        if ($unleash->isFeatureDisabled('my_other_feature')) {
            // do something else
        }

        return $this->render('home/index.html.twig');
    }
}

Twig

The bundle also provide Twig functions to check if a feature is enabled/disabled for the current user:

{# Check if a feature is enabled for current user #}
{%- if is_feature_enabled('my_awesome_feature') -%}
    <div class="alert alert-success" role="alert">
        The <code>my_awesome_feature</code> feature is enabled for current user !
    </div>
{%- else -%}
    <div class="alert alert-warning" role="alert">
        The <code>my_awesome_feature</code> feature is disabled for current user !
    </div>
{%- endif -%}

{# Check if a feature is disabled for current user #}
{%- if is_feature_disabled('my_awesome_feature') -%}
    <div class="alert alert-success" role="alert">
        The <code>my_awesome_feature</code> feature is disabled for current user !
    </div>
{%- else -%}
    <div class="alert alert-warning" role="alert">
        The <code>my_awesome_feature</code> feature is enabled for current user !
    </div>
{%- endif -%}

Strategies

Available strategies:

Strategy name Description
default It is the simplest activation strategy and basically means "active for everyone".
userWithId This strategy allows you to specify a list of user IDs that you want to expose the new feature for. (A user id may, of course, be an email if that is more appropriate in your system.)
flexibleRollout A flexible rollout strategy which combines all gradual rollout strategies in to a single strategy (and will in time replace them)
gradualRolloutUserId The gradualRolloutUserId strategy gradually activates a feature toggle for logged-in users. Stickiness is based on the user ID. The strategy guarantees that the same user gets the same experience every time across devices
gradualRolloutSessionId Similar to gradualRolloutUserId strategy, this strategy gradually activates a feature toggle, with the exception being that the stickiness is based on the session IDs. This makes it possible to target all users (not just logged-in users), guaranteeing that a user will get the same experience within a session.
gradualRolloutRandom The gradualRolloutRandom strategy randomly activates a feature toggle and has no stickiness. We have found this rollout strategy very useful in some scenarios, especially when we enable a feature which is not visible to the user. It is also the strategy we use to sample metrics and error reports.

For more informations, see https://docs.getunleash.io/docs/activation_strategy

Add a custom strategy

If the existing strategies does not fill your needs, you can implement a custom strategy with your own logic.

First, you need to create a class which implements the Stogon\UnleashBundle\Strategy\StrategyInterface

<?php

namespace App\Unleash\Strategy;

use Stogon\UnleashBundle\Strategy\StrategyInterface;

class MyCustomStrategy implements StrategyInterface
{
    public function isEnabled(array $parameters = [], array $context = [], ...$args): bool
    {
        // TODO: Implement your custom logic here.

        return false;
    }
}

Then you need to tag your custom strategy with the unleash.strategy tag and provide a activation_name for it.

services:
    App\Unleash\Strategy\MyCustomStrategy:
        tags:
            - { name: unleash.strategy, activation_name: my_custom_activation_strategy }

The activation_name must match the strategy.name value of your Unleash strategy ! see https://docs.getunleash.io/docs/activation_strategy

Override an existing strategy

You can override an existing strategy simply by setting the activation_name of the tag to the same strategy name used here.

Example:

services:
    App\Unleash\Strategy\MyCustomStrategy:
        tags:
            - { name: unleash.strategy, activation_name: userWithId }

Add additional context to strategies

If you want to add additional data to the context passed to resolved strategy ($context parameter of the Stogon\UnleashBundle\Strategy\StrategyInterface::isEnabled method), you can implement an event listener/subscriber to react to the Stogon\UnleashBundle\Event\UnleashContextEvent event.

Example:

<?php

namespace App\EventSubscriber;

use Stogon\UnleashBundle\Event\UnleashContextEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class UnleashContextSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return [
            UnleashContextEvent::class => ['onUnleashContextEvent'],
        ];
    }

    public function onUnleashContextEvent(UnleashContextEvent $event): void
    {
        // Get the original payload as an array;
        $payload = $event->getPayload();

        // Set some custom data
        $payload['awesome_data'] = 'amazing';

        // Update payload
        $event->setPayload($payload);
    }
}

Testing

Simply run :

composer run test

or

$ ./vendor/bin/phpunit
$ ./vendor/bin/phpstan analyse
$ ./vendor/bin/php-cs-fixer fix --config=.php_cs.dist

Contributing

TODO:

Special thanks

Thanks to @lastguest for his implementation of the Murmur::hash3_int (https://github.com/lastguest/murmurhash-php)

Comments
  • Add explicit token whether $token equals null

    Add explicit token whether $token equals null

    In PHP 8, the signature of method_exists does not allow for null values as the first argument. Because $token is not verified, this will crash when calling isFeatureEnabled when the user is not signed in (the registration page in our case).

    bug 
    opened by mvriel 3
  • Use a command to refresh the cache

    Use a command to refresh the cache

    We are using this bundle with Gitlab Features and sometimes the latency is quite high (>200ms, even seen 4000ms). So when the cache is expired one user request is really slow.

    Maybe it is a idea to make a Symfony Command that can call the Unleash endpoint and fetch the features and populate the cache. This can then run in a cron so it works asynchronous and does not has an effect on the request.

    enhancement 
    opened by leonrenkema 2
  • PHP 7.4

    PHP 7.4

    The bundle doesn't seem to work with PHP 7.4 (anymore?) due to some dependency:

      Problem 1
        - symfony/http-client-contracts 2.5.x-dev requires php >=8.0.2 -> your PHP version (7.4.8) does not satisfy that requirement.
        - Installation request for stogon/unleash-bundle ^0.3.3 -> satisfiable by stogon/unleash-bundle[v0.3.3].
        - Conclusion: remove symfony/http-client-contracts v2.3.1
        - Conclusion: don't install symfony/http-client-contracts v2.3.1
        - stogon/unleash-bundle v0.3.3 requires symfony/http-client-contracts ^2.4 -> satisfiable by symfony/http-client-contracts[2.4.x-dev, 2.5.x-dev].
        - Can only install one of: symfony/http-client-contracts[2.4.x-dev, v2.3.1].
        - Can only install one of: symfony/http-client-contracts[2.5.x-dev, v2.3.1].
        - Installation request for symfony/http-client-contracts (locked at v2.3.1, required as 2.3.*) -> satisfiable by symfony/http-client-contracts[v2.3.1].
    
    question 
    opened by lostfocus 2
  • Improve error handling

    Improve error handling

    In case of a failing request to the unleash server, the whole symfony request fails. Wrapping the request and getting its content into a try catch, makes it more robust.

    Should additionally some logging be added?

    bug 
    opened by m-idler 2
  • userWithId strategy not working with int userIds

    userWithId strategy not working with int userIds

    The userWithId strategy doesn't work with a non-string id property due to the strict in_array check (3rd parameter). Wouldn't it make sense, to change it to false?

    https://github.com/Stogon/unleash-bundle/blob/bfb955dea79a6d49085e410eae7b86de15fbeb7a/src/Strategy/UserWithIdStrategy.php#L25 to be changed to

    if (method_exists($currentUser, 'getId') && in_array($currentUser->getId(), $ids, false)) { 
    
    bug 
    opened by m-idler 1
  • allow symfony 4.4 (lts)

    allow symfony 4.4 (lts)

    would be great if you allow symfony 4.4 (as it has the same features as 5.0) so if you don't do something 5.1 or 5.2 specific your bundle could be compatible with 4.4

    enhancement 
    opened by c33s 1
  • `api_url` cannot be configured from enviornment

    `api_url` cannot be configured from enviornment

    When setting api_url to use an environment variable api_url: '%env(resolve:UNLEASH_API_URL)%' this error will be triggered.

    Invalid configuration for path "unleash_bundle.api_url": Invalid URL given : "%env(resolve:UNLEASH_API_URL)%\/"
    

    This seems to be caused by the fact that a custom validation closure is set, as symfony does not replace environment variables in configuration, when a custom validation function is beeing used to prevent passing empty values.

    I guess the only solution would be to replace the environment variables in the beforeNormalization function, unfortunately I have no idea how that would work :-(

    bug 
    opened by darookee 1
  • Check global feature status

    Check global feature status

    hi,

    I found out that a deactivated feature (with default strategy) is handled like an activated. And the default Strategy returns always "true". So the Unleash::isFeatureEnabled() method is always true.

    This PR checks the Feature::$enabled Flag and return "false" if the Feature is disabled in Gitlab.

    bug 
    opened by Moki78 1
  • v0.6.1

    v0.6.1

    Features

    • [5548c191ed1cfb4068401fada03453648aadc4c6] add Symfony 6.1 compatibility for console commands

    Changes

    • [ed574d37325da084953cfa85bbcec3e3d0f66fbe] update Github Actions
    opened by jsunier 0
  • v0.6.0

    v0.6.0

    Features

    Fixes

    enhancement 
    opened by jsunier 0
  • Update symfony/http-client-contracts dependency to v3

    Update symfony/http-client-contracts dependency to v3

    When updating to symfony 6, i have an dependency issue when already requiring the latest symfony/http-client package.

    • http-client requires symfony/http-client-contracts ^3 ( https://github.com/symfony/http-client/blob/6.0/composer.json )
    • unleash-bundle requires symfony/http-client-contracts ^2.4
    Your requirements could not be resolved to an installable set of packages.
    
      Problem 1
        - stogon/unleash-bundle is locked to version v0.5.1 and an update of this package was not requested.
        - symfony/http-client[v6.0.0, ..., v6.0.5] require symfony/http-client-contracts ^3 -> satisfiable by symfony/http-client-contracts[v3.0.0].
        - Conclusion: don't install symfony/http-client-contracts v3.0.0 (conflict analysis result)
        - Root composer.json requires symfony/http-client * -> satisfiable by symfony/http-client[v6.0.0, ..., v6.0.5].
    

    With the symfony 6 version bump, all symfony contract bundles are updated to v3 - as far as i can see these are just some php8 related updates.

    So I think, in the composer files the alternate version needs to be added:

        "require": {
            "symfony/cache-contracts": "^2.4|^3.0",
            ...
            "symfony/event-dispatcher-contracts": "^1.1|^2.4|^3.0",
            ...
            "symfony/http-client-contracts": "^2.4|^3.0",
        },
    
    opened by m-idler 0
  • Deprecation notice with `symfony/security-core >= 5.4`

    Deprecation notice with `symfony/security-core >= 5.4`

    The call to $token->isAuthenticated() here https://github.com/Stogon/unleash-bundle/blob/1bf62d9f8a23d039feaa1d1ed4957de3b598da25/src/Unleash.php#L76 cause this deprecation notice with symfony/security-core >= 5.4 :

    User Deprecated: Since symfony/security-core 5.4: Method "Symfony\Component\Security\Core\Authentication\Token\AbstractToken::isAuthenticated()" is deprecated, return null from "getUser()" instead when a token is not authenticated.
    
    deprecation 
    opened by jsunier 0
  • Error after bundle installation from composer

    Error after bundle installation from composer

    symfony@74455d36b45c:/app$ composer require stogon/unleash-bundle
    Using version ^0.2.0 for stogon/unleash-bundle
    ./composer.json has been updated
    Running composer update stogon/unleash-bundle
    Loading composer repositories with package information
    Updating dependencies
    Nothing to modify in lock file
    Installing dependencies from lock file (including require-dev)
    Nothing to install, update or remove
    Generating optimized autoload files
    composer/package-versions-deprecated: Generating version class...
    composer/package-versions-deprecated: ...done generating version class
    110 packages you are using are looking for funding.
    Use the `composer fund` command to find out more!
    
    Run composer recipes at any time to see the status of your Symfony recipes.
    
    Executing script cache:clear [KO]
     [KO]
    Script cache:clear returned with error code 1
    !!  
    !!  In ArrayNode.php line 218:
    !!                                                                                 
    !!    The child config "api_url" under "unleash_bundle" must be configured: Unlea  
    !!    sh API endpoint. URL Must end with a slash !                                 
    !!                                                                                 
    !!  
    !!  
    Script @auto-scripts was called via post-update-cmd
    
    Installation failed, reverting ./composer.json and ./composer.lock to their original content.
    

    This could be fixed by creating a contrib recipe for Symfony Flex.

    bug good first issue help wanted 
    opened by jsunier 0
Releases(v0.6.1)
  • v0.6.1(Nov 21, 2022)

    Features

    • [5548c191ed1cfb4068401fada03453648aadc4c6] add Symfony 6.1 compatibility for console commands

    Changes

    • [ed574d37325da084953cfa85bbcec3e3d0f66fbe] update Github Actions

    Full Changelog: https://github.com/Stogon/unleash-bundle/compare/v0.6.0...v0.6.1

    Source code(tar.gz)
    Source code(zip)
  • v0.6.0(May 26, 2022)

    Features

    Fixes

    Full Changelog: https://github.com/Stogon/unleash-bundle/compare/v0.5.2...v0.6.0

    Source code(tar.gz)
    Source code(zip)
  • v0.5.2(Mar 7, 2022)

    What's Changed

    • [62c3074e2964c895fb6b16db06329731ab446c2e, #18, #19] fix: compatibility with Symfony 6.x (thanks to @m-idler for reporting the issue)

    Full Changelog: https://github.com/Stogon/unleash-bundle/compare/v0.5.1...v0.5.2

    Source code(tar.gz)
    Source code(zip)
  • v0.5.1(Dec 19, 2021)

    What's Changed

    • [2735a64b7d325cb34423e6d7ed0e9b65d992e5d5] fix(log): use LoggerAwareTrait to fix compatibility issues
    • [#15] Add explicit token whether $token equals null by @mvriel

    New Contributors

    • @mvriel made their first contribution in https://github.com/Stogon/unleash-bundle/pull/15

    Full Changelog: https://github.com/Stogon/unleash-bundle/compare/v0.5.0...v0.5.1

    Source code(tar.gz)
    Source code(zip)
  • v0.5.0(Dec 7, 2021)

    Features

    • [f9cbb38a63ed4859f294b3874b7257b23bee6489] add support for Symfony 6.0
    • [2ef98417eb92a1ab216973c3ef9c8ed1de84367f] ci: add PHP 8.1 testing
    • [4abc2e67684c160a407ad9776efe63b9533c0ea5] ci: add testing for lowest and highest dependencies requirements

    Fixes

    • [0a1850e2b8c67f0ffc258aabf59889ee0e200818] fix deprecations for Symfony 5.4

    Full changelog : https://github.com/Stogon/unleash-bundle/compare/v0.4.0...v0.5.0

    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(Oct 29, 2021)

    What's Changed

    • [#11] Add authorization header to http client by @bashilbers
    • [13913668b9b1ee5a86b1af5992c52d8e0d8000c0, #13] Add logging using Psr\Log\LoggerInterface
    • [306df448338fdfb29ea0beae63c9d55a9d78765d, #13] Add support for upcoming Symfony 5.4

    New Contributors

    • @bashilbers made their first contribution in https://github.com/Stogon/unleash-bundle/pull/11

    Full Changelog: https://github.com/Stogon/unleash-bundle/compare/v0.3.3...v0.4.0

    Source code(tar.gz)
    Source code(zip)
  • v0.3.3(Sep 16, 2021)

  • v0.3.2(Sep 14, 2021)

  • v0.3.1(Jul 31, 2021)

  • v0.3.0(Jul 31, 2021)

    Features

    • [127fa4d87bb506ee15583d5582d1bdb10d659c18] Add support for Symfony 4.4 LTS (#5, #6)

    Changes

    • [127fa4d87bb506ee15583d5582d1bdb10d659c18] Switched from Symfony components to Symfony contracts (symfony/*-contracts) for dependencies in composer.json
    Source code(tar.gz)
    Source code(zip)
  • v0.2.1(Jul 31, 2021)

    Changes

    • [e07396274491f078f0c51968dda2c6f6a18ee9c2] docs(README): improved documentation

    Fixes

    • [b6b2a4fb65dd40fc33ed974d434d03e13f4bc989] fix(config): use %unleash.environment% for UNLEASH-APPNAME instead of %kernel.environment% in DependencyInjection/UnleashExtension.php
    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Jul 31, 2021)

  • v0.1.1(May 5, 2021)

  • v0.1.0(May 2, 2021)

Owner
Stogon
Stogon - Network
Stogon
A small library that provides functionality to PHP 8.1 enums to act as BitMask flags

PHP Enum BitMask A small library that provides functionality to PHP 8.1 enums to act as BitMask flags. Why? Sometimes you need some flags on the objec

FramJet 53 Dec 11, 2022
An easy to use Fractal wrapper built for Laravel and Lumen applications

An easy to use Fractal wrapper built for Laravel and Lumen applications The package provides a nice and easy wrapper around Fractal for use in your La

Spatie 1.8k Dec 30, 2022
This bundle provides tools to build a complete GraphQL server in your Symfony App.

OverblogGraphQLBundle This Symfony bundle provides integration of GraphQL using webonyx/graphql-php and GraphQL Relay. It also supports: batching with

Webedia - Overblog 720 Dec 25, 2022
Pure PHP implementation of GraphQL Server – Symfony Bundle

Symfony GraphQl Bundle This is a bundle based on the pure PHP GraphQL Server implementation This bundle provides you with: Full compatibility with the

null 283 Dec 15, 2022
DataTables bundle for Symfony

Symfony DataTables Bundle This bundle provides convenient integration of the popular DataTables jQuery library for realtime Ajax tables in your Symfon

Omines Internetbureau 199 Jan 3, 2023
GraphQL Bundle for Symfony 2.

Symfony 2 GraphQl Bundle Use Facebook GraphQL with Symfony 2. This library port laravel-graphql. It is based on the PHP implementation here. Installat

Sergey Varibrus 35 Nov 17, 2022
Symfony Health Check Bundle Monitoring Project Status

Symfony Health Check Bundle Version Build Status Code Coverage master develop Installation Step 1: Download the Bundle Open a command console, enter y

MacPaw Inc. 27 Jul 7, 2022
A bundle providing routes and glue code between Symfony and a WOPI connector.

WOPI Bundle A Symfony bundle to facilitate the implementation of the WOPI endpoints and protocol. Description The Web Application Open Platform Interf

Champs-Libres 5 Aug 20, 2022
Mediator - CQRS Symfony bundle. Auto Command/Query routing to corresponding handlers.

Installation $ composer require whsv26/mediator Bundle configuration // config/packages/mediator.php return static function (MediatorConfig $config)

Alexander Sv. 6 Aug 31, 2022
Symfony bundle for EventSauce (WIP)

Symfony EventSauce (WIP) This bundle provides the basic and extended container configuration of symfony for the EventSauce library. Before using it, I

Andrew Pakula 8 Dec 19, 2022
Symfony bundle integrating server-sent native notifications

Symfony UX Notify Symfony UX Notify is a Symfony bundle integrating server-sent native notifications in Symfony applications using Mercure. It is part

Symfony 6 Dec 15, 2022
Bundle to integrate Tactician with Symfony projects

TacticianBundle Symfony2 Bundle for the Tactician library https://github.com/thephpleague/tactician/ Installation Step 1: Download the Bundle Open a c

The League of Extraordinary Packages 240 Jan 4, 2023
A Symfony bundle that provides #StandWithUkraine banner and has some built-in features to block access to your resource for Russian-speaking users.

StandWithUkraineBundle На русском? Смотри README.ru.md This bundle provides a built-in StandWithUkraine banner for your Symfony application and has so

Victor Bocharsky 10 Nov 12, 2022
Class helpers for Symfony applications

Micro-Symfony Tools Class helpers for Symfony applications. Installation composer require yceruto/micro-symfony Micro-Bundle Bundles are a very impor

Yonel Ceruto 4 Sep 23, 2022
OpenAPI(v3) Validators for Symfony http-foundation, using `league/openapi-psr7-validator` and `symfony/psr-http-message-bridge`.

openapi-http-foundation-validator OpenAPI(v3) Validators for Symfony http-foundation, using league/openapi-psr7-validator and symfony/psr-http-message

n1215 2 Nov 19, 2021
Fork of Symfony Rate Limiter Component for Symfony 4

Rate Limiter Component Fork (Compatible with Symfony <=4.4) The Rate Limiter component provides a Token Bucket implementation to rate limit input and

AvaiBook by idealista 4 Apr 19, 2022
Enter-to-the-Matrix-with-Symfony-Console - Reproduction of the "Matrix characterfall" effect with the Symfony Console component.

Enter to the Matrix (with Symfony Console) Reproduction of the "Matrix characterfall" effect with the Symfony Console component. Run Clone the project

Yoan Bernabeu 23 Aug 28, 2022
It helps to provide API support to projects. It is Simple, Safe and Fast.

apiservice It helps to provide API support to projects. It is Simple, Safe and Fast. Setup composer create-project mind/apiservice or After downloadin

Ali Yılmaz 5 Nov 3, 2022
Middleware to provide IP filtering

middlewares/firewall Middleware to provide IP filtering using M6Web/Firewall. Requirements PHP >= 7.2 A PSR-7 http library A PSR-15 middleware dispatc

Middlewares 10 Dec 1, 2022