Repository: pheature-flags/pheature-flags (php)

Issue:
[pheature-flags] install roave infection-static-analysis-plugin
This plugin discovers if escaped mutants are valid mutations, or if they do not respect the type signature of your program

Pull request:
[#206] install psalm infection plugin
Closes #206.

Patch:
diff --git a/composer.json b/composer.json
index 0799ec6..793e9cc 100644
--- a/composer.json
+++ b/composer.json
@@ -7,7 +7,7 @@
         }
     ],
     "require": {
-        "doctrine/dbal": ">=2.5 || ^3.0.0",
+        "doctrine/dbal": ">=2.6 || ^3.0.0",
         "illuminate/support": "^8.37",
         "nyholm/psr7": "^1.4",
         "pheature/php-sdk": "@dev",
@@ -21,7 +21,7 @@
         "webmozart/assert": "^1.10"
     },
     "require-dev": {
-        "infection/infection": "^0.21.0",
+        "infection/infection": "^0.23.0",
         "laravel/laravel": "^8.5",
         "mezzio/mezzio": "^3.3",
         "mezzio/mezzio-helpers": "^5.4",
@@ -32,7 +32,8 @@
         "symfony/console": "^4.2 || ^5.0",
         "symfony/var-dumper": "^4.2 || ^5.0",
         "symplify/monorepo-builder": "^9.2",
-        "vimeo/psalm": "^4.4"
+        "vimeo/psalm": "^4.4",
+        "roave/infection-static-analysis-plugin": "^1.8"
     },
     "autoload": {
         "psr-4": {
@@ -78,7 +79,7 @@
         "inspect": "phpstan analyse packages/*/src -l7 --ansi",
         "test": "phpunit --colors=always",
         "psalm": "psalm packages/*/src",
-        "infection": "XDEBUG_MODE=coverage infection"
+        "infection": "XDEBUG_MODE=coverage roave-infection-static-analysis-plugin"
     },
     "extra": {
         "laminas": {
diff --git a/docs/getting-started/symfony-bundle.md b/docs/getting-started/symfony-bundle.md
index 94c8739..a211746 100644
--- a/docs/getting-started/symfony-bundle.md
+++ b/docs/getting-started/symfony-bundle.md
@@ -32,7 +32,7 @@ return [
 # config/packages/pheature-flags.yaml
 pheature_flags:
   driver:               ~ # One of "inmemory"; "dbal"
-  prefix:               ''
+  api_prefix:           ''
   segment_types:
     - { type: 'identity_segment', factory_id: 'Pheature\Model\Toggle\SegmentFactory' }
     - { type: 'strict_matching_segment', factory_id: 'Pheature\Model\Toggle\SegmentFactory' }
diff --git a/packages/dbal-toggle/composer.json b/packages/dbal-toggle/composer.json
index 371f966..1b01599 100644
--- a/packages/dbal-toggle/composer.json
+++ b/packages/dbal-toggle/composer.json
@@ -20,10 +20,11 @@
         "pheature/toggle-crud": "@dev"
     },
     "require-dev": {
-        "infection/infection": "^0.21.0",
+        "infection/infection": "^0.23.0",
         "phpro/grumphp": "^1.0",
         "phpstan/phpstan": "^0.12",
         "phpunit/phpunit": "^8.0 || ^9.0",
+        "roave/infection-static-analysis-plugin": "^1.8",
         "squizlabs/php_codesniffer": "^3.4",
         "symfony/console": "^4.2 || ^5.0",
         "symfony/var-dumper": "^4.2 || ^5.0",
@@ -52,7 +53,7 @@
         "inspect": "phpstan analyse src -l7 --ansi",
         "test": "phpunit --colors=always",
         "psalm": "psalm",
-        "infection": "XDEBUG_MODE=coverage infection"
+        "infection": "XDEBUG_MODE=coverage roave-infection-static-analysis-plugin"
     },
     "config": {
         "sort-packages": true
diff --git a/packages/dbal-toggle/src/Read/DbalFeatureFinder.php b/packages/dbal-toggle/src/Read/DbalFeatureFinder.php
index 59737c5..6a6dafb 100644
--- a/packages/dbal-toggle/src/Read/DbalFeatureFinder.php
+++ b/packages/dbal-toggle/src/Read/DbalFeatureFinder.php
@@ -5,7 +5,6 @@ declare(strict_types=1);
 namespace Pheature\Dbal\Toggle\Read;
 
 use Doctrine\DBAL\Connection;
-use Doctrine\DBAL\Portability\Statement;
 use Doctrine\DBAL\Result;
 use InvalidArgumentException;
 use Pheature\Core\Toggle\Read\Feature;
diff --git a/packages/inmemory-toggle/composer.json b/packages/inmemory-toggle/composer.json
index bed4d12..263fe73 100644
--- a/packages/inmemory-toggle/composer.json
+++ b/packages/inmemory-toggle/composer.json
@@ -18,10 +18,11 @@
         "pheature/toggle-model": "@dev"
     },
     "require-dev": {
-        "infection/infection": "^0.21.0",
+        "infection/infection": "^0.23.0",
         "phpro/grumphp": "^1.0",
         "phpstan/phpstan": "^0.12",
         "phpunit/phpunit": "^8.0 || ^9.0",
+        "roave/infection-static-analysis-plugin": "^1.8",
         "squizlabs/php_codesniffer": "^3.4",
         "symfony/var-dumper": "^4.2 || ^5.0",
         "vimeo/psalm": "^4.4"
@@ -49,7 +50,7 @@
         "inspect": "phpstan analyse src -l7 --ansi",
         "test": "phpunit --colors=always",
         "psalm": "psalm",
-        "infection": "XDEBUG_MODE=coverage infection"
+        "infection": "XDEBUG_MODE=coverage roave-infection-static-analysis-plugin"
     },
     "config": {
         "sort-packages": true
diff --git a/packages/laravel-toggle/composer.json b/packages/laravel-toggle/composer.json
index d9172c4..6f5e496 100644
--- a/packages/laravel-toggle/composer.json
+++ b/packages/laravel-toggle/composer.json
@@ -15,6 +15,7 @@
     "require": {
         "php": "^7.4|^8.0",
         "illuminate/support": "^8.37",
+        "laravel/laravel": "^8.5",
         "nyholm/psr7": "^1.4",
         "pheature/dbal-toggle": "@dev",
         "pheature/inmemory-toggle": "@dev",
@@ -27,10 +28,11 @@
         "symfony/psr-http-message-bridge": "^2.1"
     },
     "require-dev": {
-        "infection/infection": "^0.21.0",
+        "infection/infection": "^0.23.0",
         "phpro/grumphp": "^1.0",
         "phpstan/phpstan": "^0.12",
         "phpunit/phpunit": "^8.0 || ^9.0",
+        "roave/infection-static-analysis-plugin": "^1.8",
         "squizlabs/php_codesniffer": "^3.4",
         "symfony/var-dumper": "^4.2 || ^5.0",
         "vimeo/psalm": "^4.4"
@@ -58,7 +60,7 @@
         "inspect": "phpstan analyse src -l7 --ansi",
         "test": "phpunit --colors=always",
         "psalm": "psalm",
-        "infection": "XDEBUG_MODE=coverage infection"
+        "infection": "XDEBUG_MODE=coverage roave-infection-static-analysis-plugin"
     },
     "extra": {
         "laravel": {
diff --git a/packages/laravel-toggle/config/pheature_flags.php b/packages/laravel-toggle/config/pheature_flags.php
index 8a353fe..67afb65 100644
--- a/packages/laravel-toggle/config/pheature_flags.php
+++ b/packages/laravel-toggle/config/pheature_flags.php
@@ -3,7 +3,7 @@
 declare(strict_types=1);
 
 return [
-    'prefix' => '',
+    'api_prefix' => '',
     'driver' => 'inmemory',
     'toggles' => [
         'feature_1' => [
diff --git a/packages/laravel-toggle/src/ToggleProvider.php b/packages/laravel-toggle/src/ToggleProvider.php
index 4c98378..9392db7 100644
--- a/packages/laravel-toggle/src/ToggleProvider.php
+++ b/packages/laravel-toggle/src/ToggleProvider.php
@@ -128,7 +128,7 @@ final class ToggleProvider extends ServiceProvider
     private function routeConfiguration(): array
     {
         return [
-            'prefix' => config('pheature_flags.prefix') ?? '',
+            'prefix' => config('pheature_flags.api_prefix') ?? '',
             'middleware' => config('pheature_flags.middleware') ?? ['api'],
         ];
     }
diff --git a/packages/mezzio-toggle/composer.json b/packages/mezzio-toggle/composer.json
index 2a7244e..eb3f52f 100644
--- a/packages/mezzio-toggle/composer.json
+++ b/packages/mezzio-toggle/composer.json
@@ -14,6 +14,9 @@
     ],
     "require": {
         "php": "^7.4|^8.0",
+        "laminas/laminas-diactoros": "^2.6",
+        "mezzio/mezzio": "^3.3",
+        "mezzio/mezzio-helpers": "^5.4",
         "pheature/inmemory-toggle": "@dev",
         "pheature/php-sdk": "@dev",
         "pheature/toggle-core": "@dev",
@@ -23,10 +26,11 @@
         "pheature/toggle-model": "@dev"
     },
     "require-dev": {
-        "infection/infection": "^0.21.0",
+        "infection/infection": "^0.23.0",
         "phpro/grumphp": "^1.0",
         "phpstan/phpstan": "^0.12",
         "phpunit/phpunit": "^8.0 || ^9.0",
+        "roave/infection-static-analysis-plugin": "^1.8",
         "squizlabs/php_codesniffer": "^3.4",
         "symfony/var-dumper": "^4.2 || ^5.0",
         "vimeo/psalm": "^4.4"
@@ -54,7 +58,7 @@
         "inspect": "phpstan analyse src -l7 --ansi",
         "test": "phpunit --colors=always",
         "psalm": "psalm",
-        "infection": "XDEBUG_MODE=coverage infection"
+        "infection": "XDEBUG_MODE=coverage roave-infection-static-analysis-plugin"
     },
     "extra": {
         "laminas": {
diff --git a/packages/mezzio-toggle/src/RouterDelegator.php b/packages/mezzio-toggle/src/RouterDelegator.php
index 09bf4a5..513808f 100644
--- a/packages/mezzio-toggle/src/RouterDelegator.php
+++ b/packages/mezzio-toggle/src/RouterDelegator.php
@@ -25,7 +25,7 @@ final class RouterDelegator
 
         /** @var ToggleConfig $config */
         $config = $container->get(ToggleConfig::class);
-        $path = sprintf('%s/features', $config->prefix());
+        $path = sprintf('%s/features', $config->apiPrefix());
         $pathWithId = sprintf('%s/{feature_id}', $path);
 
         $app->get($path, [GetFeatures::class], 'get_features');
diff --git a/packages/php-sdk/composer.json b/packages/php-sdk/composer.json
index 5a223f6..69b8597 100644
--- a/packages/php-sdk/composer.json
+++ b/packages/php-sdk/composer.json
@@ -14,13 +14,15 @@
   ],
   "require": {
     "php": "^7.4|^8.0",
+    "pheature/toggle-core": "@dev",
     "psr/container": "^1.0.0|^2.0.0"
   },
   "require-dev": {
-    "infection/infection": "^0.21.0",
+    "infection/infection": "^0.23.0",
     "phpro/grumphp": "^1.0",
     "phpstan/phpstan": "^0.12",
     "phpunit/phpunit": "^8.0 || ^9.0",
+    "roave/infection-static-analysis-plugin": "^1.8",
     "squizlabs/php_codesniffer": "^3.4",
     "symfony/var-dumper": "^4.2 || ^5.0",
     "vimeo/psalm": "^4.4"
@@ -45,7 +47,7 @@
     ],
     "cs-check": "phpcs src --colors",
     "cs-fix": "phpcbf src --colors",
-    "infection": "XDEBUG_MODE=coverage infection",
+    "infection": "XDEBUG_MODE=coverage roave-infection-static-analysis-plugin",
     "inspect": "phpstan analyse src -l7 --ansi",
     "psalm": "psalm",
     "test": "phpunit --colors=always"
diff --git a/packages/symfony-toggle/composer.json b/packages/symfony-toggle/composer.json
index 83987f0..0e7e9f3 100644
--- a/packages/symfony-toggle/composer.json
+++ b/packages/symfony-toggle/composer.json
@@ -21,8 +21,8 @@
         "symfony/framework-bundle": "~5.0"
     },
     "require-dev": {
-        "doctrine/dbal": "^3.1",
-        "infection/infection": "^0.21.0",
+        "doctrine/dbal": ">=2.6 || ^3.0.0",
+        "infection/infection": "^0.23.0",
         "pheature/dbal-toggle": "@dev",
         "pheature/inmemory-toggle": "@dev",
         "pheature/toggle-crud": "@dev",
@@ -30,6 +30,7 @@
         "phpro/grumphp": "^1.0",
         "phpstan/phpstan": "^0.12",
         "phpunit/phpunit": "^8.0 || ^9.0",
+        "roave/infection-static-analysis-plugin": "^1.8",
         "squizlabs/php_codesniffer": "^3.4",
         "symfony/var-dumper": "^4.2 || ^5.0",
         "vimeo/psalm": "^4.4"
@@ -57,7 +58,7 @@
         "inspect": "phpstan analyse src -l7 --ansi",
         "test": "phpunit --colors=always",
         "psalm": "psalm",
-        "infection": "XDEBUG_MODE=coverage infection"
+        "infection": "XDEBUG_MODE=coverage roave-infection-static-analysis-plugin"
     },
     "extra": {
         "laravel": {
diff --git a/packages/symfony-toggle/src/DependencyInjection/Configuration.php b/packages/symfony-toggle/src/DependencyInjection/Configuration.php
index 53dce19..a544685 100644
--- a/packages/symfony-toggle/src/DependencyInjection/Configuration.php
+++ b/packages/symfony-toggle/src/DependencyInjection/Configuration.php
@@ -23,9 +23,12 @@ final class Configuration implements ConfigurationInterface
             ->enumNode('driver')
                 ->values(['inmemory', 'dbal'])
             ->end()
-            ->scalarNode('prefix')
+            ->scalarNode('api_prefix')
                 ->defaultValue('')
             ->end()
+            ->booleanNode('api_enabled')
+                ->defaultFalse()
+            ->end()
         ->end();
 
         $this->addStrategyTypes($rootNode);
diff --git a/packages/symfony-toggle/src/DependencyInjection/ToggleAPIPass.php b/packages/symfony-toggle/src/DependencyInjection/ToggleAPIPass.php
new file mode 100644
index 0000000..f72a304
--- /dev/null
+++ b/packages/symfony-toggle/src/DependencyInjection/ToggleAPIPass.php
@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Pheature\Community\Symfony\DependencyInjection;
+
+use Symfony\Component\Config\FileLocator;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
+
+final class ToggleAPIPass implements CompilerPassInterface
+{
+    public function process(ContainerBuilder $container): void
+    {
+        /** @var array<array<mixed>> $pheatureFlagsConfig */
+        $pheatureFlagsConfig = $container->getExtensionConfig('pheature_flags');
+
+        $mergedConfig = array_merge(...$pheatureFlagsConfig);
+
+        if (false === $mergedConfig['api_enabled']) {
+            return;
+        }
+
+        $container->getParameterBag()->set('pheature_flags_prefix', $mergedConfig['api_prefix']);
+
+        $loader = new YamlFileLoader(
+            $container,
+            new FileLocator(__DIR__ . '/../Resources/config/toggle_api')
+        );
+        $loader->load('services/controller_services.yaml');
+        $loader->load('services/handler_services.yaml');
+    }
+}
diff --git a/packages/symfony-toggle/src/PheatureFlagsBundle.php b/packages/symfony-toggle/src/PheatureFlagsBundle.php
index b1b2b66..cc3e3f1 100644
--- a/packages/symfony-toggle/src/PheatureFlagsBundle.php
+++ b/packages/symfony-toggle/src/PheatureFlagsBundle.php
@@ -7,6 +7,7 @@ namespace Pheature\Community\Symfony;
 use Pheature\Community\Symfony\DependencyInjection\FeatureRepositoryFactoryPass;
 use Pheature\Community\Symfony\DependencyInjection\SegmentFactoryPass;
 use Pheature\Community\Symfony\DependencyInjection\ToggleStrategyFactoryPass;
+use Pheature\Community\Symfony\DependencyInjection\ToggleAPIPass;
 use Pheature\Model\Toggle\EnableByMatchingIdentityId;
 use Pheature\Model\Toggle\EnableByMatchingSegment;
 use Pheature\Model\Toggle\IdentitySegment;
@@ -20,7 +21,8 @@ final class PheatureFlagsBundle extends Bundle
 {
     private const DEFAULT_CONFIG = [
         'driver' => 'inmemory',
-        'prefix' => '',
+        'api_prefix' => '',
+        'api_enabled' => false,
         'segment_types' => [
             [
                 'type' => IdentitySegment::NAME,
@@ -51,5 +53,6 @@ final class PheatureFlagsBundle extends Bundle
         $container->addCompilerPass(new SegmentFactoryPass());
         $container->addCompilerPass(new ToggleStrategyFactoryPass());
         $container->addCompilerPass(new FeatureRepositoryFactoryPass());
+        $container->addCompilerPass(new ToggleAPIPass());
     }
 }
diff --git a/packages/symfony-toggle/src/Resources/config/toggle_api/routes.yaml b/packages/symfony-toggle/src/Resources/config/toggle_api/routes.yaml
new file mode 100644
index 0000000..a8dc1a1
--- /dev/null
+++ b/packages/symfony-toggle/src/Resources/config/toggle_api/routes.yaml
@@ -0,0 +1,24 @@
+pheature_flags_toggle_detail:
+  methods: [GET]
+  path: /features/{feature_id}
+  controller: Pheature\Crud\Psr7\Toggle\GetFeature::handle
+
+pheature_flags_feature_list:
+  methods: [GET]
+  path: /features
+  controller: Pheature\Crud\Psr7\Toggle\GetFeatures::handle
+
+pheature_flags_feature_create:
+  methods: [POST]
+  path: /features/{feature_id}
+  controller: Pheature\Crud\Psr7\Toggle\PostFeature::handle
+
+pheature_flags_feature_update:
+  methods: [PATCH]
+  path: /features/{feature_id}
+  controller: Pheature\Crud\Psr7\Toggle\PatchFeature::handle
+
+pheature_flags_feature_remove:
+  methods: [DELETE]
+  path: /features/{feature_id}
+  controller: Pheature\Crud\Psr7\Toggle\DeleteFeature::handle
diff --git a/packages/symfony-toggle/src/Resources/config/toggle_api/services/controller_services.yaml b/packages/symfony-toggle/src/Resources/config/toggle_api/services/controller_services.yaml
new file mode 100644
index 0000000..8881e3b
--- /dev/null
+++ b/packages/symfony-toggle/src/Resources/config/toggle_api/services/controller_services.yaml
@@ -0,0 +1,44 @@
+services:
+  _defaults:
+    autowire: false
+    autoconfigure: false
+    public: true
+
+  # PSR Controllers
+  Pheature\Crud\Psr7\Toggle\GetFeatures:
+    class: Pheature\Crud\Psr7\Toggle\GetFeatures
+    arguments:
+      - '@Pheature\Core\Toggle\Read\FeatureFinder'
+      - '@Psr\Http\Message\ResponseFactoryInterface'
+    tags: [ 'controller.service_arguments' ]
+
+  Pheature\Crud\Psr7\Toggle\GetFeature:
+    class: Pheature\Crud\Psr7\Toggle\GetFeature
+    arguments:
+      - '@Pheature\Core\Toggle\Read\FeatureFinder'
+      - '@Psr\Http\Message\ResponseFactoryInterface'
+    tags: [ 'controller.service_arguments' ]
+
+  Pheature\Crud\Psr7\Toggle\PostFeature:
+    class: Pheature\Crud\Psr7\Toggle\PostFeature
+    arguments:
+      - '@Pheature\Crud\Toggle\Handler\CreateFeature'
+      - '@Psr\Http\Message\ResponseFactoryInterface'
+    tags: [ 'controller.service_arguments' ]
+
+  Pheature\Crud\Psr7\Toggle\PatchFeature:
+    class: Pheature\Crud\Psr7\Toggle\PatchFeature
+    arguments:
+      - '@Pheature\Crud\Toggle\Handler\AddStrategy'
+      - '@Pheature\Crud\Toggle\Handler\RemoveStrategy'
+      - '@Pheature\Crud\Toggle\Handler\EnableFeature'
+      - '@Pheature\Crud\Toggle\Handler\DisableFeature'
+      - '@Psr\Http\Message\ResponseFactoryInterface'
+    tags: [ 'controller.service_arguments' ]
+
+  Pheature\Crud\Psr7\Toggle\DeleteFeature:
+    class: Pheature\Crud\Psr7\Toggle\DeleteFeature
+    arguments:
+      - '@Pheature\Crud\Toggle\Handler\RemoveFeature'
+      - '@Psr\Http\Message\ResponseFactoryInterface'
+    tags: [ 'controller.service_arguments' ]
diff --git a/packages/symfony-toggle/src/Resources/config/toggle_api/services/handler_services.yaml b/packages/symfony-toggle/src/Resources/config/toggle_api/services/handler_services.yaml
new file mode 100644
index 0000000..d547cb7
--- /dev/null
+++ b/packages/symfony-toggle/src/Resources/config/toggle_api/services/handler_services.yaml
@@ -0,0 +1,34 @@
+services:
+  _defaults:
+    autowire: false
+    autoconfigure: false
+
+  Pheature\Crud\Toggle\Handler\CreateFeature:
+    class: Pheature\Crud\Toggle\Handler\CreateFeature
+    arguments:
+      - '@Pheature\Core\Toggle\Write\FeatureRepository'
+
+  Pheature\Crud\Toggle\Handler\AddStrategy:
+    class: Pheature\Crud\Toggle\Handler\AddStrategy
+    arguments:
+      - '@Pheature\Core\Toggle\Write\FeatureRepository'
+
+  Pheature\Crud\Toggle\Handler\RemoveStrategy:
+    class: Pheature\Crud\Toggle\Handler\RemoveStrategy
+    arguments:
+      - '@Pheature\Core\Toggle\Write\FeatureRepository'
+
+  Pheature\Crud\Toggle\Handler\EnableFeature:
+    class: Pheature\Crud\Toggle\Handler\EnableFeature
+    arguments:
+      - '@Pheature\Core\Toggle\Write\FeatureRepository'
+
+  Pheature\Crud\Toggle\Handler\DisableFeature:
+    class: Pheature\Crud\Toggle\Handler\DisableFeature
+    arguments:
+      - '@Pheature\Core\Toggle\Write\FeatureRepository'
+
+  Pheature\Crud\Toggle\Handler\RemoveFeature:
+    class: Pheature\Crud\Toggle\Handler\RemoveFeature
+    arguments:
+      - '@Pheature\Core\Toggle\Write\FeatureRepository'
diff --git a/packages/toggle-core/composer.json b/packages/toggle-core/composer.json
index 10ffb0c..cd60244 100644
--- a/packages/toggle-core/composer.json
+++ b/packages/toggle-core/composer.json
@@ -16,10 +16,11 @@
         "php": "^7.4|^8.0"
     },
     "require-dev": {
-        "infection/infection": "^0.21.0",
+        "infection/infection": "^0.23.0",
         "phpro/grumphp": "^1.0",
         "phpstan/phpstan": "^0.12",
         "phpunit/phpunit": "^8.0 || ^9.0",
+        "roave/infection-static-analysis-plugin": "^1.8",
         "squizlabs/php_codesniffer": "^3.4",
         "symfony/var-dumper": "^4.2 || ^5.0",
         "vimeo/psalm": "^4.4"
@@ -47,7 +48,7 @@
         "inspect": "phpstan analyse src -l7 --ansi",
         "test": "phpunit --colors=always",
         "psalm": "psalm",
-        "infection": "XDEBUG_MODE=coverage infection"
+        "infection": "XDEBUG_MODE=coverage roave-infection-static-analysis-plugin"
     },
     "config": {
         "sort-packages": true
diff --git a/packages/toggle-crud-psr11-factories/composer.json b/packages/toggle-crud-psr11-factories/composer.json
index e26e68d..81f9aac 100644
--- a/packages/toggle-crud-psr11-factories/composer.json
+++ b/packages/toggle-crud-psr11-factories/composer.json
@@ -20,12 +20,13 @@
         "pheature/toggle-crud-psr7-api": "@dev"
     },
     "require-dev": {
-        "infection/infection": "^0.21.0",
+        "infection/infection": "^0.23.0",
         "pheature/dbal-toggle": "@dev",
         "pheature/inmemory-toggle": "@dev",
         "phpro/grumphp": "^1.0",
         "phpstan/phpstan": "^0.12",
         "phpunit/phpunit": "^8.0 || ^9.0",
+        "roave/infection-static-analysis-plugin": "^1.8",
         "squizlabs/php_codesniffer": "^3.4",
         "symfony/var-dumper": "^4.2 || ^5.0",
         "vimeo/psalm": "^4.4"
@@ -53,7 +54,7 @@
         "inspect": "phpstan analyse src -l7 --ansi",
         "test": "phpunit --colors=always",
         "psalm": "psalm",
-        "infection": "XDEBUG_MODE=coverage infection"
+        "infection": "XDEBUG_MODE=coverage roave-infection-static-analysis-plugin"
     },
     "config": {
         "sort-packages": true
diff --git a/packages/toggle-crud-psr11-factories/phpunit.xml.dist b/packages/toggle-crud-psr11-factories/phpunit.xml.dist
index 76dce4e..f93369d 100644
--- a/packages/toggle-crud-psr11-factories/phpunit.xml.dist
+++ b/packages/toggle-crud-psr11-factories/phpunit.xml.dist
@@ -6,7 +6,7 @@
     </include>
   </coverage>
   <testsuites>
-    <testsuite name="Antidot\\Tests">
+    <testsuite name="Pheature\\Test\\Crud\\Psr11">
       <directory>./test</directory>
     </testsuite>
   </testsuites>
diff --git a/packages/toggle-crud-psr11-factories/src/ToggleConfig.php b/packages/toggle-crud-psr11-factories/src/ToggleConfig.php
index b986cf1..39d4432 100644
--- a/packages/toggle-crud-psr11-factories/src/ToggleConfig.php
+++ b/packages/toggle-crud-psr11-factories/src/ToggleConfig.php
@@ -9,7 +9,7 @@ use Webmozart\Assert\Assert;
 final class ToggleConfig
 {
     private string $driver;
-    private string $prefix;
+    private string $apiPrefix;
     /** @var array<string, mixed> */
     private array $toggles = [];
 
@@ -18,11 +18,11 @@ final class ToggleConfig
      */
     public function __construct(array $config)
     {
-        Assert::keyExists($config, 'prefix');
+        Assert::keyExists($config, 'api_prefix');
         Assert::keyExists($config, 'driver');
-        Assert::string($config['prefix']);
+        Assert::string($config['api_prefix']);
         Assert::string($config['driver']);
-        $this->prefix = $config['prefix'];
+        $this->apiPrefix = $config['api_prefix'];
         $this->driver = $config['driver'];
         if (array_key_exists('toggles', $config)) {
             Assert::isArray($config['toggles']);
@@ -32,9 +32,9 @@ final class ToggleConfig
         }
     }
 
-    public function prefix(): string
+    public function apiPrefix(): string
     {
-        return $this->prefix;
+        return $this->apiPrefix;
     }
 
     public function driver(): string
diff --git a/packages/toggle-crud-psr7-api/composer.json b/packages/toggle-crud-psr7-api/composer.json
index 53a814c..cba94da 100644
--- a/packages/toggle-crud-psr7-api/composer.json
+++ b/packages/toggle-crud-psr7-api/composer.json
@@ -23,10 +23,11 @@
         "webmozart/assert": "^1.10"
     },
     "require-dev": {
-        "infection/infection": "^0.21.0",
+        "infection/infection": "^0.23.0",
         "phpro/grumphp": "^1.0",
         "phpstan/phpstan": "^0.12",
         "phpunit/phpunit": "^8.0 || ^9.0",
+        "roave/infection-static-analysis-plugin": "^1.8",
         "squizlabs/php_codesniffer": "^3.4",
         "symfony/var-dumper": "^4.2 || ^5.0",
         "vimeo/psalm": "^4.4"
@@ -54,7 +55,7 @@
         "inspect": "phpstan analyse src -l7 --ansi",
         "test": "phpunit --colors=always",
         "psalm": "psalm",
-        "infection": "XDEBUG_MODE=coverage infection"
+        "infection": "XDEBUG_MODE=coverage roave-infection-static-analysis-plugin"
     },
     "config": {
         "sort-packages": true
diff --git a/packages/toggle-crud/composer.json b/packages/toggle-crud/composer.json
index 12e7c63..f743e15 100644
--- a/packages/toggle-crud/composer.json
+++ b/packages/toggle-crud/composer.json
@@ -18,7 +18,7 @@
         "pheature/toggle-model": "@dev"
     },
     "require-dev": {
-        "infection/infection": "^0.21.0",
+        "infection/infection": "^0.23.0",
         "phpro/grumphp": "^1.0",
         "phpstan/phpstan": "^0.12",
         "phpunit/phpunit": "^8.0 || ^9.0",
@@ -49,7 +49,7 @@
         "inspect": "phpstan analyse src -l7 --ansi",
         "test": "phpunit --colors=always",
         "psalm": "psalm",
-        "infection": "XDEBUG_MODE=coverage infection"
+        "infection": "XDEBUG_MODE=coverage roave-infection-static-analysis-plugin"
     },
     "config": {
         "sort-packages": true
diff --git a/packages/toggle-model/composer.json b/packages/toggle-model/composer.json
index 01242ae..713feaf 100644
--- a/packages/toggle-model/composer.json
+++ b/packages/toggle-model/composer.json
@@ -17,10 +17,11 @@
         "pheature/toggle-core": "@dev"
     },
     "require-dev": {
-        "infection/infection": "^0.21.0",
+        "infection/infection": "^0.23.0",
         "phpro/grumphp": "^1.0",
         "phpstan/phpstan": "^0.12",
         "phpunit/phpunit": "^8.0 || ^9.0",
+        "roave/infection-static-analysis-plugin": "^1.8",
         "squizlabs/php_codesniffer": "^3.4",
         "symfony/var-dumper": "^4.2 || ^5.0",
         "vimeo/psalm": "^4.4"
@@ -48,7 +49,7 @@
         "inspect": "phpstan analyse src -l7 --ansi",
         "test": "phpunit --colors=always",
         "psalm": "psalm",
-        "infection": "XDEBUG_MODE=coverage infection"
+        "infection": "XDEBUG_MODE=coverage roave-infection-static-analysis-plugin"
     },
     "config": {
         "sort-packages": true


Test patch:
diff --git a/packages/symfony-toggle/test/DependencyInjection/ConfigurationTest.php b/packages/symfony-toggle/test/DependencyInjection/ConfigurationTest.php
index 1f6c8b4..ab2306f 100644
--- a/packages/symfony-toggle/test/DependencyInjection/ConfigurationTest.php
+++ b/packages/symfony-toggle/test/DependencyInjection/ConfigurationTest.php
@@ -10,7 +10,7 @@ use PHPUnit\Framework\TestCase;
 use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
 use Symfony\Component\Config\Definition\Processor;
 
-class ConfigurationTest extends TestCase
+final class ConfigurationTest extends TestCase
 {
     /** @dataProvider validConfigurations */
     public function testItShouldReturnAConfiguration(array $actualConfig, array $expectedConfig): void
@@ -37,21 +37,23 @@ class ConfigurationTest extends TestCase
         yield 'user does not define any config' => [
             'user config' => [],
             'expected config' => [
-                'prefix' => '',
+                'api_prefix' => '',
+                'api_enabled' => false,
                 'strategy_types' => [],
                 'segment_types' => [],
                 'toggles' => [],
             ]
         ];
 
-        yield 'user defines only the prefix' => [
+        yield 'user defines only the api_prefix' => [
             'user config' => [
                 'pheature_flags' => [
-                    'prefix' => 'myapp',
+                    'api_prefix' => 'myapp',
                 ],
             ],
             'expected config' => [
-                'prefix' => 'myapp',
+                'api_prefix' => 'myapp',
+                'api_enabled' => false,
                 'strategy_types' => [],
                 'segment_types' => [],
                 'toggles' => [],
@@ -65,7 +67,8 @@ class ConfigurationTest extends TestCase
                 ],
             ],
             'expected config' => [
-                'prefix' => '',
+                'api_prefix' => '',
+                'api_enabled' => false,
                 'driver' => 'dbal',
                 'strategy_types' => [],
                 'segment_types' => [],
@@ -85,7 +88,8 @@ class ConfigurationTest extends TestCase
                 ],
             ],
             'expected config' => [
-                'prefix' => '',
+                'api_prefix' => '',
+                'api_enabled' => false,
                 'strategy_types' => [
                     [
                         'type' => 'my_strategy_type',
@@ -109,7 +113,8 @@ class ConfigurationTest extends TestCase
                 ],
             ],
             'expected config' => [
-                'prefix' => '',
+                'api_prefix' => '',
+                'api_enabled' => false,
                 'strategy_types' => [],
                 'segment_types' => [
                     [
@@ -148,7 +153,8 @@ class ConfigurationTest extends TestCase
                 ],
             ],
             'expected config' => [
-                'prefix' => '',
+                'api_prefix' => '',
+                'api_enabled' => false,
                 'strategy_types' => [],
                 'segment_types' => [],
                 'toggles' => [
diff --git a/packages/symfony-toggle/test/DependencyInjection/FeatureRepositoryFactoryPassTest.php b/packages/symfony-toggle/test/DependencyInjection/FeatureRepositoryFactoryPassTest.php
index 2185388..8c53a08 100644
--- a/packages/symfony-toggle/test/DependencyInjection/FeatureRepositoryFactoryPassTest.php
+++ b/packages/symfony-toggle/test/DependencyInjection/FeatureRepositoryFactoryPassTest.php
@@ -19,7 +19,7 @@ final class FeatureRepositoryFactoryPassTest extends TestCase
         $container = TestContainerFactory::create($compilerPass);
         $container->register(ToggleConfig::class, ToggleConfig::class)->addArgument([
             'driver' => 'inmemory',
-            'prefix' => '',
+            'api_prefix' => '',
         ]);
 
         $featureRepositoryFactoryDefinition = $container->getDefinition(FeatureRepository::class);
@@ -37,7 +37,7 @@ final class FeatureRepositoryFactoryPassTest extends TestCase
         $container = TestContainerFactory::create($compilerPass, 'dbal');
         $container->register(ToggleConfig::class, ToggleConfig::class)->addArgument([
             'driver' => 'dbal',
-            'prefix' => '',
+            'api_prefix' => '',
         ]);
         $container->register(Connection::class, Connection::class)
             ->setFactory([DriverManager::class, 'getConnection'])
diff --git a/packages/symfony-toggle/test/DependencyInjection/Fixtures/PheatureFlagsConfig.php b/packages/symfony-toggle/test/DependencyInjection/Fixtures/PheatureFlagsConfig.php
new file mode 100644
index 0000000..2560b12
--- /dev/null
+++ b/packages/symfony-toggle/test/DependencyInjection/Fixtures/PheatureFlagsConfig.php
@@ -0,0 +1,73 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Pheature\Test\Community\Symfony\DependencyInjection\Fixtures;
+
+use Pheature\Model\Toggle\EnableByMatchingIdentityId;
+use Pheature\Model\Toggle\EnableByMatchingSegment;
+use Pheature\Model\Toggle\IdentitySegment;
+use Pheature\Model\Toggle\SegmentFactory;
+use Pheature\Model\Toggle\StrategyFactory;
+use Pheature\Model\Toggle\StrictMatchingSegment;
+
+final class PheatureFlagsConfig
+{
+    private array $config;
+
+    public function __construct(array $config)
+    {
+        $this->config = $config;
+    }
+
+    public static function createDefault(): self
+    {
+        $defaultConfig = [
+            'driver' => 'inmemory',
+            'api_prefix' => '',
+            'api_enabled' => false,
+            'segment_types' => [
+                [
+                    'type' => IdentitySegment::NAME,
+                    'factory_id' => SegmentFactory::class
+                ],
+                [
+                    'type' => StrictMatchingSegment::NAME,
+                    'factory_id' => SegmentFactory::class
+                ]
+            ],
+            'strategy_types' => [
+                [
+                    'type' => EnableByMatchingSegment::NAME,
+                    'factory_id' => StrategyFactory::class
+                ],
+                [
+                    'type' => EnableByMatchingIdentityId::NAME,
+                    'factory_id' => StrategyFactory::class
+                ]
+            ],
+            'toggles' => [],
+        ];
+
+        return new self($defaultConfig);
+    }
+
+    public function withApiEnabled(bool $enabled): self
+    {
+        $this->config['api_enabled'] = $enabled;
+
+        return $this;
+    }
+
+    public function withApiPrefix(string $prefix): self
+    {
+        $this->config['api_prefix'] = $prefix;
+
+        return $this;
+    }
+
+    public function build(): array
+    {
+        return $this->config;
+    }
+}
diff --git a/packages/symfony-toggle/test/DependencyInjection/TestContainerFactory.php b/packages/symfony-toggle/test/DependencyInjection/TestContainerFactory.php
index 06c96b8..3660d0d 100644
--- a/packages/symfony-toggle/test/DependencyInjection/TestContainerFactory.php
+++ b/packages/symfony-toggle/test/DependencyInjection/TestContainerFactory.php
@@ -8,25 +8,36 @@ use Pheature\Community\Symfony\DependencyInjection\PheatureFlagsExtension;
 use Symfony\Component\Config\FileLocator;
 use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
 use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
 
 final class TestContainerFactory
 {
-    public static function create(CompilerPassInterface $compilerPass, string $driver = 'inmemory'): ContainerBuilder
+    public static function create(CompilerPassInterface $compilerPass, ?string $driver = null, array $config = []): ContainerBuilder
     {
         $containerBuilder = new ContainerBuilder();
         $extension = new PheatureFlagsExtension();
         $containerBuilder->registerExtension($extension);
 
-        $phpFileLoader = new YamlFileLoader($containerBuilder, new FileLocator());
+        if (!empty($config)) {
+            $containerBuilder->loadFromExtension('pheature_flags', $config);
+
+            $compilerPass->process($containerBuilder);
+
+            return $containerBuilder;
+        }
+
+        $driver = $driver ?? 'inmemory';
+
+        $yamlFileLoader = new YamlFileLoader($containerBuilder, new FileLocator());
         if ('inmemory' === $driver) {
-            $phpFileLoader->load(realpath(__DIR__ . '/../../config/config.yaml'));
+            $yamlFileLoader->load(realpath(__DIR__ . '/../../config/config.yaml'));
         }
         if ('dbal' === $driver) {
-            $phpFileLoader->load(realpath(__DIR__ . '/../../config/dbal_config.yaml'));
+            $yamlFileLoader->load(realpath(__DIR__ . '/../../config/dbal_config.yaml'));
         }
         $compilerPass->process($containerBuilder);
 
         return $containerBuilder;
     }
-}
\ No newline at end of file
+}
diff --git a/packages/symfony-toggle/test/DependencyInjection/ToggleAPIPassTest.php b/packages/symfony-toggle/test/DependencyInjection/ToggleAPIPassTest.php
new file mode 100644
index 0000000..93b4fe3
--- /dev/null
+++ b/packages/symfony-toggle/test/DependencyInjection/ToggleAPIPassTest.php
@@ -0,0 +1,77 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Pheature\Test\Community\Symfony\DependencyInjection;
+
+use Pheature\Community\Symfony\DependencyInjection\ToggleAPIPass;
+use Pheature\Test\Community\Symfony\DependencyInjection\Fixtures\PheatureFlagsConfig;
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\Config\Resource\FileResource;
+use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
+
+final class ToggleAPIPassTest extends TestCase
+{
+    public function testItShouldNotLoadApiServicesInContainer(): void
+    {
+        $config = PheatureFlagsConfig::createDefault()
+            ->withApiEnabled(false)
+            ->build();
+
+        $compilerPass = new ToggleAPIPass();
+        $container = TestContainerFactory::create($compilerPass, null, $config);
+
+        $this->expectException(ParameterNotFoundException::class);
+        $container->getParameter('pheature_flags_prefix');
+
+        $expectedLoadedResources = 0;
+        $loadedResources = $container->getResources();
+        self::assertCount($expectedLoadedResources, $loadedResources);
+    }
+
+    public function testItShouldLoadApiServicesInContainer(): void
+    {
+        $expectedPrefix = 'a-prefix';
+
+        $config = PheatureFlagsConfig::createDefault()
+            ->withApiEnabled(true)
+            ->withApiPrefix($expectedPrefix)
+            ->build();
+
+        $compilerPass = new ToggleAPIPass();
+        $container = TestContainerFactory::create($compilerPass, null, $config);
+
+        self::assertSame($expectedPrefix, $container->getParameter('pheature_flags_prefix'));
+
+        $loadedResources = $container->getResources();
+
+        self::assertCount(2, $loadedResources);
+
+        $this->assertSimilarResourceIn('src/Resources/config/toggle_api/services/controller_services.yaml',
+            $loadedResources);
+        $this->assertSimilarResourceIn('src/Resources/config/toggle_api/services/handler_services.yaml',
+            $loadedResources);
+    }
+
+    private function assertSimilarResourceIn(string $similarResource, array $currentResources): void
+    {
+        /** @var FileResource $currentResource */
+        foreach ($currentResources as $currentResource) {
+            if (false !== strpos($currentResource->getResource(), $similarResource)) {
+                return;
+            }
+        }
+
+        $actualResources = json_encode(
+            array_map(static fn(FileResource $fileResource) => $fileResource->getResource(), $currentResources)
+        );
+
+        self::fail(
+            sprintf(
+                'Similar resource "%s" not found in current resources: [%s]',
+                $similarResource,
+                $actualResources
+            )
+        );
+    }
+}
diff --git a/packages/toggle-crud-psr11-factories/test/FeatureFinderFactoryTest.php b/packages/toggle-crud-psr11-factories/test/FeatureFinderFactoryTest.php
index 8803cec..9d2d4ae 100644
--- a/packages/toggle-crud-psr11-factories/test/FeatureFinderFactoryTest.php
+++ b/packages/toggle-crud-psr11-factories/test/FeatureFinderFactoryTest.php
@@ -25,7 +25,7 @@ class FeatureFinderFactoryTest extends TestCase
             $this->createMock(SegmentFactory::class),
             $this->createMock(ToggleStrategyFactory::class),
         );
-        $toggleConfig = new ToggleConfig(['prefix' => '', 'driver' => 'some_other']);
+        $toggleConfig = new ToggleConfig(['api_prefix' => '', 'driver' => 'some_other']);
 
         $container->expects(self::exactly(3))
             ->method('get')
@@ -41,7 +41,7 @@ class FeatureFinderFactoryTest extends TestCase
     public function testItShouldCreateADBalFeatureFinderFromInvokable(): void
     {
         $container = $this->createMock(ContainerInterface::class);
-        $toggleConfig = new ToggleConfig(['prefix' => '', 'driver' => 'dbal']);
+        $toggleConfig = new ToggleConfig(['api_prefix' => '', 'driver' => 'dbal']);
         $chainStrategyFactory = new ChainToggleStrategyFactory(
             $this->createMock(SegmentFactory::class),
             $this->createMock(ToggleStrategyFactory::class),
@@ -62,7 +62,7 @@ class FeatureFinderFactoryTest extends TestCase
     public function testItShouldCreateAnInMemoryFeatureFinderFromInvokable(): void
     {
         $container = $this->createMock(ContainerInterface::class);
-        $toggleConfig = new ToggleConfig(['prefix' => '', 'driver' => 'inmemory']);
+        $toggleConfig = new ToggleConfig(['api_prefix' => '', 'driver' => 'inmemory']);
         $chainStrategyFactory = new ChainToggleStrategyFactory(
             $this->createMock(SegmentFactory::class),
             $this->createMock(ToggleStrategyFactory::class),
@@ -81,7 +81,7 @@ class FeatureFinderFactoryTest extends TestCase
 
     public function testItShouldCreateADBalFeatureFinderFromCreate(): void
     {
-        $toggleConfig = new ToggleConfig(['prefix' => '', 'driver' => 'dbal']);
+        $toggleConfig = new ToggleConfig(['api_prefix' => '', 'driver' => 'dbal']);
         $chainStrategyFactory = new ChainToggleStrategyFactory(
             $this->createMock(SegmentFactory::class),
             $this->createMock(ToggleStrategyFactory::class),
@@ -93,7 +93,7 @@ class FeatureFinderFactoryTest extends TestCase
 
     public function testItShouldCreateInMemoryFeatureFinderFromCreate(): void
     {
-        $toggleConfig = new ToggleConfig(['prefix' => '', 'driver' => 'inmemory']);
+        $toggleConfig = new ToggleConfig(['api_prefix' => '', 'driver' => 'inmemory']);
         $chainStrategyFactory = new ChainToggleStrategyFactory(
             $this->createMock(SegmentFactory::class),
             $this->createMock(ToggleStrategyFactory::class),
diff --git a/packages/toggle-crud-psr11-factories/test/FeatureRepositoryFactoryTest.php b/packages/toggle-crud-psr11-factories/test/FeatureRepositoryFactoryTest.php
index 0390034..5dece48 100644
--- a/packages/toggle-crud-psr11-factories/test/FeatureRepositoryFactoryTest.php
+++ b/packages/toggle-crud-psr11-factories/test/FeatureRepositoryFactoryTest.php
@@ -21,7 +21,7 @@ class FeatureRepositoryFactoryTest extends TestCase
     {
         $this->expectException(InvalidArgumentException::class);
         $container = $this->createMock(ContainerInterface::class);
-        $toggleConfig = new ToggleConfig(['prefix' => '', 'driver' => 'some_other']);
+        $toggleConfig = new ToggleConfig(['api_prefix' => '', 'driver' => 'some_other']);
 
         $container->expects(self::exactly(2))
             ->method('get')
@@ -36,7 +36,7 @@ class FeatureRepositoryFactoryTest extends TestCase
     public function testItShouldCreateADBalFeatureRepositoryFromInvokable(): void
     {
         $container = $this->createMock(ContainerInterface::class);
-        $toggleConfig = new ToggleConfig(['prefix' => '', 'driver' => 'dbal']);
+        $toggleConfig = new ToggleConfig(['api_prefix' => '', 'driver' => 'dbal']);
         $connection = $this->createMock(Connection::class);
 
         $container->expects(static::exactly(2))
@@ -53,7 +53,7 @@ class FeatureRepositoryFactoryTest extends TestCase
     public function testItShouldCreateAnInMemoryFeatureRepositoryFromInvokable(): void
     {
         $container = $this->createMock(ContainerInterface::class);
-        $toggleConfig = new ToggleConfig(['prefix' => '', 'driver' => 'inmemory']);
+        $toggleConfig = new ToggleConfig(['api_prefix' => '', 'driver' => 'inmemory']);
 
         $container->expects(static::exactly(2))
             ->method('get')
@@ -68,7 +68,7 @@ class FeatureRepositoryFactoryTest extends TestCase
 
     public function testItShouldCreateADBalFeatureRepositoryFromCreate(): void
     {
-        $toggleConfig = new ToggleConfig(['prefix' => '', 'driver' => 'dbal']);
+        $toggleConfig = new ToggleConfig(['api_prefix' => '', 'driver' => 'dbal']);
         $connection = $this->createMock(Connection::class);
         $featureRepository = FeatureRepositoryFactory::create($toggleConfig, $connection);
         self::assertInstanceOf(FeatureRepository::class, $featureRepository);
@@ -76,7 +76,7 @@ class FeatureRepositoryFactoryTest extends TestCase
 
     public function testItShouldCreateInMemoryFeatureRepositoryFromCreate(): void
     {
-        $toggleConfig = new ToggleConfig(['prefix' => '', 'driver' => 'inmemory']);
+        $toggleConfig = new ToggleConfig(['api_prefix' => '', 'driver' => 'inmemory']);
         $connection = null;
         $featureRepository = FeatureRepositoryFactory::create($toggleConfig, $connection);
         self::assertInstanceOf(FeatureRepository::class, $featureRepository);