PHP code example of azaharizaman / nexus-feature-flags
1. Go to this page and download the library: Download azaharizaman/nexus-feature-flags library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
azaharizaman / nexus-feature-flags example snippets
use Nexus\FeatureFlags\Services\FeatureFlagManager;
use Nexus\FeatureFlags\Core\Engine\DefaultFlagEvaluator;
use Nexus\FeatureFlags\Core\Repository\InMemoryFlagRepository;
use Psr\Log\NullLogger;
$repository = new InMemoryFlagRepository();
$evaluator = new DefaultFlagEvaluator(new PercentageHasher());
$manager = new FeatureFlagManager($repository, $evaluator, new NullLogger());
use Nexus\FeatureFlags\Contracts\FeatureFlagManagerInterface;
class MyController
{
public function __construct(
private readonly FeatureFlagManagerInterface $flags
) {}
public function index(): Response
{
if ($this->flags->isEnabled('new_dashboard')) {
return $this->renderNewDashboard();
}
return $this->renderOldDashboard();
}
}
use Nexus\FeatureFlags\ValueObjects\EvaluationContext;
$context = new EvaluationContext(
tenantId: 'tenant-123',
userId: 'user-456',
customAttributes: ['plan' => 'premium']
);
if ($this->flags->isEnabled('advanced_analytics', $context)) {
// Show premium feature
}
// In controllers
public function __construct(
private readonly FeatureFlagManagerInterface $flags
) {}
public function show(Request $request): JsonResponse
{
$context = [
'tenantId' => $request->user()->tenant_id,
'userId' => $request->user()->id,
];
if ($this->flags->isEnabled('premium.analytics', $context)) {
return response()->json(['data' => $this->getPremiumAnalytics()]);
}
return response()->json(['data' => $this->getBasicAnalytics()]);
}
// In AppServiceProvider
Blade::directive('featureFlag', function ($expression) {
return " if(app(FeatureFlagManagerInterface::class)->isEnabled($expression)):
use Nexus\FeatureFlags\Contracts\FeatureFlagManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class DashboardController extends AbstractController
{
public function __construct(
private readonly FeatureFlagManagerInterface $flags
) {}
#[Route('/dashboard')]
public function index(RequestStack $requestStack): Response
{
$context = [
'userId' => $this->getUser()?->getId(),
'tenantId' => $requestStack->getCurrentRequest()?->attributes->get('tenant_id'),
];
return $this->render('dashboard/index.html.twig', [
'use_new_ui' => $this->flags->isEnabled('dashboard.v2', $context),
]);
}
}
namespace App\Twig;
use Nexus\FeatureFlags\Contracts\FeatureFlagManagerInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
class FeatureFlagExtension extends AbstractExtension
{
public function __construct(
private readonly FeatureFlagManagerInterface $flags
) {}
public function getFunctions(): array
{
return [
new TwigFunction('feature_enabled', [$this, 'isEnabled']),
];
}
public function isEnabled(string $flagName, array $context = []): bool
{
return $this->flags->isEnabled($flagName, $context);
}
}
use Nexus\FeatureFlags\Services\FeatureFlagManager;
use Nexus\FeatureFlags\Core\Engine\DefaultFlagEvaluator;
use Nexus\FeatureFlags\Core\Repository\InMemoryFlagRepository;
use Psr\Container\ContainerInterface;
use Slim\Factory\AppFactory;
$container = new \DI\Container();
// Register feature flag services
$container->set(FlagRepositoryInterface::class, function() {
return new InMemoryFlagRepository(); // Or your custom implementation
});
$container->set(FeatureFlagManagerInterface::class, function(ContainerInterface $c) {
return new FeatureFlagManager(
$c->get(FlagRepositoryInterface::class),
new DefaultFlagEvaluator(new PercentageHasher()),
$c->get(LoggerInterface::class)
);
});
AppFactory::setContainer($container);
$app = AppFactory::create();
// Use in routes
$app->get('/dashboard', function (Request $request, Response $response) use ($container) {
$flags = $container->get(FeatureFlagManagerInterface::class);
$context = [
'userId' => $request->getAttribute('user_id'),
];
if ($flags->isEnabled('beta.features', $context)) {
return $response->withJson(['version' => 'beta']);
}
return $response->withJson(['version' => 'stable']);
});
exus\FeatureFlags\Services\FeatureFlagManager;
use Nexus\FeatureFlags\Core\Engine\DefaultFlagEvaluator;
use Nexus\FeatureFlags\Core\Engine\PercentageHasher;
use Nexus\FeatureFlags\Core\Repository\InMemoryFlagRepository;
use Nexus\FeatureFlags\ValueObjects\FlagDefinition;
use Nexus\FeatureFlags\Enums\FlagStrategy;
use Psr\Log\NullLogger;
// Setup repository and add flags
$repository = new InMemoryFlagRepository();
$repository->save(FlagDefinition::create(
name: 'new.feature',
enabled: true,
strategy: FlagStrategy::PERCENTAGE_ROLLOUT,
value: 50 // 50% rollout
));
// Create manager
$manager = new FeatureFlagManager(
repository: $repository,
evaluator: new DefaultFlagEvaluator(new PercentageHasher()),
logger: new NullLogger()
);
// Evaluate flags
$context = ['userId' => 'user-12345'];
if ($manager->isEnabled('new.feature', $context)) {
echo "You're in the 50% rollout group!\n";
} else {
echo "Not yet enabled for you.\n";
}
use Nexus\FeatureFlags\Contracts\FlagAuditChangeInterface;
use Nexus\FeatureFlags\Enums\AuditAction;
use Nexus\AuditLogger\Contracts\AuditLogRepositoryInterface;
// Application layer implementation
final readonly class FeatureFlagAuditLogger implements FlagAuditChangeInterface
{
public function __construct(
private AuditLogRepositoryInterface $auditLogger,
private TenantContextInterface $tenantContext
) {}
public function recordChange(
string $flagName,
AuditAction $action,
?string $userId,
?array $before,
?array $after,
array $metadata = []
): void {
$this->auditLogger->create([
'log_name' => 'feature_flags',
'subject_type' => 'feature_flag',
'subject_id' => $flagName,
'causer_type' => 'user',
'causer_id' => $userId,
'event' => $action->value,
'description' => $action->getDescription(),
'properties' => [
'before' => $before,
'after' => $after,
...$metadata,
],
'level' => $action->isCritical() ? 4 : 2, // Critical = 4, Medium = 2
'tenant_id' => $this->tenantContext->getCurrentTenantId(),
]);
}
public function recordBatchChange(
AuditAction $action,
?string $userId,
array $changes,
array $metadata = []
): void {
// Generate batch ID using your preferred method:
// - Symfony: (new \Symfony\Component\Uid\Ulid())->__toString()
// - ramsey/uuid: (string) \Ramsey\Uuid\Uuid::uuid7()
// - Laravel: (string) Str::ulid()
$batchId = $this->generateBatchId();
foreach ($changes as $flagName => $change) {
$this->recordChange(
$flagName,
$action,
$userId,
$change['before'],
$change['after'],
[...$metadata, 'batch_id' => $batchId]
);
}
}
private function generateBatchId(): string
{
// Implement using your preferred ULID/UUID library
return (new \Symfony\Component\Uid\Ulid())->__toString();
}
}
use Nexus\FeatureFlags\Contracts\FlagAuditQueryInterface;
use Nexus\FeatureFlags\Contracts\FlagAuditRecordInterface;
use Nexus\FeatureFlags\Enums\AuditAction;
use Nexus\EventStream\Contracts\EventStoreInterface;
// Application layer implementation
final readonly class FeatureFlagAuditQuery implements FlagAuditQueryInterface
{
public function __construct(
private EventStoreInterface $eventStore
) {}
public function getHistory(
string $flagName,
?string $tenantId = null,
int $limit = 100,
int $offset = 0
): array {
return $this->eventStore->query(
filters: [
'aggregate_id' => ['operator' => '=', 'value' => "flag:{$flagName}"],
],
inFilters: [],
orderByField: 'occurred_at',
orderDirection: 'desc',
limit: $limit,
cursorData: null
);
}
public function getStateAt(
string $flagName,
DateTimeImmutable $timestamp,
?string $tenantId = null
): ?array {
// Replay events up to timestamp to reconstruct state
$events = $this->eventStore->query(
filters: [
'aggregate_id' => ['operator' => '=', 'value' => "flag:{$flagName}"],
'occurred_at' => ['operator' => '<=', 'value' => $timestamp->format('Y-m-d H:i:s')],
],
inFilters: [],
orderByField: 'occurred_at',
orderDirection: 'asc',
limit: 10000
);
if (empty($events)) {
return null;
}
// Reconstruct state by replaying events
return $this->reconstructState($events);
}
public function getCriticalChanges(
?string $tenantId = null,
?DateTimeImmutable $since = null,
int $limit = 500
): array {
$filters = [];
if ($since !== null) {
$filters['occurred_at'] = ['operator' => '>=', 'value' => $since->format('Y-m-d H:i:s')];
}
$criticalActions = [
AuditAction::FORCE_DISABLED->value,
AuditAction::FORCE_ENABLED->value,
AuditAction::DELETED->value,
AuditAction::OVERRIDE_CHANGED->value,
];
return $this->eventStore->query(
filters: $filters,
inFilters: ['event_type' => $criticalActions],
orderByField: 'occurred_at',
orderDirection: 'desc',
limit: $limit
);
}
// ... other methods
}
use Nexus\FeatureFlags\Services\AuditableFlagRepository;
// Wrap your repository for automatic audit logging
$auditableRepo = new AuditableFlagRepository(
repository: $baseRepository,
auditChange: $auditChangeLogger,
userId: $currentUser->getId()
);
// Set tenant context
$auditableRepo = $auditableRepo->withTenantId($tenantId);
// Now all save/delete operations are automatically audited
$auditableRepo->save($flag); // Records CREATED or appropriate action
$auditableRepo->delete('old_flag', $tenantId); // Records DELETED
// Check if audit capabilities are configured
if ($manager->hasAuditChange()) {
// Audit change logging is available
}
if ($manager->hasAuditQuery()) {
// Historical queries are available
$query = $manager->getAuditQuery();
// Get flag history
$history = $query->getHistory('payment_v2', 'tenant-123');
// Compliance audit: What was the state during an incident?
$stateAtIncident = $query->getStateAt(
'payment_v2',
new DateTimeImmutable('2024-11-15 14:30:00'),
'tenant-123'
);
// Get all critical changes this month
$criticalChanges = $query->getCriticalChanges(
tenantId: 'tenant-123',
since: new DateTimeImmutable('first day of this month')
);
}
// AppServiceProvider.php
public function register(): void
{
// Register audit change logger (uses Nexus\AuditLogger)
$this->app->singleton(FlagAuditChangeInterface::class, function ($app) {
return new FeatureFlagAuditLogger(
$app->make(AuditLogRepositoryInterface::class),
$app->make(TenantContextInterface::class)
);
});
// Register audit query (uses Nexus\EventStream)
$this->app->singleton(FlagAuditQueryInterface::class, function ($app) {
return new FeatureFlagAuditQuery(
$app->make(EventStoreInterface::class)
);
});
// Register manager with audit support
$this->app->singleton(FeatureFlagManagerInterface::class, function ($app) {
return new FeatureFlagManager(
$app->make(FlagRepositoryInterface::class),
$app->make(FlagEvaluatorInterface::class),
$app->make(LoggerInterface::class),
$app->make(FlagAuditChangeInterface::class), // Optional
$app->make(FlagAuditQueryInterface::class) // Optional
);
});
}