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

Shizuku Feature Flags Laravel Package

devexploris/shizuku-feature-flags

Symfony bundle to manage feature flags stored in Doctrine ORM. Toggle features from the database, check flags in PHP via FeatureFlagService or in Twig with the feature() function, and manage flags with CLI commands to list, create, enable, and disable.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps for Laravel Integration

  1. Install via Composer (with abstraction layer):

    composer require devexploris/shizuku-feature-flags
    

    Note: Requires Symfony components; use a facade to bridge Laravel/Symfony.

  2. Create a Laravel Service Wrapper (app/Services/FeatureFlagService.php):

    namespace App\Services;
    
    use Devexploris\ShizukuFeatureFlags\Service\FeatureFlagService as SymfonyFlagService;
    use Illuminate\Support\Facades\Cache;
    
    class FeatureFlagService
    {
        public function __construct(private SymfonyFlagService $symfonyFlags) {}
    
        public function isEnabled(string $flag): bool
        {
            return $this->symfonyFlags->isEnabled($flag);
        }
    }
    
  3. Register the Bundle in Laravel (via config/app.php or a custom bootloader):

    // In a service provider's boot method
    $this->app->register(\Devexploris\ShizukuFeatureFlags\ShizukuFeatureFlagsBundle::class);
    
  4. Generate and Run Migrations (adapt Doctrine schema to Eloquent):

    php artisan doctrine:migrations:diff  # Requires Laravel Doctrine bridge
    php artisan migrate
    
  5. First Use Case: Check a flag in a Laravel controller:

    use App\Services\FeatureFlagService;
    
    class MyController extends Controller
    {
        public function __construct(private FeatureFlagService $flags) {}
    
        public function index()
        {
            if ($this->flags->isEnabled('new_ui')) {
                return view('ui.new');
            }
            return view('ui.old');
        }
    }
    

Implementation Patterns

Core Workflows

1. Flag Management CLI

  • Create Flags: Use Artisan commands with Laravel’s interactive prompts:
    php artisan shizuku:flag:create --name=payment_v2 --description="New payment processor" --enable
    
  • Bulk Operations: Extend commands to support Laravel collections (e.g., enable/disable flags for a user segment via middleware).

2. Environment-Specific Flags

  • Config-Based Overrides: Use Laravel’s config/flags.php to map flags to environments:
    'flags' => [
        'dark_mode' => [
            'dev' => true,
            'staging' => false,
            'production' => env('FEATURE_DARK_MODE', false),
        ],
    ],
    
  • Cache Key Scoping: Extend FeatureFlagService to include environment in cache keys:
    $cacheKey = "flags:{$flag}:env:{app()->environment()}";
    

3. Twig Replacement: Blade Directives

  • Register a Blade directive in AppServiceProvider:
    Blade::directive('feature', function ($flag) {
        return "<?php echo app(\\App\\Services\\FeatureFlagService::class)->isEnabled({$flag}) ? 'true' : 'false'; ?>";
    });
    
  • Usage in Blade:
    @if(feature('new_ui'))
        <div class="ui-v2">...</div>
    @endif
    

4. Profiler Integration

  • Replace Symfony Profiler with Laravel Debugbar:
    use Debugbar;
    
    Debugbar::info([
        'feature_flags' => [
            'checked' => $this->flags->getCheckedCount(),
            'enabled' => $this->flags->getEnabledCount(),
            'locked' => $this->flags->getLockedFlags(),
        ],
    ]);
    

5. Event-Driven Flag Updates

  • Listen for flag changes via Doctrine events (adapted to Eloquent):
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Support\Facades\Cache;
    
    Model::observe(Flag::class, function ($flag) {
        Cache::forget("flags:{$flag->name}");
    });
    

