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

Database Activator Laravel Package

flagception/database-activator

Doctrine DBAL-backed activator for Flagception feature flags. Stores flag state in a SQL database (MySQL/Postgres/SQLite), auto-creates the table, and supports connection arrays, DSNs, or an existing DBAL instance, with customizable table/column names.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:
    composer require flagception/database-activator
    
  2. Create a basic activator instance (using DSN string):
    use Flagception\DatabaseActivator;
    
    $activator = new DatabaseActivator('pdo-mysql://user:pass@localhost/db_name');
    
  3. Integrate with FeatureManager:
    use Flagception\FeatureManager;
    
    $manager = new FeatureManager($activator);
    if ($manager->isActive('my_feature')) {
        // Feature logic here
    }
    

First Use Case: Persistent Feature Flags

Replace in-memory or file-based flags with database-backed ones:

// app/Providers/FlagServiceProvider.php
public function register()
{
    $this->app->singleton(DatabaseActivator::class, function ($app) {
        return new DatabaseActivator(config('database.connections.mysql'));
    });

    $this->app->singleton(FeatureManager::class, function ($app) {
        return new FeatureManager($app->make(DatabaseActivator::class));
    });
}

Where to Look First

  • README.md: For connection options and table customization.
  • Changelog: To verify compatibility with your PHP/DBAL versions.
  • Source Code: src/DatabaseActivator.php for method signatures and behavior.

Implementation Patterns

Core Workflow: Feature Flag Management

  1. Initialize Activator:
    $activator = new DatabaseActivator([
        'url' => 'mysql://user:pass@localhost/db',
        'table' => 'feature_flags',
    ]);
    
  2. Set Flags (via migrations or admin panel):
    $activator->setFeature('new_ui', true);
    $activator->setFeature('experimental_api', false);
    
  3. Check Flags:
    if ($manager->isActive('new_ui')) {
        // Enable new UI
    }
    

Laravel-Specific Patterns

  1. Service Container Binding:
    $this->app->bind(DatabaseActivator::class, function ($app) {
        return new DatabaseActivator($app['db']->connection('mysql'));
    });
    
  2. Configurable Table:
    // config/flagception.php
    'table' => env('FLAGCEP_TABLE', 'flagception_features'),
    'columns' => [
        'feature' => 'flag_name',
        'state' => 'is_enabled',
    ],
    
  3. Migration for Schema:
    Schema::create('feature_flags', function (Blueprint $table) {
        $table->string('flag_name')->primary();
        $table->boolean('is_enabled')->default(false);
        $table->timestamps();
    });
    

Integration with Admin Panels

  1. Laravel Nova Resource:
    // app/Nova/FeatureFlag.php
    public static $model = \Flagception\DatabaseActivator::class;
    public static $title = 'name';
    
  2. Filament Panel:
    use Filament\Tables;
    Tables::column('is_enabled')->toggle();
    

Advanced: Multi-Environment Flags

$activator = new DatabaseActivator('pdo-mysql://...', [
    'table' => 'feature_flags',
    'columns' => [
        'feature' => 'flag_name',
        'state' => 'is_enabled',
        'environment' => 'env',
    ],
]);

// Set flag for production only
$activator->setFeature('premium_feature', true, 'prod');

Testing Patterns

  1. Unit Test Setup:
    $activator = new DatabaseActivator(':memory:');
    $activator->setFeature('test_flag', true);
    $this->assertTrue($manager->isActive('test_flag'));
    
  2. Database Transactions:
    DB::transaction(function () use ($activator) {
        $activator->setFeature('temp_flag', true);
        // Test logic
    });
    

Gotchas and Tips

