GithubHelp home page GithubHelp logo

juststeveking / laravel-feature-flags Goto Github PK

View Code? Open in Web Editor NEW
173.0 3.0 13.0 251 KB

I recommend using laravel/pennant for any future Feature Flag needs. This package will be frozen as is with no updates planned.

License: MIT License

PHP 100.00%

laravel-feature-flags's Introduction

Laravel Feature Flags

Software License PHP Version Run Tests Latest Version on Packagist Total Downloads

I recommend using laravel/pennant for any future Feature Flag needs. This package will be frozen as is with no updates planned.

A simple to use Feature Flag package for Laravel, allowing you to create Feature Groups and assign Users to them - while also being able to give users override access to given features outside of their groups.

Installation

You can install the package via composer:

composer require juststeveking/laravel-feature-flags

You can publish the migrations files with:

php artisan vendor:publish --provider="JustSteveKing\Laravel\FeatureFlags\FeatureFlagsServiceProvider" --tag="migrations"

You can publish the config file with:

php artisan vendor:publish --provider="JustSteveKing\Laravel\FeatureFlags\FeatureFlagsServiceProvider" --tag="config"

This is the contents of the published config file:

return [
    'middleware' => [
        'mode' => 'abort',

        'redirect_route' => '/',

        'status_code' => 404,
    ],
    
    'enable_time_bombs' => false,
    
    'time_bomb_environments' => ['production']
];

You will then need to migrate the database changes:

php artisan migrate

Usage

This package allows you to manage user features and feature groups in a database.

All Feature and Feature Group names will be normalised to lower case on save.

To use this package your User model needs to have the HasFeatures trait:

<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use JustSteveKing\Laravel\FeatureFlags\Concerns\HasFeatures;

class User extends Authenticatable
{
    use HasFeatures;
}

This will allow you to manage features and feature groups on your user model.

A User can belong to many Feature Groups, but can also be assigned access to specific Features.

Working with Feature Groups

// This will create the Feature Group if not already created and attach the user to it.
auth()->user()->addToGroup('beta testers');

// Alternatively you can use the following syntax
auth()->user()->joinGroup('beta testers');

// You can check if a user is a member of a feature group
auth()->user()->inGroup('beta testers');

// You can also get a user to leave a feature group
auth()->user()->leaveGroup('beta testers');

// You can also pass in more than one group name
auth()->user()->joinGroup('beta testers', 'api testers');

Working with Features

// This will create the Feature if not already created and attach the user to it.
auth()->user()->giveFeature('run reports');

// You can check if a user has a specific feature
auth()->user()->hasFeature('run reports');

// You can also remove a feature for a user
auth()->user()->removeFeature('run reports');

// Like with Feature Groups you can pass in more than one option
// These will return if any are matched.
auth()->user()->hasFeature('run reports', 'admin');

Putting it together

To use the package as a whole:

// Create a Feature Group
$group = FeatureGroup::create([
    'name' => 'Beta Testers'
]);

// Create a Feature
$feature = Feature::create([
    'name' => 'API Access'
]);

// Add the Feature to the Feature Group
$group->addFeature($feature);

// Assign a User to the Group
auth()->user()->joinGroup($group->name);

if (auth()->user()->groupHasFeature('api access')) {
    // The user belongs to a group that has access to this feature.
}

if (auth()->user()->hasFeature('run reports')) {
    // The user has been given access to this feature outside of group features
}

if (auth()->user()->hasFeature('user level feature')) {
    // The user has access to this feature as a user or through a group.
}

Timebombs for Features

A common use case for Feature Flags is to allow developers to add new functionality without breaking existing code.

This process is great when paired with a solid CI/CD pipeline. But the biggest drawback to this is residual technical debt that can occur when developers forget about removing implemented flags across a code base.

To handle this, users of this package can utilise Timebombs! Timebombs are used to cause Feature Flags to throw an exception when a flag should have been removed from the code base.

To use Timebombs, you will need to explicitly enable them within the config ('enable_time_bombs' => true). And define which environments you do not want exceptions to be thrown. (This is particularly useful with CI/CD, as you will want to throw exceptions locally, in CI and on staging environments but NOT on production).

Defining when a timebomb should throw an exception

Once Timebombs are enabled, when creating a new Flag, you will be asked when you want your flag to expire (This is number of days). When the current time surpasses that expiration date, then your feature flag will throw an exception.

To extend a flag, you can use the handy command

php artisan feature-flags:extend-feature

Where you will be prompted to define how many more days are required before the flag should throw an exception again.

Further reading

To learn more on Feature flags and Timebombs, there is a great article by Martin Fowler Here.

Template Usage

There are some Blade Directives to help control access to features in your UI:

// You can check if a user has a specific feature
@feature('api access')
    <x-api-console />
@endfeature

// You can check if a user is a member of a feature group
@featuregroup('beta testers')
    <x-group-feature />
@endfeaturegroup

// You can check if a user is a member of a group with access to a feature
@groupfeature('api access')
    <x-api-console />
@endgroupfeature

Middleware