Integration Tips

  • Cache Configuration: Override the cache pool in Laravel’s config/cache.php:

    'default' => env('CACHE_DRIVER', 'redis'),
    

    Then bind it to the Symfony service:

    # config/services.yaml (if using Symfony config)
    Devexploris\ShizukuFeatureFlags\Service\FeatureFlagService:
        arguments:
            $cache: '@cache.connector'
    
  • Testing: Mock FeatureFlagService in Laravel tests:

    $this->mock(FeatureFlagService::class)->shouldReceive('isEnabled')
        ->with('payment_v2')->andReturn(true);
    
  • Multi-Tenancy: Scope flags to tenants via middleware:

    public function handle($request, Closure $next)
    {
        $tenant = auth()->user()->tenant;
        app(FeatureFlagService::class)->setTenant($tenant);
        return $next($request);
    }
    

Gotchas and Tips

Pitfalls

  1. Doctrine vs. Eloquent Schema Mismatch:

    • Issue: Doctrine’s DateTimeImmutable vs. Laravel’s Carbon. Fix by casting in the facade:
      public function getLockedAt(): ?\Carbon\Carbon
      {
          return $this->symfonyFlag->lockedAt?->toDateTimeString() ?? null;
      }
      
    • Tip: Use a migration to convert the database schema to Eloquent-compatible types.
  2. Cache Invalidation Bypass:

    • Issue: Direct database edits (e.g., via raw SQL) bypass cache invalidation.
    • Fix: Use Eloquent events or a queue job to invalidate cache after manual changes:
      Flag::updated(function ($flag) {
          Cache::forget("flags:{$flag->name}");
      });
      
  3. Console Command Conflicts:

    • Issue: Artisan commands may clash with Symfony’s CLI namespace.
    • Fix: Alias commands in artisan:
      // In AppServiceProvider
      Artisan::alias('shizuku:flag:create', 'make:flag');
      
  4. Twig Dependency:

    • Issue: The bundle assumes Twig; Blade requires custom directives.
    • Tip: Use the feature() directive (above) or a helper class:
      class FeatureHelper {
          public static function check(string $flag): bool
          {
              return app(FeatureFlagService::class)->isEnabled($flag);
          }
      }
      
      Blade usage:
      @if(FeatureHelper::check('new_ui'))
      
  5. Locked Flag Cleanup:

    • Issue: Profiler warnings may not appear in Laravel’s Debugbar.
    • Fix: Log locked flags to Laravel’s log channel:
      if ($flag->isLocked()) {
          \Log::warning("Flag '{$flag->name}' is locked and must be cleaned up.");
      }
      

Debugging Tips

  • Unknown Flags: Log unknown flags in a middleware:

    public function handle($request, Closure $next)
    {
        $unknownFlags = app(FeatureFlagService::class)->getUnknownFlags();
        if (!empty($unknownFlags)) {
            \Log::warning("Unknown flags checked: " . implode(', ', $unknownFlags));
        }
        return $next($request);
    }
    
  • Cache Debugging: Dump cache keys to identify stale entries:

    \Log::debug('Cache keys:', Cache::getStore()->getAllKeys());
    
  • Migration Issues: Use Laravel Doctrine bridge tools to inspect schema:

    php artisan doctrine:schema:update --dump-sql
    

Extension Points

  1. Custom Flag Types:

    • Extend the Flag entity to add metadata (e.g., user_segment, percentage):
      class Flag extends \Devexploris\ShizukuFeatureFlags\Entity\Flag
      {
          protected $percentage; // e.g., 10 for 10% rollout
      }
      
    • Update FeatureFlagService to support percentage-based checks:
      public function isEnabledForUser(string $flag, User $user): bool
      {
          $flag = $this->getFlag($flag);
          if (!$flag || !$flag->percentage) return $flag->isEnabled;
      
          return $flag->isEnabled && (rand(1, 100) <= $flag->percentage);
      }
      
  2. Webhook Notifications:

    • Dispatch events when flags change (e.g., Slack notifications):
      use Illuminate\Support\Facades\Event;
      
      Event::listen(Flag::class, function ($flag) {
          if ($flag->wasChanged('isEnabled')) {
              \Log::info("Flag '{$flag->name}' toggled to {$flag->isEnabled}");
              // Send webhook to Slack/Teams
          }
      });
      
  3. Audit Logging:

    • Track flag changes with Laravel’s audit packages (e.g., spatie/laravel-audit-log):
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
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
christhompsontldr/laravel-inky