ambrion/feature-flags-core

Framework-agnostic Feature Flags library following DDD and Clean Architecture principles

Maintainers

Package info

github.com/Ambrion/feature-flags-core

pkg:composer/ambrion/feature-flags-core

Statistics

Installs: 8

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0-alpha 2026-05-06 14:41 UTC

This package is auto-updated.

Last update: 2026-05-06 14:45:10 UTC


README

Framework-agnostic Feature Flags engine built with DDD and Clean Architecture principles.
Designed to be portable, testable, and easily integrated into any PHP project.

PHP Version License Tests Pest

✨ Features

  • Framework-agnostic: No dependencies on CMS, framework, or global state.
  • Domain-Driven Design: Clean separation of Entities, Value Objects, Specifications, and Services.
  • Rule-Based Evaluation: category=, user_role=, target_id IN (...), current_date BETWEEN, PERCENTAGE N.
  • A/B Testing: Deterministic variant selection via getVariant().
  • Extensible Logging: Contract-based usage tracking with NullFlagUsageLogger out of the box.
  • TDD-Verified: 74%+ code coverage with Pest/PHPUnit, safe for production.

📦 Installation

composer require ambrion/feature-flags-core

🚀 Quick Start

1. Wire Dependencies

use FeatureFlags\Core\Application\Service\FeatureFlagService;
use FeatureFlags\Core\Domain\Logger\NullFlagUsageLogger;
use FeatureFlags\Core\Domain\Repository\FlagRepositoryInterface;

// Implement your own repository (DB, config file, etc.)
$repository = new MyFlagRepository();
$logger = new NullFlagUsageLogger();

$flagService = new FeatureFlagService($repository, $logger);

2. Evaluate Flags

// Boolean flag with context
$isEnabled = $flagService->isEnabled('new_product_template', [
    'user_role' => 'manager',
    'category' => 'electronics',
    'target_id' => 42
]);

// A/B Test variant (returns string|null)
$variant = $flagService->getVariant('article_header_test', [
    'user_hash' => md5($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'])
]);

🧩 How Rules Work

Flags are evaluated in order (short-circuit). First matching rule wins.

Condition Syntax Description Example
user_role=VALUE Exact role match user_role=admin
category IN (a,b) List match category IN (electronics,phones)
target_id=VALUE Exact entity ID target_id=101
current_date BETWEEN MM-DD AND MM-DD Seasonal window current_date BETWEEN 12-01 AND 12-31
user_hash PERCENTAGE N Deterministic rollout user_hash PERCENTAGE 25

💡 Platform Integration: Map your platform-specific keys (e.g., document_id) to target_id in your adapter. The core stays neutral.

🏗️ Architecture Overview

Application/
  └── Service/FeatureFlagService.php  ← Orchestration layer
Domain/
  ├── Entity/FeatureFlag.php          ← Business rules & evaluation
  ├── Specification/                  ← Condition strategies
  ├── ValueObject/                    ← FlagName, EvaluationContext
  ├── Logger/FlagUsageLoggerInterface ← Contract for analytics
  └── Repository/FlagRepositoryInterface ← Contract for storage
  • No framework ties: Core doesn't know about Laravel, Symfony, or DB drivers.
  • Ports & Adapters: Implement FlagRepositoryInterface and FlagUsageLoggerInterface for your stack.

📊 Logging & Analytics

Implement FlagUsageLoggerInterface to track flag usage:

public function log(string $flagName, bool $result, array $context = []): void;
public function logVariant(string $flagName, ?string $variant, array $context = []): void;

Use NullFlagUsageLogger in dev/tests. Swap to DatabaseLogger or FileLogger in production.

🧪 Development & Testing

composer install
composer test          # Run unit tests
composer test:coverage # Run with coverage report
composer stan          # Static analysis with PHPStan
composer format        # Auto-format with Pint
composer check         # Run all checks: lint + test + stan

Built with Pest. Follow TDD: Red → Green → Refactor.

📄 License

MIT © Ambrion. See LICENSE for details.