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

Openfeature Bundle Laravel Package

aubes/openfeature-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install the Bundle:

    composer require aubes/openfeature-bundle
    

    Register the bundle in config/bundles.php:

    Aubes\OpenFeatureBundle\OpenFeatureBundle::class => ['all' => true],
    
  2. Configure Flags (e.g., config/packages/open_feature.yaml):

    open_feature:
        flags:
            new_checkout: true
            dark_mode: false
            max_items: 10
    
  3. Use in a Controller (attribute-based):

    use Aubes\OpenFeatureBundle\Attribute\FeatureFlag;
    use Aubes\OpenFeatureBundle\Attribute\FeatureGate;
    
    class CheckoutController {
        #[FeatureGate('new_checkout')] // Blocks if flag is off
        public function checkout(
            #[FeatureFlag('dark_mode')] bool $darkMode,
            #[FeatureFlag('max_items')] int $maxItems,
        ): Response {
            return new Response("Dark mode: $darkMode, Max items: $maxItems");
        }
    }
    
  4. Use in Twig:

    {% if feature('new_checkout') %}
        {# New checkout UI #}
    {% endif %}
    

First Use Case

Kill Switch for a Feature:

  • Define a flag in open_feature.yaml:
    open_feature:
        flags:
            experimental_api: false
    
  • Guard a controller method:
    #[FeatureGate('experimental_api')]
    public function experimentalEndpoint(): Response { ... }
    
  • Toggle via config or provider (e.g., EnvVar) without redeploying.

Implementation Patterns

Workflows

  1. Attribute-Based Injection:

    • Use #[FeatureFlag] for typed flag values (e.g., bool, int, string).
    • Use #[FeatureGate] to block execution if a flag is off.
    • Example:
      #[FeatureGate('feature_x')]
      public function sensitiveAction(
          #[FeatureFlag('timeout_ms')] int $timeout,
      ): void { ... }
      
  2. Service Integration:

    • Inject Client for programmatic access:
      use OpenFeature\interfaces\flags\Client;
      
      class MyService {
          public function __construct(private readonly Client $client) {}
      
          public function checkFlag(): bool {
              return $this->client->getBooleanValue('feature_x', false);
          }
      }
      
  3. Evaluation Context:

    • Implement EvaluationContextProviderInterface to feed dynamic attributes (e.g., user ID, region):
      use Aubes\OpenFeatureBundle\Context\EvaluationContextProviderInterface;
      
      class UserContextProvider implements EvaluationContextProviderInterface {
          public function getContext(): array {
              return ['user_id' => $this->userService->getId()];
          }
      }
      
    • Register via autoconfiguration (no manual tags needed in Symfony 6.4+).
  4. Hooks for Observability:

    • Implement Hook for logging/tracing:
      use OpenFeature\interfaces\hooks\Hook;
      
      class LoggingHook implements Hook {
          public function onFlagEvaluated(string $flagKey, mixed $value): void {
              \Log::info("Flag $flagKey resolved to: " . json_encode($value));
          }
      }
      
    • Autoconfigured via openfeature.hook tag (Symfony auto-detects services).
  5. Provider Migration:

    • Start with InMemoryProvider (dev) or EnvVarProvider (bootstrap):
      open_feature:
          provider: env_var  # Uses env vars like `FEATURE_NEW_CHECKOUT=true`
      
    • Switch to Flagd or ConfigCat later by updating the provider config:
      open_feature:
          provider: flagd
          flagd:
              url: http://flagd:8080
      

Integration Tips

  • FrankenPHP: Safe out-of-the-box. The EvaluationContextListener ensures context resets per request.
  • Redis Provider: Use for shared toggles across instances:
    open_feature:
        provider: redis
        redis:
            dsn: redis://redis:6379
    
  • Twig: Prefer feature_value() for defaults:
    {{ feature_value('max_items', 10) }}  {# Falls back to 10 if flag is missing #}
    
  • Testing: Mock the Client in tests:
    $this->container->set('open_feature.client', $this->createMock(Client::class));
    

Gotchas and Tips

Pitfalls

  1. Built-in Providers Are Limited:

    • InMemoryProvider/EnvVarProvider ignore EvaluationContext (no user targeting, rollouts).
    • Fix: Use a real provider (Flagd/ConfigCat) for production.
  2. Double Hook Registration:

    • If a Hook service has both autoconfigure: true and tags: [openfeature.hook], it fires twice.
    • Fix: Remove explicit tags in Symfony 6.4+ (autoconfiguration handles it).
  3. Context Leakage in Long-Running Runtimes:

    • FrankenPHP/workers may retain stale contexts between requests.
    • Fix: The EvaluationContextListener resets contexts per request (verified in 0.1.1+).
  4. Attribute Parsing Overhead:

    • #[FeatureFlag] adds reflection overhead. Avoid overusing on performance-critical paths.
    • Fix: Use direct Client injection for hot paths.
  5. Redis Provider Key Format:

    • Flags are stored as openfeature:{flag_key} in Redis.
    • Fix: Ensure your Redis config matches the expected prefix.

Debugging

  • Symfony Profiler: Check the "OpenFeature" panel for:
    • Evaluated flags and their values.
    • Provider metadata (e.g., "Flagd" vs. "InMemory").
    • Evaluation context (user attributes, etc.).
  • Logs: Enable OpenFeature\SDK logging in config/packages/dev/monolog.yaml:
    monolog:
        handlers:
            main:
                processors:
                    - OpenFeature\SDK\Logging\LogFlagEvaluationsProcessor
    
  • Flag Not Found?:
    • Verify the flag key matches exactly (case-sensitive).
    • Check if the provider is initialized (e.g., Redis connection issues).

Extension Points

  1. Custom Providers:
    • Implement OpenFeature\interfaces\flags\Provider and register via config:
      open_feature:
          provider: custom_provider
          custom_provider:
              class: App\OpenFeature\CustomProvider
      
  2. Dynamic Context Providers:
    • Implement EvaluationContextProviderInterface for runtime context (e.g., request-based):
      class RequestContextProvider implements EvaluationContextProviderInterface {
          public function __construct(private RequestStack $requestStack) {}
      
          public function getContext(): array {
              $request = $this->requestStack->getCurrentRequest();
              return ['ip' => $request->getClientIp()];
          }
      }
      
  3. Hooks for Validation:
    • Use RegexpValidatorHook to validate flag values:
      services:
          App\OpenFeature\Hooks\RegexpValidatorHook:
              tags: [openfeature.hook]
              arguments:
                  $pattern: '^[a-z0-9_-]+$'
      
  4. Provider Fallbacks:
    • Chain providers for resilience:
      open_feature:
          provider: flagd
          fallback_provider: env_var  # Falls back to env vars if Flagd fails
      
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.
cadot.eu/make
besmartand-pro/php-quality-config
sentix/ai-chatbot
codifyo/ts-generator-bundle
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
christhompsontldr/laravel-inky