diff --git a/docs/configuration.md b/docs/configuration.md index 39eacd2e..4eb0d471 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -34,10 +34,11 @@ $testContainer = $builder->getTestContainer(); * `ContainerBuilder#addPass()`: Adds an instance of a [Compiler Pass](compiler-passes.md) to be processed * `ContainerBuilder#addDelayedPass()`: Adds a reference (class name and constructor arguments) of a [Compiler Pass](compiler-passes.md) to be processed * `ContainerBuilder#addPackage()`: Adds a reference (class name and constructor arguments) of a [Package](packages.md) to be processed -* `ContainerBuilder#useDevelopmentMode()`: Optimises the generate container for development purposes (configures the compiler to track file changes and update the cache) +* `ContainerBuilder#enableDebugging()`: Configures the compiler to track file changes and update the cache, optimised for local development purposes * `ContainerBuilder#setDumpDir()`: Configures the directory to be used to dump the cache files * `ContainerBuilder#setParameter()`: Configures a dynamic parameter * `ContainerBuilder#setBaseClass()`: Modifies which class should be used as base class for the container +* `ContainerBuilder#setProfileName()`: Enables the loading of application profile-specific services via the `when@{profile-name}` syntax ## Configuration file example @@ -59,11 +60,12 @@ require __DIR__ . '/../vendor/autoload.php'; $builder = ContainerBuilder::xml(__FILE__, __NAMESPACE__); $projectRoot = dirname(__DIR__); -if (getenv('APPLICATION_MODE', true) === 'development') { - $builder->useDevelopmentMode(); +if (getenv('APP_PROFILE') !== 'prod') { + $builder->enableDebugging(); } -return $builder->setDumpDir($projectRoot . '/var/tmp') +return $builder->setProfileName(getenv('APP_PROFILE')) + ->setDumpDir($projectRoot . '/var/tmp') ->setParameter('app.basedir', $projectRoot) ->addFile(__DIR__ . '/container.xml') ->getContainer(); diff --git a/src/Builder.php b/src/Builder.php index 9725bc53..0393805b 100644 --- a/src/Builder.php +++ b/src/Builder.php @@ -53,11 +53,25 @@ public function addDelayedPass( */ public function addPackage(string $className, array $constructArguments = []): Builder; + /** + * Configures the application profile name to support profile-specific services + */ + public function setProfileName(string $profileName): Builder; + /** * Mark the container to be used as development mode + * + * @deprecated this method will be removed in favour of a more explicit name. + * + * @see enableDebugging */ public function useDevelopmentMode(): Builder; + /** + * Configure the container to track file updates + */ + public function enableDebugging(): Builder; + /** * Configures the dump directory */ diff --git a/src/Config/ContainerConfiguration.php b/src/Config/ContainerConfiguration.php index fd561c02..c64378d9 100644 --- a/src/Config/ContainerConfiguration.php +++ b/src/Config/ContainerConfiguration.php @@ -31,6 +31,8 @@ final class ContainerConfiguration private string $dumpDir; + private ?string $profileName = null; + /** * phpcs:disable Generic.Files.LineLength * @@ -51,6 +53,16 @@ public function __construct( $this->dumpDir = sys_get_temp_dir(); } + public function setProfileName(string $profileName): void + { + $this->profileName = $profileName; + } + + public function profileName(): ?string + { + return $this->profileName; + } + /** @return Package[] */ public function getPackages(): array { @@ -183,6 +195,7 @@ public function getDumpFile(): string { return $this->dumpDir . DIRECTORY_SEPARATOR . strtolower(str_replace('\\', '_', $this->namespace)) . DIRECTORY_SEPARATOR + . ($this->profileName !== null ? $this->profileName . DIRECTORY_SEPARATOR : '') . self::CLASS_NAME . '.php'; } diff --git a/src/ContainerBuilder.php b/src/ContainerBuilder.php index 1524752c..9aa752e9 100644 --- a/src/ContainerBuilder.php +++ b/src/ContainerBuilder.php @@ -38,11 +38,11 @@ public static function default(string $configurationFile, string $namespace): se return self::xml($configurationFile, $namespace); } - /** @param class-string|null $builderClass */ + /** @param class-string $builderClass */ public static function xml( string $configurationFile, string $namespace, - ?string $builderClass = null, + string $builderClass = SymfonyBuilder::class, ): self { return new self( new ContainerConfiguration($namespace), @@ -51,11 +51,11 @@ public static function xml( ); } - /** @param class-string|null $builderClass */ + /** @param class-string $builderClass */ public static function php( string $configurationFile, string $namespace, - ?string $builderClass = null, + string $builderClass = SymfonyBuilder::class, ): self { return new self( new ContainerConfiguration($namespace), @@ -64,11 +64,11 @@ public static function php( ); } - /** @param class-string|null $builderClass */ + /** @param class-string $builderClass */ public static function yaml( string $configurationFile, string $namespace, - ?string $builderClass = null, + string $builderClass = SymfonyBuilder::class, ): self { return new self( new ContainerConfiguration($namespace), @@ -77,11 +77,11 @@ public static function yaml( ); } - /** @param class-string|null $builderClass */ + /** @param class-string $builderClass */ public static function delegating( string $configurationFile, string $namespace, - ?string $builderClass = null, + string $builderClass = SymfonyBuilder::class, ): self { return new self( new ContainerConfiguration($namespace), @@ -144,7 +144,19 @@ public function addPackage(string $className, array $constructArguments = []): B return $this; } + public function setProfileName(string $profileName): Builder + { + $this->config->setProfileName($profileName); + + return $this; + } + public function useDevelopmentMode(): Builder + { + return $this->enableDebugging(); + } + + public function enableDebugging(): Builder { $this->parameterBag->set('app.devmode', true); diff --git a/src/Generator.php b/src/Generator.php index be728d4c..3c81d4e3 100644 --- a/src/Generator.php +++ b/src/Generator.php @@ -16,16 +16,13 @@ abstract class Generator { private Compiler $compiler; - /** @var class-string */ - private string $builderClass; - /** @param class-string|null $builderClass */ + /** @param class-string $builderClass */ public function __construct( - private string $configurationFile, - ?string $builderClass = null, + private readonly string $configurationFile, + private readonly string $builderClass = SymfonyBuilder::class, ) { - $this->compiler = new Compiler(); - $this->builderClass = $builderClass ?? SymfonyBuilder::class; + $this->compiler = new Compiler(); } /** @@ -54,7 +51,7 @@ public function initializeContainer(ContainerConfiguration $config): SymfonyBuil $container = new $this->builderClass(); $container->addResource(new FileResource($this->configurationFile)); - $loader = $this->getLoader($container, $config->getPaths()); + $loader = $this->getLoader($container, $config->getPaths(), $config->profileName()); foreach ($config->getFiles() as $file) { $loader->load($file); @@ -64,5 +61,9 @@ public function initializeContainer(ContainerConfiguration $config): SymfonyBuil } /** @param string[] $paths */ - abstract public function getLoader(SymfonyBuilder $container, array $paths): LoaderInterface; + abstract public function getLoader( + SymfonyBuilder $container, + array $paths, + ?string $profileName = null, + ): LoaderInterface; } diff --git a/src/Generators/Delegating.php b/src/Generators/Delegating.php index 178b36c5..4e0eb481 100644 --- a/src/Generators/Delegating.php +++ b/src/Generators/Delegating.php @@ -19,16 +19,16 @@ final class Delegating extends Generator { /** @inheritDoc */ - public function getLoader(SymfonyBuilder $container, array $paths): LoaderInterface + public function getLoader(SymfonyBuilder $container, array $paths, ?string $profileName = null): LoaderInterface { $locator = new FileLocator($paths); return new DelegatingLoader( new LoaderResolver( [ - new XmlFileLoader($container, $locator), - new YamlFileLoader($container, $locator), - new PhpFileLoader($container, $locator), + new XmlFileLoader($container, $locator, $profileName), + new YamlFileLoader($container, $locator, $profileName), + new PhpFileLoader($container, $locator, $profileName), ], ), ); diff --git a/src/Generators/Php.php b/src/Generators/Php.php index a998b801..85c34b00 100644 --- a/src/Generators/Php.php +++ b/src/Generators/Php.php @@ -15,11 +15,12 @@ final class Php extends Generator { /** @inheritDoc */ - public function getLoader(SymfonyBuilder $container, array $paths): LoaderInterface + public function getLoader(SymfonyBuilder $container, array $paths, ?string $profileName = null): LoaderInterface { return new PhpFileLoader( $container, new FileLocator($paths), + $profileName, ); } } diff --git a/src/Generators/Xml.php b/src/Generators/Xml.php index 9400c8ba..dba92122 100644 --- a/src/Generators/Xml.php +++ b/src/Generators/Xml.php @@ -15,11 +15,12 @@ final class Xml extends Generator { /** @inheritDoc */ - public function getLoader(SymfonyBuilder $container, array $paths): LoaderInterface + public function getLoader(SymfonyBuilder $container, array $paths, ?string $profileName = null): LoaderInterface { return new XmlFileLoader( $container, new FileLocator($paths), + $profileName, ); } } diff --git a/src/Generators/Yaml.php b/src/Generators/Yaml.php index 6ba588b4..668057ba 100644 --- a/src/Generators/Yaml.php +++ b/src/Generators/Yaml.php @@ -15,11 +15,12 @@ final class Yaml extends Generator { /** @inheritDoc */ - public function getLoader(SymfonyBuilder $container, array $paths): LoaderInterface + public function getLoader(SymfonyBuilder $container, array $paths, ?string $profileName = null): LoaderInterface { return new YamlFileLoader( $container, new FileLocator($paths), + $profileName, ); } } diff --git a/test/Config/ContainerConfigurationTest.php b/test/Config/ContainerConfigurationTest.php index e348397d..c1dfc5bd 100644 --- a/test/Config/ContainerConfigurationTest.php +++ b/test/Config/ContainerConfigurationTest.php @@ -289,6 +289,19 @@ public function getDumpFileShouldReturnTheFullPathOfDumpFile(): void ); } + #[PHPUnit\Test] + public function getDumpFileShouldIncludeProfileNameWhenItIsSet(): void + { + $config = new ContainerConfiguration('Me\\MyApp'); + $config->setProfileName('prod'); + + self::assertEquals( + sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'me_myapp' . DIRECTORY_SEPARATOR + . 'prod' . DIRECTORY_SEPARATOR . 'AppContainer.php', + $config->getDumpFile(), + ); + } + #[PHPUnit\Test] public function getDumpOptionsShouldReturnTheDumpingInformation(): void { @@ -357,4 +370,16 @@ public function withAddedNamespaceShouldModifyTheNamespaceOfANewInstanceOnly(): self::assertSame('Me\\MyApp\\AppContainer', $config->getClassName()); self::assertSame('Me\\MyApp\\Testing\\AppContainer', $other->getClassName()); } + + #[PHPUnit\Test] + public function profileNameShouldBeConfigurable(): void + { + $config = new ContainerConfiguration('Me\\MyApp'); + + self::assertNull($config->profileName()); + + $config->setProfileName('test'); + + self::assertSame('test', $config->profileName()); + } } diff --git a/test/ContainerBuilderTest.php b/test/ContainerBuilderTest.php index a004e480..d61f4bb7 100644 --- a/test/ContainerBuilderTest.php +++ b/test/ContainerBuilderTest.php @@ -14,6 +14,7 @@ use Symfony\Component\Config\ConfigCache; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\PassConfig; +use Symfony\Component\DependencyInjection\ContainerBuilder as SymfonyBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use function get_class; @@ -43,7 +44,7 @@ public function configureDependencies(): void public function namedConstructorsShouldSimplifyTheObjectCreation( string $method, Generator $generator, - ?string $builderClass = null, + string $builderClass = SymfonyBuilder::class, ): void { $expected = new ContainerBuilder( new ContainerConfiguration('Lcobucci\\DependencyInjection'), @@ -177,11 +178,11 @@ public function setBaseClassShouldConfigureTheBaseClassAndReturnSelf(): void } #[PHPUnit\Test] - public function useDevelopmentModeShouldChangeTheParameterAndReturnSelf(): void + public function enableDebuggingShouldChangeTheParameterAndReturnSelf(): void { $builder = new ContainerBuilder($this->config, $this->generator, $this->parameterBag); - self::assertSame($builder, $builder->useDevelopmentMode()); + self::assertSame($builder, $builder->enableDebugging()); self::assertTrue($this->parameterBag->get('app.devmode')); } @@ -231,4 +232,13 @@ public function getTestContainerShouldGenerateAndReturnTheContainer(): void self::assertCount(1, $compilerPasses); self::assertSame($this->parameterBag, $compilerPasses[0][0]); } + + #[PHPUnit\Test] + public function profileNameShouldBeConfigurable(): void + { + $builder = new ContainerBuilder($this->config, $this->generator, $this->parameterBag); + $builder->setProfileName('testing'); + + self::assertSame('testing', $this->config->profileName()); + } }