Laravel Bento
, (*1)
Bento helps you organize feature launches by custom user segments.
Create and organize rules to make features available to certain users., (*2)
Define your features, define your segmentation strategies and let Bento launch each feature to the right people. Bento can also help you run A/B testing on your applications., (*3)
The core concepts of this library are inspired by Airbnb's Trebuchet project for Ruby., (*4)
Installation
Require this package with composer:, (*5)
composer require eXolnet/laravel-bento
After installing Bento, publish its example service provider to hold your feature definitions:, (*6)
php artisan vendor:publish --tag=bento-provider
Then, add it to the providers
array in config/app.php
:, (*7)
App\Providers\BentoServiceProvider::class
Usage
Create Features
Define features and their launch segmentation strategies. You can define one strategy with the feature
method:, (*8)
Bento::feature('feature')->visitorPercent(10);
Or you can combine multiple strategies:, (*9)
Bento::feature('feature')->visitorPercent(10)->hostname('example.com');
Your features could be grouped in the boot
method of a service provider:, (*10)
<?php
namespace App\Providers;
use Exolnet\Bento\Facades\Bento;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* @return void
*/
public function boot(): void
{
Bento::feature('foo')->everyone();
Bento::feature('bar')->everyone();
}
}
Launch Your Features
You can check if a feature is launched for a visitor with the launch
method:, (*11)
if (Bento::launch('feature')) {
//
}
Or check that a feature is awaiting launch:, (*12)
if (Bento::await('feature')) {
//
}
Blade
In Blade templates, handy macros are also available:, (*13)
@launch('feature')
Feature is launched!
@else
Coming soon!
@endlaunch
@await('feature')
Coming soon!
@else
Feature is launched!
@endawait
Middleware
Since some strategy requires the request context to be evaluated, it's recommended to use middleware to limit a route:, (*14)
- Add the following middleware in the
$routeMiddleware
of your application's HTTP Kernel:
protected $routeMiddleware = [
// ...
'await' => \Exolnet\Bento\Middleware\Await::class,
'launch' => \Exolnet\Bento\Middleware\Launch::class,
// ...
];
- Then, you could use them to restrict your routes:
Route::middleware('launch:feature')->group(function () {
//
});
Route::middleware('await:feature')->group(function () {
//
});
Basic Segmentation Strategies
The following segmentation strategies are available to help quickly target your users:, (*15)
- Callback
- Config
- Date
- Environment
- Everyone
- Guest
- Hostname
- Nobody
- Stub
- User (authenticated or specific user IDs)
- User Percent (a fraction of all connected visitors)
- Visitor Percent (a fraction of all your visitors)
Logic Segmentation Strategies
Additional logic segmentation strategies are available to help target your users with more complex rules., (*16)
Not
Bento::feature('feature')->not->everyone();
All
use \Exolnet\Bento\Strategy\AimsStrategies;
Bento::feature('feature')->all(function (AimsStrategies $aims) {
$aims
->environment('production')
->visitorPercent(20);
});
Any
use \Exolnet\Bento\Strategy\AimsStrategies;
Bento::feature('feature')->any(function (AimsStrategies $aims) {
$aims
->environment('staging')
->user([1, 2]);
});
Custom Segmentation Strategies
You can create custom strategies with dependency injection support similarly to Laravel Controllers' method injection. A common use-case for method injection is injecting the Illuminate\Contracts\Auth\Guard
instance into your strategy to target users by property:, (*17)
Callback
use Illuminate\Contracts\Auth\Guard;
Bento::feature('feature')->custom(function (Guard $guard, $role) {
return $guard->user() && $guard->user()->role === 'admin';
});
Class
use Illuminate\Contracts\Auth\Guard;
class RoleStrategy {
/**
* @var \Illuminate\Contracts\Auth\Guard
*/
protected $guard;
/**
* @var string
*/
protected $role;
/**
* @param \Illuminate\Contracts\Auth\Guard $guard
*/
public function __construct(Guard $guard, string $role)
{
$this->guard = $guard;
$this->role = $role;
}
/**
* @return bool
*/
public function launch(): bool
{
return $this->guard->user() && $this->guard->user()->role === $this->role;
}
}
Bento::feature('feature')->aim(RoleStrategy::class, 'admin');
Testing
To run the PHPUnit tests, please use:, (*18)
bash
$ composer test
, (*19)
Contributing
Please see CONTRIBUTING and CODE OF CONDUCT for details., (*20)
Security
If you discover any security related issues, please email security@exolnet.com instead of using the issue tracker., (*21)
Credits
License
Copyright © eXolnet. All rights reserved., (*22)
This code is licensed under the MIT license.
Please see the license file for more information., (*23)