Installation
composer require ericdowell/feature-toggle
Publish the config file:
php artisan vendor:publish --provider="EricDowell\FeatureToggle\FeatureToggleServiceProvider" --tag="config"
Basic Configuration
Edit config/feature-toggle.php to define your toggles:
'toggles' => [
'new-ui' => [
'enabled' => env('FEATURE_NEW_UI_ENABLED', false),
'description' => 'Enable the new user interface',
],
'beta-invitations' => [
'enabled' => env('FEATURE_BETA_INVITATIONS_ENABLED', false),
'description' => 'Allow beta program invitations',
],
],
First Usage Check a toggle in a controller or blade view:
if (FeatureToggle::isEnabled('new-ui')) {
// Render new UI
}
// In a controller
$isNewUIEnabled = FeatureToggle::isEnabled('new-ui', request()->ip());
// In Blade
@if(FeatureToggle::isEnabled('beta-invitations'))
<a href="/beta-invite">Invite Friends</a>
@endif
Default Evaluation
// Simple boolean check
if (FeatureToggle::isEnabled('new-ui')) {
// ...
}
Context-Aware Evaluation
// User-specific toggle
$userId = auth()->id();
if (FeatureToggle::isEnabled('premium-features', $userId)) {
// ...
}
// IP-based toggle (for A/B testing)
if (FeatureToggle::isEnabled('new-checkout', request()->ip())) {
// ...
}
Fallback Logic
// Graceful fallback
$isEnabled = FeatureToggle::isEnabled('experimental-feature', auth()->id(), false);
Middleware for Route Protection
// app/Http/Middleware/FeatureToggleMiddleware.php
public function handle($request, Closure $next) {
if (!FeatureToggle::isEnabled('admin-dashboard')) {
abort(403);
}
return $next($request);
}
Service Layer Abstraction
// app/Services/FeatureService.php
public function shouldShowNewFeature(User $user) {
return FeatureToggle::isEnabled('new-feature', $user->id);
}
Blade Directives
// app/Providers/BladeServiceProvider.php
Blade::directive('toggle', function ($expression) {
return "<?php if (\\FeatureToggle::isEnabled({$expression})): ?>";
});
Usage:
@toggle('new-ui')
<div>New UI Content</div>
@endtoggle
Event-Based Toggle Management
// Listen for toggle changes
event(new FeatureToggleEnabled('new-ui'));
Dynamic Toggle Loading
// Load toggles from a remote service
FeatureToggle::loadFromRemote('https://api.example.com/feature-flags');
Percentage-Based Rollouts
// 10% rollout
if (FeatureToggle::isEnabled('new-algorithm', request()->ip(), 0.1)) {
// ...
}
Multi-Context Evaluation
// Combine user and device context
$context = [
'user_id' => auth()->id(),
'device_type' => request()->userAgent(),
];
if (FeatureToggle::isEnabled('personalized-experience', $context)) {
// ...
}
Cache Invalidation
php artisan config:clear
'cache' => false,
Context Collisions
user_id) for different toggle types.FeatureToggle::isEnabled('feature', ['user_id' => 1, 'type' => 'premium']);
Environment Overrides
.env overrides may not reflect immediately in cached configs.php artisan config:cache after changes or disable caching.Percentage Rollouts
FeatureToggle::isEnabled('feature', null, 0.5, true); // Force 50% (no randomness)
Inspect Toggle Values
// Dump all toggles
dd(FeatureToggle::getAllToggles());
// Check a specific toggle's config
dd(FeatureToggle::getToggleConfig('new-ui'));
Logging Evaluation
// Enable debug logging
config(['feature-toggle.debug' => true]);
// Check logs for evaluation details
Context Validation
DateTime) will cause issues.Custom Storage Backends
EricDowell\FeatureToggle\Contracts\ToggleStore:
class DatabaseToggleStore implements ToggleStore {
public function get($name) { ... }
public function all() { ... }
}
AppServiceProvider:
FeatureToggle::extend('database', function () {
return new DatabaseToggleStore();
});
Custom Context Resolvers
FeatureToggle::resolveContext(function ($context) {
if (is_string($context)) {
return ['user_id' => $context];
}
return $context;
});
Event Listeners
FeatureToggle::listen(function ($toggleName, $enabled) {
Log::info("Toggle {$toggleName} set to {$enabled}");
});
Disable Caching for Dynamic Toggles
'cache' => env('FEATURE_TOGGLE_CACHE', true),
Batch Context Evaluation
// Evaluate multiple toggles at once
$results = FeatureToggle::batch([
'toggle1' => ['context' => $context1],
'toggle2' => ['context' => $context2],
]);
Lazy-Load Remote Toggles
// Load only when needed
if (FeatureToggle::isRemoteToggle('new-ui')) {
FeatureToggle::loadRemoteToggle('new-ui');
}
Boolean Parsing
'true'/'false' are parsed as booleans, but null or 0 may behave unexpectedly.enabled to false instead of null.Default Values
false. Override in config:
'default' => true, // All unknown toggles return true
Case Sensitivity
define('TOGGLE_NEW_UI', 'new-ui');
How can I help you explore Laravel packages today?