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.
composer require flagception/database-activator
use Flagception\DatabaseActivator;
$activator = new DatabaseActivator('pdo-mysql://user:pass@localhost/db_name');
use Flagception\FeatureManager;
$manager = new FeatureManager($activator);
if ($manager->isActive('my_feature')) {
// Feature logic here
}
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));
});
}
src/DatabaseActivator.php for method signatures and behavior.$activator = new DatabaseActivator([
'url' => 'mysql://user:pass@localhost/db',
'table' => 'feature_flags',
]);
$activator->setFeature('new_ui', true);
$activator->setFeature('experimental_api', false);
if ($manager->isActive('new_ui')) {
// Enable new UI
}
$this->app->bind(DatabaseActivator::class, function ($app) {
return new DatabaseActivator($app['db']->connection('mysql'));
});
// config/flagception.php
'table' => env('FLAGCEP_TABLE', 'flagception_features'),
'columns' => [
'feature' => 'flag_name',
'state' => 'is_enabled',
],
Schema::create('feature_flags', function (Blueprint $table) {
$table->string('flag_name')->primary();
$table->boolean('is_enabled')->default(false);
$table->timestamps();
});
// app/Nova/FeatureFlag.php
public static $model = \Flagception\DatabaseActivator::class;
public static $title = 'name';
use Filament\Tables;
Tables::column('is_enabled')->toggle();
$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');
$activator = new DatabaseActivator(':memory:');
$activator->setFeature('test_flag', true);
$this->assertTrue($manager->isActive('test_flag'));
DB::transaction(function () use ($activator) {
$activator->setFeature('temp_flag', true);
// Test logic
});
Schema Mismatch:
SQLSTATE[42S02]: Base table or view not found.Connection Issues:
PDOException: could not find driver.sudo apt-get install php-mysql for MySQL).PostgreSQL Parameterization:
ERROR: column "state" must appear in the GROUP BY clause.v1.1.1+ where queries are parametrized to avoid this issue.Case Sensitivity:
strtolower()) or use a consistent case in queries.$dbal = DatabaseDriverManager::getConnection(['url' => '...'], [
'logging' => true,
'logger' => new \Monolog\Logger('dbal'),
]);
$activator->getConnection()->getDatabasePlatform()->getListTableColumnsSQL('flagception_features');
php artisan db:show flagception_features
flagception_features. To override:
$activator = new DatabaseActivator('pdo-mysql://...', ['db_table' => 'custom_flags']);
$activator = new DatabaseActivator('pdo-mysql://...', [
'db_column_feature' => 'flag_key',
'db_column_state' => 'enabled',
]);
$dbal = DatabaseDriverManager::getConnection(['url' => '...']);
$activator1 = new DatabaseActivator($dbal);
$activator2 = new DatabaseActivator($dbal); // Shares the same connection
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)]
);
}
}
$activator->addListener(function ($feature, $state) {
Log::info("Flag {$feature} set to {$state}");
});
$activator = new DatabaseActivator('pdo-mysql://...');
Cache::remember("flag_{$feature}", now()->addHours(1), function () use ($activator, $feature) {
return $activator->isActive($feature);
});
feature column is indexed for fast lookups:
CREATE INDEX idx_feature_flags_feature ON feature_flags(feature);
$connection = $activator->getConnection();
$connection->insert(
'INSERT INTO feature_flags (feature, state) VALUES ?',
array_map(function ($flag) {
return [$flag['name'], $flag['enabled']];
}, $flags)
);
Route::put('/flags/{feature}', function ($feature) {
if (!auth()->user()->isAdmin()) {
abort(403);
}
$activator->setFeature($feature, request('state'));
})->middleware('auth');
How can I help you explore Laravel packages today?