There are some middleware classes that you can use:

By default you can use:

  • \JustSteveKing\Laravel\FeatureFlags\Http\Middleware\FeatureMiddleware::class
  • \JustSteveKing\Laravel\FeatureFlags\Http\Middleware\GroupMiddleware::class

There 2 middleware classes will either abort on failure, or redirect. The way these work can be managed in the config file for the package. It allows you to set a mode for the middleware (either abort or redirect) and also allows you to set a redirect_route or status_code.

Then there is also:

  • \JustSteveKing\Laravel\FeatureFlags\Http\Middleware\API\FeatureMiddleware::class
  • \JustSteveKing\Laravel\FeatureFlags\Http\Middleware\API\GroupMiddleware::class

These 2 middleware classes only have the one mode of abort but will ready from your config file for the package to know what status code to return, these classes are made specifically for APIs.

To limit access to users with specific features

Add the following to your app/Http/Kernel.php

protected $routeMiddleware = [
    'feature' => \JustSteveKing\Laravel\FeatureFlags\Http\Middleware\FeatureMiddleware::class,
];

You can pass through more than one feature name, and pass them in a friendlier format or as they are:

Route::middleware(['feature:run-reports,print reports'])->group(/* */);

To limit access to users who are part of a feature group

Add the following to your app/Http/Kernel.php

protected $routeMiddleware = [
    'feature-group' => \JustSteveKing\Laravel\FeatureFlags\Http\Middleware\GroupMiddleware::class,
];

You can pass through more than one feature group name, and pass them in a friendlier format or as they are:

Route::middleware(['feature-group:beta-testers,internal,developer advocates'])->group(/* */);

Artisan Commands

There are a number of artisan commands available for interacting with feature flags.

  feature-flags:activate-feature           Activates a feature
  feature-flags:activate-feature-group     Activates a feature group
  feature-flags:add-feature                Add a new feature
  feature-flags:add-feature-group          Add a new feature group
  feature-flags:add-feature-to-group       Add a feature to a group
  feature-flags:deactivate-feature         Deactivates a feature
  feature-flags:deactivate-feature-group   Deactivates a feature group
  feature-flags:view-feature-groups        View feature groups
  feature-flags:view-features              View features
  feature-flags:view-groups-with-features  View groups with features

Testing

$ composer run test

Contributing

Please see CONTRIBUTING and CODE_OF_CONDUCT for details.

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.

laravel-feature-flags's People

Contributors

aidanlaycock avatar hajmo avatar juststeveking avatar laravel-shift avatar mrailton avatar simensen avatar thinkverse avatar zaherg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

laravel-feature-flags's Issues

routeMiddlewares -> str_replace

Hi,

I believe there is a bug on both FeatureMiddleware and GroupMiddleware: str_replace params are out of order, it should be:

GroupMiddleware:
$group = str_replace('-', ' ', $group);

FeatureMiddleware:
$feature = str_replace('-', ' ', $feature);

Would it be possible to publish the migrations versus running them automatically?

I have an older model/schema that is unable to run the default migration scripts. It uses $table->increments('id') instead of $table->bigIncrements('id') and this causes the migration to fail for my application.

The "correct" solution for me is probably to go through and upgrade all the columns to be using bigints, but I was hoping to not have to worry about that just yet.

Is there another workaround to get the migrations to not run automatically?

User::inGroup() doesn’t work as expected

Based on the joinGroup()/addToGroup() and leaveGroup() methods and the inGroup() name, I would expect inGroup() to return true/false based on whether the user is in the given group(s):

$group = FeatureGroup::create([
  'name' => 'beta-testers',
]);

$user = User::first();

// Current behavior:
$user->inGroup('beta-testers'); // returns true; I would expect it to be false
$user->joinGroup('beta-testers');
$user->inGroup('beta-testers'); // returns true, as expected
$user->leaveGroup('beta-testers');
$user->inGroup('beta-testers'); // returns true; I would expect it to be false

Is this the desired behavior? Or is it a bug?

Idea: Optionally registering a view for Features

Hi!

I was wondering what your thoughts are on providing an option to register a view to see the Feature flags/groups etc that are currently implemented across the code base as well as showing the users within the group. As well as showing when a feature should expire through timebombs.

And potentially a longer term feature to add the ability for users to be able to manage who is in feature groups via the UI.

I'm happy to work on this over the next few weeks and to contribute a PR for it, but I'd love to get some feedback to see if it would be useful/if there are any additional bits of functionality that would be useful.

Idea: Time Bomb on Features

Hi, I was wondering what your opinion was on adding a time bomb (Expiry date) on features so that developers could create expiring features that would trigger an exception during CI to notify them of any missed features that require removing.

See this article - https://martinfowler.com/articles/feature-toggles.html (Section: Managing the carrying cost of Feature Toggles
) which talks about this.

Support Laravel 10

Hey @JustSteveKing
I was wondering if you are planning to support Laravel 10, if thats something you want I can try sending you a PR that will add L10 support (if I am not mistaken those are small changes in composer side nothing big)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.