Common Pitfalls

  1. Schema Mismatch:

    • Error: SQLSTATE[42S02]: Base table or view not found.
    • Fix: Ensure the table exists or let the activator auto-create it. For custom schemas, verify column names match the activator’s expectations.
  2. Connection Issues:

    • Error: PDOException: could not find driver.
    • Fix: Install the correct PHP PDO driver (e.g., sudo apt-get install php-mysql for MySQL).
  3. PostgreSQL Parameterization:

    • Error: ERROR: column "state" must appear in the GROUP BY clause.
    • Fix: Upgrade to v1.1.1+ where queries are parametrized to avoid this issue.
  4. Case Sensitivity:

    • Issue: Flags may not match due to case sensitivity in databases (e.g., PostgreSQL).
    • Fix: Normalize flag names (e.g., strtolower()) or use a consistent case in queries.

Debugging Tips

  1. Enable DBAL Logging:
    $dbal = DatabaseDriverManager::getConnection(['url' => '...'], [
        'logging' => true,
        'logger' => new \Monolog\Logger('dbal'),
    ]);
    
  2. Check Raw Queries:
    $activator->getConnection()->getDatabasePlatform()->getListTableColumnsSQL('flagception_features');
    
  3. Verify Table Structure:
    php artisan db:show flagception_features
    

Configuration Quirks

  1. Default Table Name:
    • The activator defaults to flagception_features. To override:
      $activator = new DatabaseActivator('pdo-mysql://...', ['db_table' => 'custom_flags']);
      
  2. Column Names:
    • Customize column names for existing schemas:
      $activator = new DatabaseActivator('pdo-mysql://...', [
          'db_column_feature' => 'flag_key',
          'db_column_state' => 'enabled',
      ]);
      
  3. Connection Sharing:
    • Reuse a DBAL connection instance to avoid overhead:
      $dbal = DatabaseDriverManager::getConnection(['url' => '...']);
      $activator1 = new DatabaseActivator($dbal);
      $activator2 = new DatabaseActivator($dbal); // Shares the same connection
      

Extension Points

  1. Custom Activator Logic:
    • Extend DatabaseActivator to add methods like setFeatureWithMetadata:
      class ExtendedActivator extends DatabaseActivator {
          public function setFeatureWithMetadata($feature, $state, $metadata) {
              $this->getConnection()->executeStatement(
                  'INSERT INTO feature_flags (feature, state, metadata) VALUES (?, ?, ?)',
                  [$feature, $state, json_encode($metadata)]
              );
          }
      }
      
  2. Event Listeners:
    • Trigger events on flag changes (e.g., log to Laravel logs):
      $activator->addListener(function ($feature, $state) {
          Log::info("Flag {$feature} set to {$state}");
      });
      
  3. Caching Layer:
    • Cache flag states to reduce database reads:
      $activator = new DatabaseActivator('pdo-mysql://...');
      Cache::remember("flag_{$feature}", now()->addHours(1), function () use ($activator, $feature) {
          return $activator->isActive($feature);
      });
      

Performance Considerations

  1. Indexing:
    • Ensure the feature column is indexed for fast lookups:
      CREATE INDEX idx_feature_flags_feature ON feature_flags(feature);
      
  2. Batch Operations:
    • Use bulk inserts for initial flag setup:
      $connection = $activator->getConnection();
      $connection->insert(
          'INSERT INTO feature_flags (feature, state) VALUES ?',
          array_map(function ($flag) {
              return [$flag['name'], $flag['enabled']];
          }, $flags)
      );
      
  3. Connection Pooling:
    • Reuse DBAL connections across activators to reduce connection overhead.

Security Notes

  1. SQL Injection:
    • The package uses DBAL’s prepared statements, so no additional protection is needed for basic usage.
  2. Sensitive Data:
    • Avoid storing secrets or PII in flag metadata. Use environment variables for sensitive configurations.
  3. Authorization:
    • Implement middleware to restrict flag modifications to admin users:
      Route::put('/flags/{feature}', function ($feature) {
          if (!auth()->user()->isAdmin()) {
              abort(403);
          }
          $activator->setFeature($feature, request('state'));
      })->middleware('auth');
      
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