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 Flag Bundle Laravel Package

ajgarlag/feature-flag-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require ajgarlag/feature-flag-bundle
    

    Enable the bundle in config/bundles.php:

    Ajgarlag\FeatureFlagBundle\FeatureFlagBundle::class => ['all' => true],
    
  2. First Feature Flag: Create a simple feature flag class with the #[AsFeature] attribute:

    // src/Feature/XmasFeature.php
    namespace App\Feature;
    
    use Ajgarlag\FeatureFlagBundle\Attribute\AsFeature;
    
    #[AsFeature('xmas')]
    final class XmasFeature {
        public function __invoke(): bool {
            return date('m-d') === '12-25';
        }
    }
    
  3. Usage in Code: Inject the FeatureFlagChecker service and check flags:

    use Ajgarlag\FeatureFlagBundle\FeatureFlagChecker;
    
    class SomeService {
        public function __construct(private FeatureFlagChecker $featureFlagChecker) {}
    
        public function doSomething() {
            if ($this->featureFlagChecker->isEnabled('xmas')) {
                // Enable Christmas logic
            }
        }
    }
    

Implementation Patterns

Common Workflows

  1. Dynamic Feature Toggles: Use #[AsFeature] on methods to dynamically enable/disable logic:

    #[AsFeature('new_ui')]
    public function isNewUIEnabled(): bool {
        return $this->user->hasRole('premium');
    }
    
  2. Context-Aware Flags: Implement a custom ProviderInterface to fetch flags from external sources (e.g., database, API):

    class DatabaseProvider implements ProviderInterface {
        public function get(string $featureName): ?callable {
            return fn() => $this->db->getFlag($featureName, $this->context);
        }
    }
    
  3. Route-Based Feature Gating: Use feature_is_enabled in route conditions to hide/show endpoints:

    #[Route('/admin', condition: "feature_is_enabled('admin_panel')")]
    public function adminDashboard() {}
    
  4. Twig Integration: Conditionally render UI elements:

    {% if feature_is_enabled('dark_mode') %}
        <link rel="stylesheet" href="{{ asset('css/dark.css') }}">
    {% endif %}
    

Integration Tips

  • Dependency Injection: Prefer injecting FeatureFlagChecker over direct service calls for testability.
  • Priority Providers: Use #[AutoconfigureTag] with priority to control provider resolution order.
  • Caching: Cache provider responses (e.g., GitlabProvider) to reduce external API calls.

Gotchas and Tips

Pitfalls

  1. Provider Order: The first provider returning a non-null result wins. Ensure high-priority providers (e.g., database) are last if they should override defaults.

  2. Attribute Naming: Omitting the name in #[AsFeature] uses the FQCN, which can lead to verbose flag names (e.g., App\Feature\XmasFeature).

  3. Route Conditions: feature_is_enabled() in route conditions evaluates at request time, not compile time. Avoid complex logic here.

  4. Testing: Mock FeatureFlagChecker or use a test provider to isolate feature logic:

    $this->featureFlagChecker->shouldReceive('isEnabled')->with('xmas')->andReturn(true);
    

Debugging Tips

  • Check Registered Flags: Dump all available flags via:

    $flags = $this->container->get('feature_flag.checker')->getAllFeatures();
    
  • Provider Debugging: Implement a debug provider to log resolution:

    class DebugProvider implements ProviderInterface {
        public function get(string $featureName): ?callable {
            return fn() => error_log("Checking flag: $featureName");
        }
    }
    

Extension Points

  1. Custom Providers: Extend ChainProvider to add logic (e.g., fallback to defaults if no provider matches).

  2. Attribute Enhancements: Add metadata to #[AsFeature] (e.g., description, defaultValue) via a custom attribute class.

  3. Event Listeners: Trigger events when flags are evaluated (e.g., for analytics):

    $dispatcher->addListener('feature_flag.checked', fn($event) => $this->logFlagCheck($event));
    
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity