Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Feature Toggle Laravel Package

ericdowell/feature-toggle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require ericdowell/feature-toggle
    

    Publish the config file:

    php artisan vendor:publish --provider="EricDowell\FeatureToggle\FeatureToggleServiceProvider" --tag="config"
    
  2. 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',
        ],
    ],
    
  3. First Usage Check a toggle in a controller or blade view:

    if (FeatureToggle::isEnabled('new-ui')) {
        // Render new UI
    }
    

First Use Case: A/B Testing

// 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

Implementation Patterns

Toggle Evaluation Workflows

  1. Default Evaluation

    // Simple boolean check
    if (FeatureToggle::isEnabled('new-ui')) {
        // ...
    }
    
  2. 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())) {
        // ...
    }
    
  3. Fallback Logic

    // Graceful fallback
    $isEnabled = FeatureToggle::isEnabled('experimental-feature', auth()->id(), false);
    

Integration Patterns

  1. 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);
    }
    
  2. Service Layer Abstraction

    // app/Services/FeatureService.php
    public function shouldShowNewFeature(User $user) {
        return FeatureToggle::isEnabled('new-feature', $user->id);
    }
    
  3. 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
    
  4. Event-Based Toggle Management

    // Listen for toggle changes
    event(new FeatureToggleEnabled('new-ui'));
    

Advanced Patterns

  1. Dynamic Toggle Loading

    // Load toggles from a remote service
    FeatureToggle::loadFromRemote('https://api.example.com/feature-flags');
    
  2. Percentage-Based Rollouts

    // 10% rollout
    if (FeatureToggle::isEnabled('new-algorithm', request()->ip(), 0.1)) {
        // ...
    }
    
  3. Multi-Context Evaluation

    // Combine user and device context
    $context = [
        'user_id' => auth()->id(),
        'device_type' => request()->userAgent(),
    ];
    if (FeatureToggle::isEnabled('personalized-experience', $context)) {
        // ...
    }
    

Gotchas and Tips

Common Pitfalls

  1. Cache Invalidation

    • Toggles are cached by default. Clear cache after config changes:
      php artisan config:clear
      
    • For dynamic toggles, disable caching in config:
      'cache' => false,
      
  2. Context Collisions

    • Avoid using the same context key (e.g., user_id) for different toggle types.
    • Fix: Use composite contexts:
      FeatureToggle::isEnabled('feature', ['user_id' => 1, 'type' => 'premium']);
      
  3. Environment Overrides

    • .env overrides may not reflect immediately in cached configs.
    • Fix: Use php artisan config:cache after changes or disable caching.
  4. Percentage Rollouts

    • Randomness is seeded by default. For deterministic testing:
      FeatureToggle::isEnabled('feature', null, 0.5, true); // Force 50% (no randomness)
      

Debugging Tips

  1. Inspect Toggle Values

    // Dump all toggles
    dd(FeatureToggle::getAllToggles());
    
    // Check a specific toggle's config
    dd(FeatureToggle::getToggleConfig('new-ui'));
    
  2. Logging Evaluation

    // Enable debug logging
    config(['feature-toggle.debug' => true]);
    
    // Check logs for evaluation details
    
  3. Context Validation

    • Ensure contexts are serializable (arrays, strings, numbers).
    • Error: Non-serializable objects (e.g., DateTime) will cause issues.
    • Fix: Convert contexts to strings or use supported types.

Extension Points

  1. Custom Storage Backends

    • Implement EricDowell\FeatureToggle\Contracts\ToggleStore:
      class DatabaseToggleStore implements ToggleStore {
          public function get($name) { ... }
          public function all() { ... }
      }
      
    • Bind in AppServiceProvider:
      FeatureToggle::extend('database', function () {
          return new DatabaseToggleStore();
      });
      
  2. Custom Context Resolvers

    • Override context resolution:
      FeatureToggle::resolveContext(function ($context) {
          if (is_string($context)) {
              return ['user_id' => $context];
          }
          return $context;
      });
      
  3. Event Listeners

    • Listen for toggle changes:
      FeatureToggle::listen(function ($toggleName, $enabled) {
          Log::info("Toggle {$toggleName} set to {$enabled}");
      });
      

Performance Tips

  1. Disable Caching for Dynamic Toggles

    'cache' => env('FEATURE_TOGGLE_CACHE', true),
    
  2. Batch Context Evaluation

    // Evaluate multiple toggles at once
    $results = FeatureToggle::batch([
        'toggle1' => ['context' => $context1],
        'toggle2' => ['context' => $context2],
    ]);
    
  3. Lazy-Load Remote Toggles

    // Load only when needed
    if (FeatureToggle::isRemoteToggle('new-ui')) {
        FeatureToggle::loadRemoteToggle('new-ui');
    }
    

Configuration Quirks

  1. Boolean Parsing

    • Strings 'true'/'false' are parsed as booleans, but null or 0 may behave unexpectedly.
    • Fix: Explicitly set enabled to false instead of null.
  2. Default Values

    • If a toggle is not found, it defaults to false. Override in config:
      'default' => true, // All unknown toggles return true
      
  3. Case Sensitivity

    • Toggle names are case-sensitive. Use constants or strings consistently:
      define('TOGGLE_NEW_UI', 'new-ui');
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle