From 0307872177a09a81049bc9267538cd72783c849a Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Thu, 23 Nov 2023 15:37:17 +0200 Subject: [PATCH 1/2] Add BootloaderRules and checkers --- src/Boot/src/AbstractKernel.php | 3 +- src/Boot/src/Attribute/BootloaderRules.php | 20 ++ .../AbstractBootloadManager.php | 13 +- .../Checker/BootloaderChecker.php | 27 +++ .../Checker/BootloaderCheckerInterface.php | 16 ++ .../Checker/CanBootedChecker.php | 27 +++ .../Checker/CheckerRegistry.php | 26 +++ .../Checker/CheckerRegistryInterface.php | 15 ++ .../Checker/ClassExistsChecker.php | 28 +++ .../BootloadManager/Checker/RulesChecker.php | 44 ++++ .../DefaultInvokerStrategy.php | 11 +- src/Boot/src/BootloadManager/Initializer.php | 107 ++++++++-- .../StrategyBasedBootloadManager.php | 11 +- .../AttributeBootloaderRulesTest.php | 150 ++++++++++++++ .../BootloadManager/BootloadManagerTest.php | 28 +-- .../BootloadManager/BootloaderRulesTest.php | 193 ++++++++++++++++++ .../tests/BootloadManager/BootloadersTest.php | 54 +++-- .../Checker/BootloaderCheckerTest.php | 45 ++++ .../Checker/CanBootedCheckerTest.php | 48 +++++ .../Checker/ClassExistsCheckerTest.php | 29 +++ .../Checker/RulesCheckerTest.php | 56 +++++ .../BootloadManager/DependenciesTest.php | 17 +- .../tests/BootloadManager/InitializerTest.php | 11 +- .../BootloadManager/InitializerTestCase.php | 20 ++ .../MergeBootloaderRulesTest.php | 112 ++++++++++ .../tests/Fixtures/Attribute/TargetWorker.php | 17 ++ src/Boot/tests/Fixtures/BootloaderE.php | 12 ++ src/Boot/tests/Fixtures/BootloaderF.php | 12 ++ src/Boot/tests/Fixtures/BootloaderG.php | 12 ++ src/Boot/tests/Fixtures/BootloaderH.php | 16 ++ src/Boot/tests/Fixtures/BootloaderI.php | 16 ++ src/Boot/tests/Fixtures/BootloaderJ.php | 12 ++ src/Boot/tests/Fixtures/BootloaderK.php | 12 ++ src/Boot/tests/TestCase.php | 18 +- 34 files changed, 1140 insertions(+), 98 deletions(-) create mode 100644 src/Boot/src/Attribute/BootloaderRules.php create mode 100644 src/Boot/src/BootloadManager/Checker/BootloaderChecker.php create mode 100644 src/Boot/src/BootloadManager/Checker/BootloaderCheckerInterface.php create mode 100644 src/Boot/src/BootloadManager/Checker/CanBootedChecker.php create mode 100644 src/Boot/src/BootloadManager/Checker/CheckerRegistry.php create mode 100644 src/Boot/src/BootloadManager/Checker/CheckerRegistryInterface.php create mode 100644 src/Boot/src/BootloadManager/Checker/ClassExistsChecker.php create mode 100644 src/Boot/src/BootloadManager/Checker/RulesChecker.php create mode 100644 src/Boot/tests/BootloadManager/AttributeBootloaderRulesTest.php create mode 100644 src/Boot/tests/BootloadManager/BootloaderRulesTest.php create mode 100644 src/Boot/tests/BootloadManager/Checker/BootloaderCheckerTest.php create mode 100644 src/Boot/tests/BootloadManager/Checker/CanBootedCheckerTest.php create mode 100644 src/Boot/tests/BootloadManager/Checker/ClassExistsCheckerTest.php create mode 100644 src/Boot/tests/BootloadManager/Checker/RulesCheckerTest.php create mode 100644 src/Boot/tests/BootloadManager/InitializerTestCase.php create mode 100644 src/Boot/tests/BootloadManager/MergeBootloaderRulesTest.php create mode 100644 src/Boot/tests/Fixtures/Attribute/TargetWorker.php create mode 100644 src/Boot/tests/Fixtures/BootloaderE.php create mode 100644 src/Boot/tests/Fixtures/BootloaderF.php create mode 100644 src/Boot/tests/Fixtures/BootloaderG.php create mode 100644 src/Boot/tests/Fixtures/BootloaderH.php create mode 100644 src/Boot/tests/Fixtures/BootloaderI.php create mode 100644 src/Boot/tests/Fixtures/BootloaderJ.php create mode 100644 src/Boot/tests/Fixtures/BootloaderK.php diff --git a/src/Boot/src/AbstractKernel.php b/src/Boot/src/AbstractKernel.php index f89190927..3ae0b6f0f 100644 --- a/src/Boot/src/AbstractKernel.php +++ b/src/Boot/src/AbstractKernel.php @@ -173,7 +173,8 @@ public function run(?EnvironmentInterface $environment = null): ?self function (Container $container): void { $registry = $container->get(BootloaderRegistryInterface::class); - $this->bootloader->bootload($registry->getSystemBootloaders()); + /** @psalm-suppress TooManyArguments */ + $this->bootloader->bootload($registry->getSystemBootloaders(), [], [], false); $this->fireCallbacks($this->runningCallbacks); $this->bootload($registry->getBootloaders()); diff --git a/src/Boot/src/Attribute/BootloaderRules.php b/src/Boot/src/Attribute/BootloaderRules.php new file mode 100644 index 000000000..c7d23d0e9 --- /dev/null +++ b/src/Boot/src/Attribute/BootloaderRules.php @@ -0,0 +1,20 @@ +initializer->getRegistry()->getClasses(); } - public function bootload(array $classes, array $bootingCallbacks = [], array $bootedCallbacks = []): void - { + public function bootload( + array $classes, + array $bootingCallbacks = [], + array $bootedCallbacks = [], + bool $useRules = true + ): void { $this->scope->runScope( [self::class => $this], - function () use ($classes, $bootingCallbacks, $bootedCallbacks): void { - $this->boot($classes, $bootingCallbacks, $bootedCallbacks); + function () use ($classes, $bootingCallbacks, $bootedCallbacks, $useRules): void { + /** @psalm-suppress TooManyArguments */ + $this->boot($classes, $bootingCallbacks, $bootedCallbacks, $useRules); } ); } diff --git a/src/Boot/src/BootloadManager/Checker/BootloaderChecker.php b/src/Boot/src/BootloadManager/Checker/BootloaderChecker.php new file mode 100644 index 000000000..d2ce96e38 --- /dev/null +++ b/src/Boot/src/BootloadManager/Checker/BootloaderChecker.php @@ -0,0 +1,27 @@ +registry->getCheckers() as $checker) { + if (!$checker->canInitialize($bootloader, $rules)) { + return false; + } + } + + return true; + } +} diff --git a/src/Boot/src/BootloadManager/Checker/BootloaderCheckerInterface.php b/src/Boot/src/BootloadManager/Checker/BootloaderCheckerInterface.php new file mode 100644 index 000000000..fabde876b --- /dev/null +++ b/src/Boot/src/BootloadManager/Checker/BootloaderCheckerInterface.php @@ -0,0 +1,16 @@ +|BootloaderInterface $bootloader + */ + public function canInitialize(string|BootloaderInterface $bootloader, ?BootloaderRules $rules = null): bool; +} diff --git a/src/Boot/src/BootloadManager/Checker/CanBootedChecker.php b/src/Boot/src/BootloadManager/Checker/CanBootedChecker.php new file mode 100644 index 000000000..91441f7d2 --- /dev/null +++ b/src/Boot/src/BootloadManager/Checker/CanBootedChecker.php @@ -0,0 +1,27 @@ +bootloaders->isBooted($ref->getName()) + && !$ref->isAbstract() + && !$ref->isInterface() + && $ref->implementsInterface(BootloaderInterface::class); + } +} diff --git a/src/Boot/src/BootloadManager/Checker/CheckerRegistry.php b/src/Boot/src/BootloadManager/Checker/CheckerRegistry.php new file mode 100644 index 000000000..3a9dd879f --- /dev/null +++ b/src/Boot/src/BootloadManager/Checker/CheckerRegistry.php @@ -0,0 +1,26 @@ + + */ + private array $checkers = []; + + public function register(BootloaderCheckerInterface $checker): void + { + $this->checkers[] = $checker; + } + + /** + * @return array + */ + public function getCheckers(): array + { + return $this->checkers; + } +} diff --git a/src/Boot/src/BootloadManager/Checker/CheckerRegistryInterface.php b/src/Boot/src/BootloadManager/Checker/CheckerRegistryInterface.php new file mode 100644 index 000000000..12203a79c --- /dev/null +++ b/src/Boot/src/BootloadManager/Checker/CheckerRegistryInterface.php @@ -0,0 +1,15 @@ + + */ + public function getCheckers(): array; +} diff --git a/src/Boot/src/BootloadManager/Checker/ClassExistsChecker.php b/src/Boot/src/BootloadManager/Checker/ClassExistsChecker.php new file mode 100644 index 000000000..34fc36ea6 --- /dev/null +++ b/src/Boot/src/BootloadManager/Checker/ClassExistsChecker.php @@ -0,0 +1,28 @@ +enabled) { + return false; + } + + foreach ($rules->denyEnv as $env => $denyValues) { + $value = $this->environment->get($env); + if ($value !== null && \in_array($value, (array) $denyValues, true)) { + return false; + } + } + + foreach ($rules->allowEnv as $env => $allowValues) { + $value = $this->environment->get($env); + if ($value === null || !\in_array($value, (array) $allowValues, true)) { + return false; + } + } + + return true; + } +} diff --git a/src/Boot/src/BootloadManager/DefaultInvokerStrategy.php b/src/Boot/src/BootloadManager/DefaultInvokerStrategy.php index ec95c60ff..a5a355fb7 100644 --- a/src/Boot/src/BootloadManager/DefaultInvokerStrategy.php +++ b/src/Boot/src/BootloadManager/DefaultInvokerStrategy.php @@ -17,9 +17,14 @@ public function __construct( ) { } - public function invokeBootloaders(array $classes, array $bootingCallbacks, array $bootedCallbacks): void - { - $bootloaders = \iterator_to_array($this->initializer->init($classes)); + public function invokeBootloaders( + array $classes, + array $bootingCallbacks, + array $bootedCallbacks, + bool $useRules = true + ): void { + /** @psalm-suppress TooManyArguments */ + $bootloaders = \iterator_to_array($this->initializer->init($classes, $useRules)); foreach ($bootloaders as $data) { $this->invokeBootloader($data['bootloader'], Methods::INIT, $data['options']); diff --git a/src/Boot/src/BootloadManager/Initializer.php b/src/Boot/src/BootloadManager/Initializer.php index b1d905662..462cec8cb 100644 --- a/src/Boot/src/BootloadManager/Initializer.php +++ b/src/Boot/src/BootloadManager/Initializer.php @@ -5,12 +5,19 @@ namespace Spiral\Boot\BootloadManager; use Psr\Container\ContainerInterface; +use Spiral\Boot\Attribute\BootloaderRules; use Spiral\Boot\Bootloader\BootloaderInterface; use Spiral\Boot\Bootloader\DependedInterface; +use Spiral\Boot\BootloadManager\Checker\BootloaderChecker; +use Spiral\Boot\BootloadManager\Checker\BootloaderCheckerInterface; +use Spiral\Boot\BootloadManager\Checker\CanBootedChecker; +use Spiral\Boot\BootloadManager\Checker\CheckerRegistry; +use Spiral\Boot\BootloadManager\Checker\ClassExistsChecker; +use Spiral\Boot\BootloadManager\Checker\RulesChecker; use Spiral\Boot\BootloadManagerInterface; -use Spiral\Boot\Exception\ClassNotFoundException; use Spiral\Core\BinderInterface; use Spiral\Core\Container; +use Spiral\Core\ResolverInterface; /** * @internal @@ -19,10 +26,13 @@ */ class Initializer implements InitializerInterface, Container\SingletonInterface { + protected ?BootloaderCheckerInterface $checker = null; + public function __construct( protected readonly ContainerInterface $container, protected readonly BinderInterface $binder, - protected readonly ClassesRegistry $bootloaders = new ClassesRegistry() + protected readonly ClassesRegistry $bootloaders = new ClassesRegistry(), + ?BootloaderCheckerInterface $checker = null, ) { } @@ -31,42 +41,34 @@ public function __construct( * * @param TClass[]|array> $classes */ - public function init(array $classes): \Generator + public function init(array $classes, bool $useRules = true): \Generator { + $this->checker ??= $this->initDefaultChecker(); + foreach ($classes as $bootloader => $options) { // default bootload syntax as simple array if (\is_string($options) || $options instanceof BootloaderInterface) { $bootloader = $options; $options = []; } + $options = $useRules ? $this->getBootloaderRules($bootloader, $options) : []; - // Replace class aliases with source classes - try { - $ref = (new \ReflectionClass($bootloader)); - $className = $ref->getName(); - } catch (\ReflectionException) { - throw new ClassNotFoundException( - \sprintf('Bootloader class `%s` is not exist.', $bootloader) - ); - } - - if ($this->bootloaders->isBooted($className) || $ref->isAbstract()) { + if (!$this->checker->canInitialize($bootloader, $useRules ? $options : null)) { continue; } - $this->bootloaders->register($className); + $this->bootloaders->register($bootloader instanceof BootloaderInterface ? $bootloader::class : $bootloader); if (!$bootloader instanceof BootloaderInterface) { $bootloader = $this->container->get($bootloader); } - if (!$this->isBootloader($bootloader)) { - continue; - } - /** @var BootloaderInterface $bootloader */ yield from $this->initBootloader($bootloader); - yield $className => \compact('bootloader', 'options'); + yield $bootloader::class => [ + 'bootloader' => $bootloader, + 'options' => $options instanceof BootloaderRules ? $options->args : $options, + ]; } } @@ -156,4 +158,69 @@ protected function isBootloader(string|object $class): bool { return \is_subclass_of($class, BootloaderInterface::class); } + + protected function initDefaultChecker(): BootloaderCheckerInterface + { + $registry = new CheckerRegistry(); + $registry->register($this->container->get(RulesChecker::class)); + $registry->register(new ClassExistsChecker()); + $registry->register(new CanBootedChecker($this->bootloaders)); + + return new BootloaderChecker($registry); + } + + /** + * Returns merged rules. Attribute rules have lower priority. + * + * @param class-string|BootloaderInterface $bootloader + */ + private function getBootloaderRules( + string|BootloaderInterface $bootloader, + array|callable|BootloaderRules $rules + ): BootloaderRules { + if ($rules instanceof \Closure) { + $rules = $this->container instanceof ResolverInterface + ? $rules(...$this->container->resolveArguments(new \ReflectionFunction($rules))) + : $rules(); + } + $attr = $this->getBootloaderRulesAttribute($bootloader); + + $getArgument = static function (string $key, bool $override, mixed $default = []) use ($rules, $attr): mixed { + return match (true) { + $rules instanceof BootloaderRules && $override => $rules->{$key}, + $rules instanceof BootloaderRules && !$override && \is_array($default) => + $rules->{$key} + ($attr->{$key} ?? []), + $rules instanceof BootloaderRules && !$override && \is_bool($default) => $rules->{$key}, + \is_array($rules) && $rules !== [] && $key === 'args' => $rules, + default => $attr->{$key} ?? $default, + }; + }; + + $override = $rules instanceof BootloaderRules ? $rules->override : true; + + return new BootloaderRules( + args: $getArgument('args', $override), + enabled: $getArgument('enabled', $override, true), + allowEnv: $getArgument('allowEnv', $override), + denyEnv: $getArgument('denyEnv', $override), + ); + } + + /** + * @param class-string|BootloaderInterface $bootloader + */ + private function getBootloaderRulesAttribute(string|BootloaderInterface $bootloader): ?BootloaderRules + { + $attribute = null; + if ($bootloader instanceof BootloaderInterface || \class_exists($bootloader)) { + $ref = new \ReflectionClass($bootloader); + $attribute = $ref->getAttributes(BootloaderRules::class)[0] ?? null; + } + + if ($attribute === null) { + return null; + } + + return $attribute->newInstance(); + } } diff --git a/src/Boot/src/BootloadManager/StrategyBasedBootloadManager.php b/src/Boot/src/BootloadManager/StrategyBasedBootloadManager.php index 6d36783ec..ea572f1d0 100644 --- a/src/Boot/src/BootloadManager/StrategyBasedBootloadManager.php +++ b/src/Boot/src/BootloadManager/StrategyBasedBootloadManager.php @@ -23,8 +23,13 @@ public function __construct( * * @throws \Throwable */ - protected function boot(array $classes, array $bootingCallbacks, array $bootedCallbacks): void - { - $this->invoker->invokeBootloaders($classes, $bootingCallbacks, $bootedCallbacks); + protected function boot( + array $classes, + array $bootingCallbacks, + array $bootedCallbacks, + bool $useRules = true + ): void { + /** @psalm-suppress TooManyArguments */ + $this->invoker->invokeBootloaders($classes, $bootingCallbacks, $bootedCallbacks, $useRules); } } diff --git a/src/Boot/tests/BootloadManager/AttributeBootloaderRulesTest.php b/src/Boot/tests/BootloadManager/AttributeBootloaderRulesTest.php new file mode 100644 index 000000000..617156d08 --- /dev/null +++ b/src/Boot/tests/BootloadManager/AttributeBootloaderRulesTest.php @@ -0,0 +1,150 @@ +initializer->init([BootloaderE::class, BootloaderD::class])); + + $this->assertEquals([ + BootloaderE::class => ['bootloader' => new BootloaderE(), 'options' => []], + BootloaderD::class => ['bootloader' => new BootloaderD(), 'options' => []] + ], $result); + } + + public function testDisabledBootloader(): void + { + $result = \iterator_to_array($this->initializer->init([BootloaderF::class, BootloaderD::class])); + + $this->assertEquals([ + BootloaderD::class => ['bootloader' => new BootloaderD(), 'options' => []] + ], $result); + } + + public function testArguments(): void + { + $result = \iterator_to_array($this->initializer->init([BootloaderG::class])); + + $this->assertEquals([ + BootloaderG::class => ['bootloader' => new BootloaderG(), 'options' => ['a' => 'b', 'c' => 'd']], + ], $result); + } + + public function testDisabledRules(): void + { + $result = \iterator_to_array($this->initializer->init([BootloaderF::class, BootloaderD::class], false)); + + $this->assertEquals([ + BootloaderF::class => ['bootloader' => new BootloaderF(), 'options' => []], + BootloaderD::class => ['bootloader' => new BootloaderD(), 'options' => []] + ], $result); + } + + #[DataProvider('allowEnvDataProvider')] + public function testAllowEnv(array $env, array $expected): void + { + $this->container->bindSingleton(EnvironmentInterface::class, new Environment($env), true); + + $result = \iterator_to_array($this->initializer->init([BootloaderH::class])); + + $this->assertEquals($expected, $result); + } + + #[DataProvider('denyEnvDataProvider')] + public function testDenyEnv(array $env, array $expected): void + { + $this->container->bindSingleton(EnvironmentInterface::class, new Environment($env), true); + + $result = \iterator_to_array($this->initializer->init([BootloaderI::class])); + + $this->assertEquals($expected, $result); + } + + public function testDenyEnvShouldHaveHigherPriority(): void + { + $this->container->bindSingleton(EnvironmentInterface::class, new Environment(['APP_DEBUG' => true]), true); + + $result = \iterator_to_array($this->initializer->init([BootloaderJ::class])); + + $this->assertEquals([], $result); + } + + public function testExtendedAttribute(): void + { + $this->container->bindSingleton(EnvironmentInterface::class, new Environment(['RR_MODE' => 'http']), true); + $result = \iterator_to_array($this->initializer->init([BootloaderK::class])); + $this->assertEquals([BootloaderK::class => ['bootloader' => new BootloaderK(), 'options' => []]], $result); + + $this->container->bindSingleton(EnvironmentInterface::class, new Environment(['RR_MODE' => 'jobs']), true); + $result = \iterator_to_array($this->initializer->init([BootloaderK::class])); + $this->assertEquals([], $result); + } + + public static function allowEnvDataProvider(): \Traversable + { + yield [ + ['APP_ENV' => 'prod', 'APP_DEBUG' => false, 'RR_MODE' => 'http'], + [BootloaderH::class => ['bootloader' => new BootloaderH(), 'options' => []]] + ]; + yield [ + ['APP_ENV' => 'dev', 'APP_DEBUG' => false, 'RR_MODE' => 'http'], + [] + ]; + yield [ + ['APP_ENV' => 'prod', 'APP_DEBUG' => true, 'RR_MODE' => 'http'], + [] + ]; + yield [ + ['APP_ENV' => 'prod', 'APP_DEBUG' => false, 'RR_MODE' => 'jobs'], + [] + ]; + } + + public static function denyEnvDataProvider(): \Traversable + { + yield [ + ['RR_MODE' => 'http', 'APP_ENV' => 'prod', 'DB_HOST' => 'db.example.com'], + [] + ]; + yield [ + ['RR_MODE' => 'http', 'APP_ENV' => 'production', 'DB_HOST' => 'db.example.com'], + [] + ]; + yield [ + ['RR_MODE' => 'http', 'APP_ENV' => 'production', 'DB_HOST' => 'db.example.com'], + [] + ]; + yield [ + ['RR_MODE' => 'jobs', 'APP_ENV' => 'production', 'DB_HOST' => 'db.example.com'], + [] + ]; + yield [ + ['RR_MODE' => 'http', 'APP_ENV' => 'dev', 'DB_HOST' => 'db.example.com'], + [] + ]; + yield [ + ['RR_MODE' => 'http', 'APP_ENV' => 'dev', 'DB_HOST' => 'localhost'], + [] + ]; + yield [ + ['RR_MODE' => 'jobs', 'APP_ENV' => 'dev', 'DB_HOST' => 'localhost'], + [BootloaderI::class => ['bootloader' => new BootloaderI(), 'options' => []]] + ]; + } +} diff --git a/src/Boot/tests/BootloadManager/BootloadManagerTest.php b/src/Boot/tests/BootloadManager/BootloadManagerTest.php index 4788bc3f5..5ee23d254 100644 --- a/src/Boot/tests/BootloadManager/BootloadManagerTest.php +++ b/src/Boot/tests/BootloadManager/BootloadManagerTest.php @@ -19,14 +19,13 @@ final class BootloadManagerTest extends TestCase { public function testWithoutInvokerStrategy(): void { - $container = new Container(); - $container->bind(InitializerInterface::class, new Initializer($container, $container)); + $this->container->bind(InitializerInterface::class, new Initializer($this->container, $this->container)); $bootloader = new BootloadManager( - $container, - $container, - $container, - $container->get(InitializerInterface::class) + $this->container, + $this->container, + $this->container, + $this->container->get(InitializerInterface::class) ); $bootloader->bootload($classes = [ @@ -43,15 +42,16 @@ static function(Container $container, SampleBoot $boot) { } ]); - $this->assertTrue($container->has('abc')); - $this->assertTrue($container->hasInstance('cde')); - $this->assertTrue($container->hasInstance('def')); - $this->assertTrue($container->hasInstance('efg')); - $this->assertTrue($container->has('single')); - $this->assertTrue($container->has('ghi')); - $this->assertNotInstanceOf(SampleBoot::class, $container->get('efg')); - $this->assertInstanceOf(SampleBoot::class, $container->get('ghi')); + $this->assertTrue($this->container->has('abc')); + $this->assertTrue($this->container->hasInstance('cde')); + $this->assertTrue($this->container->hasInstance('def')); + $this->assertTrue($this->container->hasInstance('efg')); + $this->assertTrue($this->container->has('single')); + $this->assertTrue($this->container->has('ghi')); + $this->assertNotInstanceOf(SampleBoot::class, $this->container->get('efg')); + $this->assertInstanceOf(SampleBoot::class, $this->container->get('ghi')); + $classes = \array_filter($classes, static fn(string $class): bool => $class !== SampleClass::class); $this->assertSame(\array_merge($classes, [ BootloaderA::class, BootloaderB::class, diff --git a/src/Boot/tests/BootloadManager/BootloaderRulesTest.php b/src/Boot/tests/BootloadManager/BootloaderRulesTest.php new file mode 100644 index 000000000..174a9a5bc --- /dev/null +++ b/src/Boot/tests/BootloadManager/BootloaderRulesTest.php @@ -0,0 +1,193 @@ +initializer->init([ + BootloaderA::class => new BootloaderRules(), + BootloaderD::class + ])); + + $this->assertEquals([ + BootloaderA::class => ['bootloader' => new BootloaderA(), 'options' => []], + BootloaderD::class => ['bootloader' => new BootloaderD(), 'options' => []] + ], $result); + } + + public function testDisabledBootloader(): void + { + $result = \iterator_to_array($this->initializer->init([ + BootloaderA::class => new BootloaderRules(enabled: false), + BootloaderD::class + ])); + + $this->assertEquals([ + BootloaderD::class => ['bootloader' => new BootloaderD(), 'options' => []] + ], $result); + } + + public function testArguments(): void + { + $result = \iterator_to_array($this->initializer->init([ + BootloaderA::class => new BootloaderRules(args: ['a' => 'b']) + ])); + + $this->assertEquals([ + BootloaderA::class => ['bootloader' => new BootloaderA(), 'options' => ['a' => 'b']], + ], $result); + } + + public function testDisabledRules(): void + { + $result = \iterator_to_array($this->initializer->init([ + BootloaderA::class => new BootloaderRules(enabled: false), + BootloaderD::class + ], false)); + + $this->assertEquals([ + BootloaderA::class => ['bootloader' => new BootloaderA(), 'options' => []], + BootloaderD::class => ['bootloader' => new BootloaderD(), 'options' => []] + ], $result); + } + + public function testCallableRules(): void + { + $result = \iterator_to_array($this->initializer->init([ + BootloaderA::class => static fn () => new BootloaderRules(args: ['a' => 'b']), + ])); + + $this->assertEquals([ + BootloaderA::class => ['bootloader' => new BootloaderA(), 'options' => ['a' => 'b']], + ], $result); + } + + public function testCallableRulesWithArguments(): void + { + $this->container->bind(AppEnvironment::class, AppEnvironment::Production); + + $result = \iterator_to_array($this->initializer->init([ + BootloaderA::class => static fn (AppEnvironment $env) => new BootloaderRules(enabled: $env->isLocal()), + ])); + $this->assertEquals([], $result); + + $result = \iterator_to_array($this->initializer->init([ + BootloaderA::class => static fn (AppEnvironment $env) => new BootloaderRules(enabled: $env->isProduction()), + ])); + $this->assertEquals([BootloaderA::class => ['bootloader' => new BootloaderA(), 'options' => []]], $result); + } + + #[DataProvider('allowEnvDataProvider')] + public function testAllowEnv(array $env, array $expected): void + { + $this->container->bindSingleton(EnvironmentInterface::class, new Environment($env), true); + + $result = \iterator_to_array($this->initializer->init([ + BootloaderA::class => new BootloaderRules(allowEnv: [ + 'APP_ENV' => 'prod', + 'APP_DEBUG' => false, + 'RR_MODE' => ['http'] + ]), + ])); + + $this->assertEquals($expected, $result); + } + + #[DataProvider('denyEnvDataProvider')] + public function testDenyEnv(array $env, array $expected): void + { + $this->container->bindSingleton(EnvironmentInterface::class, new Environment($env), true); + + $result = \iterator_to_array($this->initializer->init([ + BootloaderA::class => new BootloaderRules(denyEnv: [ + 'RR_MODE' => 'http', + 'APP_ENV' => ['production', 'prod'], + 'DB_HOST' => 'db.example.com', + ]), + ])); + + $this->assertEquals($expected, $result); + } + + public function testDenyEnvShouldHaveHigherPriority(): void + { + $this->container->bindSingleton(EnvironmentInterface::class, new Environment(['APP_DEBUG' => true]), true); + + $result = \iterator_to_array($this->initializer->init([ + BootloaderA::class => new BootloaderRules( + allowEnv: [ + 'APP_DEBUG' => true, + ], + denyEnv: [ + 'APP_DEBUG' => true, + ] + ), + ])); + + $this->assertEquals([], $result); + } + + public static function allowEnvDataProvider(): \Traversable + { + yield [ + ['APP_ENV' => 'prod', 'APP_DEBUG' => false, 'RR_MODE' => 'http'], + [BootloaderA::class => ['bootloader' => new BootloaderA(), 'options' => []]] + ]; + yield [ + ['APP_ENV' => 'dev', 'APP_DEBUG' => false, 'RR_MODE' => 'http'], + [] + ]; + yield [ + ['APP_ENV' => 'prod', 'APP_DEBUG' => true, 'RR_MODE' => 'http'], + [] + ]; + yield [ + ['APP_ENV' => 'prod', 'APP_DEBUG' => false, 'RR_MODE' => 'jobs'], + [] + ]; + } + + public static function denyEnvDataProvider(): \Traversable + { + yield [ + ['RR_MODE' => 'http', 'APP_ENV' => 'prod', 'DB_HOST' => 'db.example.com'], + [] + ]; + yield [ + ['RR_MODE' => 'http', 'APP_ENV' => 'production', 'DB_HOST' => 'db.example.com'], + [] + ]; + yield [ + ['RR_MODE' => 'http', 'APP_ENV' => 'production', 'DB_HOST' => 'db.example.com'], + [] + ]; + yield [ + ['RR_MODE' => 'jobs', 'APP_ENV' => 'production', 'DB_HOST' => 'db.example.com'], + [] + ]; + yield [ + ['RR_MODE' => 'http', 'APP_ENV' => 'dev', 'DB_HOST' => 'db.example.com'], + [] + ]; + yield [ + ['RR_MODE' => 'http', 'APP_ENV' => 'dev', 'DB_HOST' => 'localhost'], + [] + ]; + yield [ + ['RR_MODE' => 'jobs', 'APP_ENV' => 'dev', 'DB_HOST' => 'localhost'], + [BootloaderA::class => ['bootloader' => new BootloaderA(), 'options' => []]] + ]; + } +} diff --git a/src/Boot/tests/BootloadManager/BootloadersTest.php b/src/Boot/tests/BootloadManager/BootloadersTest.php index f0d9e4ba9..ecf472590 100644 --- a/src/Boot/tests/BootloadManager/BootloadersTest.php +++ b/src/Boot/tests/BootloadManager/BootloadersTest.php @@ -15,13 +15,11 @@ use Spiral\Tests\Boot\Fixtures\SampleClass; use Spiral\Tests\Boot\TestCase; -class BootloadersTest extends TestCase +final class BootloadersTest extends TestCase { public function testSchemaLoading(): void { - $container = new Container(); - - $bootloader = $this->getBootloadManager($container); + $bootloader = $this->getBootloadManager(); $bootloader->bootload($classes = [ SampleClass::class, @@ -37,15 +35,16 @@ static function(Container $container, SampleBoot $boot) { } ]); - $this->assertTrue($container->has('abc')); - $this->assertTrue($container->hasInstance('cde')); - $this->assertTrue($container->hasInstance('def')); - $this->assertTrue($container->hasInstance('efg')); - $this->assertTrue($container->has('single')); - $this->assertTrue($container->has('ghi')); - $this->assertNotInstanceOf(SampleBoot::class, $container->get('efg')); - $this->assertInstanceOf(SampleBoot::class, $container->get('ghi')); + $this->assertTrue($this->container->has('abc')); + $this->assertTrue($this->container->hasInstance('cde')); + $this->assertTrue($this->container->hasInstance('def')); + $this->assertTrue($this->container->hasInstance('efg')); + $this->assertTrue($this->container->has('single')); + $this->assertTrue($this->container->has('ghi')); + $this->assertNotInstanceOf(SampleBoot::class, $this->container->get('efg')); + $this->assertInstanceOf(SampleBoot::class, $this->container->get('ghi')); + $classes = \array_filter($classes, static fn(string $class): bool => $class !== SampleClass::class); $this->assertSame(\array_merge($classes, [ BootloaderA::class, BootloaderB::class, @@ -54,9 +53,7 @@ static function(Container $container, SampleBoot $boot) { public function testBootloadFromInstance(): void { - $container = new Container(); - - $bootloader = $this->getBootloadManager($container); + $bootloader = $this->getBootloadManager(); $bootloader->bootload([ SampleClass::class, @@ -64,15 +61,14 @@ public function testBootloadFromInstance(): void new SampleBoot(), ]); - $this->assertTrue($container->has('abc')); - $this->assertTrue($container->has('single')); - $this->assertTrue($container->hasInstance('def')); - $this->assertTrue($container->hasInstance('efg')); - $this->assertTrue($container->hasInstance('cde')); - $this->assertTrue($container->has('ghi')); + $this->assertTrue($this->container->has('abc')); + $this->assertTrue($this->container->has('single')); + $this->assertTrue($this->container->hasInstance('def')); + $this->assertTrue($this->container->hasInstance('efg')); + $this->assertTrue($this->container->hasInstance('cde')); + $this->assertTrue($this->container->has('ghi')); $this->assertSame([ - SampleClass::class, SampleBootWithMethodBoot::class, SampleBoot::class, BootloaderA::class, @@ -82,9 +78,7 @@ public function testBootloadFromInstance(): void public function testBootloadFromAnonymousClass(): void { - $container = new Container(); - - $bootloader = $this->getBootloadManager($container); + $bootloader = $this->getBootloadManager(); $bootloader->bootload([ new class () extends Bootloader { @@ -104,11 +98,11 @@ public function boot(BinderInterface $binder): void }, ]); - $this->assertTrue($container->has('abc')); - $this->assertTrue($container->has('single')); - $this->assertTrue($container->hasInstance('def')); - $this->assertTrue($container->hasInstance('efg')); - $this->assertTrue($container->has('ghi')); + $this->assertTrue($this->container->has('abc')); + $this->assertTrue($this->container->has('single')); + $this->assertTrue($this->container->hasInstance('def')); + $this->assertTrue($this->container->hasInstance('efg')); + $this->assertTrue($this->container->has('ghi')); $this->assertCount(1, $bootloader->getClasses()); } diff --git a/src/Boot/tests/BootloadManager/Checker/BootloaderCheckerTest.php b/src/Boot/tests/BootloadManager/Checker/BootloaderCheckerTest.php new file mode 100644 index 000000000..301b1d59f --- /dev/null +++ b/src/Boot/tests/BootloadManager/Checker/BootloaderCheckerTest.php @@ -0,0 +1,45 @@ +createMock(BootloaderCheckerInterface::class); + $checker1->method('canInitialize')->willReturn(true); + $checker2 = $this->createMock(BootloaderCheckerInterface::class); + $checker2->method('canInitialize')->willReturn(false); + + $registry = new CheckerRegistry(); + $registry->register($checker1); + $registry->register($checker2); + + $checker = new BootloaderChecker($registry); + + $this->assertFalse($checker->canInitialize('foo')); + } + + public function testCanInitializeSuccess(): void + { + $checker1 = $this->createMock(BootloaderCheckerInterface::class); + $checker1->method('canInitialize')->willReturn(true); + $checker2 = $this->createMock(BootloaderCheckerInterface::class); + $checker2->method('canInitialize')->willReturn(true); + + $registry = new CheckerRegistry(); + $registry->register($checker1); + $registry->register($checker2); + + $checker = new BootloaderChecker($registry); + + $this->assertTrue($checker->canInitialize('foo')); + } +} diff --git a/src/Boot/tests/BootloadManager/Checker/CanBootedCheckerTest.php b/src/Boot/tests/BootloadManager/Checker/CanBootedCheckerTest.php new file mode 100644 index 000000000..e4e7307d7 --- /dev/null +++ b/src/Boot/tests/BootloadManager/Checker/CanBootedCheckerTest.php @@ -0,0 +1,48 @@ +assertTrue($checker->canInitialize(BootloaderA::class)); + $this->assertTrue($checker->canInitialize(new BootloaderA())); + } + + public function testCanInitializeBootloaderAlreadyBooted(): void + { + $registry = new ClassesRegistry(); + $registry->register(BootloaderA::class); + + $checker = new CanBootedChecker($registry); + + $this->assertFalse($checker->canInitialize(BootloaderA::class)); + $this->assertFalse($checker->canInitialize(new BootloaderA())); + } + + public function testCanInitializeAbstractBootloader(): void + { + $checker = new CanBootedChecker(new ClassesRegistry()); + + $this->assertFalse($checker->canInitialize(AbstractBootloader::class)); + } + + public function testCanInitializeNotImplementInterface(): void + { + $checker = new CanBootedChecker(new ClassesRegistry()); + + $this->assertFalse($checker->canInitialize(SampleClass::class)); + } +} diff --git a/src/Boot/tests/BootloadManager/Checker/ClassExistsCheckerTest.php b/src/Boot/tests/BootloadManager/Checker/ClassExistsCheckerTest.php new file mode 100644 index 000000000..fdbcaed87 --- /dev/null +++ b/src/Boot/tests/BootloadManager/Checker/ClassExistsCheckerTest.php @@ -0,0 +1,29 @@ +assertTrue($checker->canInitialize(BootloaderA::class)); + $this->assertTrue($checker->canInitialize(new BootloaderA())); + } + + public function testCanInitializeException(): void + { + $checker = new ClassExistsChecker(); + + $this->expectException(ClassNotFoundException::class); + $checker->canInitialize('foo'); + } +} diff --git a/src/Boot/tests/BootloadManager/Checker/RulesCheckerTest.php b/src/Boot/tests/BootloadManager/Checker/RulesCheckerTest.php new file mode 100644 index 000000000..6ceaa5d30 --- /dev/null +++ b/src/Boot/tests/BootloadManager/Checker/RulesCheckerTest.php @@ -0,0 +1,56 @@ + 'dev' + ])); + + $this->assertSame($expected, $checker->canInitialize(BootloaderA::class, $rules)); + } + + public function testCanInitializeException(): void + { + $checker = new ClassExistsChecker(); + + $this->expectException(ClassNotFoundException::class); + $checker->canInitialize('foo'); + } + + public static function canInitializeDataProvider(): \Traversable + { + yield [true, null]; + yield [true, new BootloaderRules()]; + yield [false, new BootloaderRules(enabled: false)]; + + yield [true, new BootloaderRules(allowEnv: ['APP_ENV' => 'dev'])]; + yield [true, new BootloaderRules(allowEnv: ['APP_ENV' => ['dev']])]; + yield [false, new BootloaderRules(allowEnv: ['APP_ENV' => 'dev', 'DEBUG' => true])]; + yield [false, new BootloaderRules(allowEnv: ['APP_ENV' => 'prod'])]; + yield [false, new BootloaderRules(allowEnv: ['APP_ENV' => ['prod']])]; + yield [false, new BootloaderRules(allowEnv: ['APP_ENV' => ['prod'], 'DEBUG' => true])]; + + yield [false, new BootloaderRules(denyEnv: ['APP_ENV' => 'dev'])]; + yield [false, new BootloaderRules(denyEnv: ['APP_ENV' => ['dev']])]; + yield [false, new BootloaderRules(denyEnv: ['APP_ENV' => 'dev', 'DEBUG' => true])]; + yield [true, new BootloaderRules(denyEnv: ['APP_ENV' => 'prod'])]; + yield [true, new BootloaderRules(denyEnv: ['APP_ENV' => ['prod']])]; + yield [true, new BootloaderRules(denyEnv: ['APP_ENV' => ['prod'], 'DEBUG' => true])]; + } +} diff --git a/src/Boot/tests/BootloadManager/DependenciesTest.php b/src/Boot/tests/BootloadManager/DependenciesTest.php index 80fa15a00..61d6fa095 100644 --- a/src/Boot/tests/BootloadManager/DependenciesTest.php +++ b/src/Boot/tests/BootloadManager/DependenciesTest.php @@ -5,31 +5,28 @@ namespace Spiral\Tests\Boot\BootloadManager; use Spiral\Tests\Boot\TestCase; -use Spiral\Core\Container; use Spiral\Tests\Boot\Fixtures\BootloaderA; use Spiral\Tests\Boot\Fixtures\BootloaderB; -class DependenciesTest extends TestCase +final class DependenciesTest extends TestCase { public function testDep(): void { - $c = new Container(); - $b = $this->getBootloadManager($c); + $b = $this->getBootloadManager(); $b->bootload([BootloaderA::class]); - $this->assertTrue($c->has('a')); - $this->assertFalse($c->has('b')); + $this->assertTrue($this->container->has('a')); + $this->assertFalse($this->container->has('b')); } public function testDep2(): void { - $c = new Container(); - $b = $this->getBootloadManager($c); + $b = $this->getBootloadManager(); $b->bootload([BootloaderB::class]); - $this->assertTrue($c->has('a')); - $this->assertTrue($c->has('b')); + $this->assertTrue($this->container->has('a')); + $this->assertTrue($this->container->has('b')); } } diff --git a/src/Boot/tests/BootloadManager/InitializerTest.php b/src/Boot/tests/BootloadManager/InitializerTest.php index 2a9062c25..ebf99dc31 100644 --- a/src/Boot/tests/BootloadManager/InitializerTest.php +++ b/src/Boot/tests/BootloadManager/InitializerTest.php @@ -4,21 +4,14 @@ namespace Spiral\Tests\Boot\BootloadManager; -use PHPUnit\Framework\TestCase; -use Spiral\Boot\BootloadManager\Initializer; -use Spiral\Core\Container; use Spiral\Tests\Boot\Fixtures\AbstractBootloader; use Spiral\Tests\Boot\Fixtures\BootloaderD; -final class InitializerTest extends TestCase +final class InitializerTest extends InitializerTestCase { public function testDontBootloadAbstractBootloader(): void { - $container = new Container(); - - $initializer = new Initializer($container, $container); - - $result = \iterator_to_array($initializer->init([AbstractBootloader::class, BootloaderD::class])); + $result = \iterator_to_array($this->initializer->init([AbstractBootloader::class, BootloaderD::class])); $this->assertCount(1, $result); $this->assertIsArray($result[BootloaderD::class]); diff --git a/src/Boot/tests/BootloadManager/InitializerTestCase.php b/src/Boot/tests/BootloadManager/InitializerTestCase.php new file mode 100644 index 000000000..817d9347f --- /dev/null +++ b/src/Boot/tests/BootloadManager/InitializerTestCase.php @@ -0,0 +1,20 @@ +initializer = new Initializer($this->container, $this->container); + } +} diff --git a/src/Boot/tests/BootloadManager/MergeBootloaderRulesTest.php b/src/Boot/tests/BootloadManager/MergeBootloaderRulesTest.php new file mode 100644 index 000000000..27a8f2281 --- /dev/null +++ b/src/Boot/tests/BootloadManager/MergeBootloaderRulesTest.php @@ -0,0 +1,112 @@ +initializer->init([ + BootloaderF::class => new BootloaderRules(enabled: true), + BootloaderD::class + ])); + + $this->assertEquals([ + BootloaderF::class => ['bootloader' => new BootloaderF(), 'options' => []], + BootloaderD::class => ['bootloader' => new BootloaderD(), 'options' => []] + ], $result); + } + + public function testOverrideArgs(): void + { + $result = \iterator_to_array($this->initializer->init([ + BootloaderG::class => new BootloaderRules(args: ['foo' => 'bar']), + ])); + + $this->assertEquals([ + BootloaderG::class => ['bootloader' => new BootloaderG(), 'options' => ['foo' => 'bar']] + ], $result); + } + + public function testMergeArgs(): void + { + $result = \iterator_to_array($this->initializer->init([ + BootloaderG::class => new BootloaderRules(args: ['foo' => 'bar', 'a' => 'baz'], override: false), + ])); + + $this->assertEquals([ + BootloaderG::class => ['bootloader' => new BootloaderG(), 'options' => [ + 'a' => 'baz', + 'foo' => 'bar', + 'c' => 'd' + ]] + ], $result); + } + + public function testOverrideAllowEnv(): void + { + $ref = new \ReflectionMethod($this->initializer, 'getBootloaderRules'); + $rules = $ref->invoke( + $this->initializer, + BootloaderH::class, + new BootloaderRules(allowEnv: ['foo' => 'bar']) + ); + + $this->assertEquals(['foo' => 'bar'], $rules->allowEnv); + } + + public function testMergeAllowEnv(): void + { + $ref = new \ReflectionMethod($this->initializer, 'getBootloaderRules'); + $rules = $ref->invoke( + $this->initializer, + BootloaderH::class, + new BootloaderRules(allowEnv: ['APP_ENV' => 'dev', 'foo' => 'bar'], override: false) + ); + + $this->assertEquals([ + 'foo' => 'bar', + 'APP_ENV' => 'dev', + 'APP_DEBUG' => false, + 'RR_MODE' => ['http'] + ], $rules->allowEnv); + } + + public function testOverrideDenyEnv(): void + { + $ref = new \ReflectionMethod($this->initializer, 'getBootloaderRules'); + $rules = $ref->invoke( + $this->initializer, + BootloaderI::class, + new BootloaderRules(denyEnv: ['foo' => 'bar']) + ); + + $this->assertEquals(['foo' => 'bar'], $rules->denyEnv); + } + + public function testMergeDenyEnv(): void + { + $ref = new \ReflectionMethod($this->initializer, 'getBootloaderRules'); + $rules = $ref->invoke( + $this->initializer, + BootloaderI::class, + new BootloaderRules(denyEnv: ['DB_HOST' => 'localhost', 'foo' => 'bar'], override: false) + ); + + $this->assertEquals([ + 'foo' => 'bar', + 'RR_MODE' => 'http', + 'APP_ENV' => ['production', 'prod'], + 'DB_HOST' => 'localhost', + ], $rules->denyEnv); + } +} diff --git a/src/Boot/tests/Fixtures/Attribute/TargetWorker.php b/src/Boot/tests/Fixtures/Attribute/TargetWorker.php new file mode 100644 index 000000000..031ae6430 --- /dev/null +++ b/src/Boot/tests/Fixtures/Attribute/TargetWorker.php @@ -0,0 +1,17 @@ + $workers]); + } +} diff --git a/src/Boot/tests/Fixtures/BootloaderE.php b/src/Boot/tests/Fixtures/BootloaderE.php new file mode 100644 index 000000000..0a544d7c3 --- /dev/null +++ b/src/Boot/tests/Fixtures/BootloaderE.php @@ -0,0 +1,12 @@ + 'b', 'c' => 'd'])] +class BootloaderG extends AbstractBootloader +{ +} diff --git a/src/Boot/tests/Fixtures/BootloaderH.php b/src/Boot/tests/Fixtures/BootloaderH.php new file mode 100644 index 000000000..4d7a53352 --- /dev/null +++ b/src/Boot/tests/Fixtures/BootloaderH.php @@ -0,0 +1,16 @@ + 'prod', + 'APP_DEBUG' => false, + 'RR_MODE' => ['http'] +])] +class BootloaderH extends AbstractBootloader +{ +} diff --git a/src/Boot/tests/Fixtures/BootloaderI.php b/src/Boot/tests/Fixtures/BootloaderI.php new file mode 100644 index 000000000..eb6affa1f --- /dev/null +++ b/src/Boot/tests/Fixtures/BootloaderI.php @@ -0,0 +1,16 @@ + 'http', + 'APP_ENV' => ['production', 'prod'], + 'DB_HOST' => 'db.example.com', +])] +class BootloaderI extends AbstractBootloader +{ +} diff --git a/src/Boot/tests/Fixtures/BootloaderJ.php b/src/Boot/tests/Fixtures/BootloaderJ.php new file mode 100644 index 000000000..7b4ba3569 --- /dev/null +++ b/src/Boot/tests/Fixtures/BootloaderJ.php @@ -0,0 +1,12 @@ + true], denyEnv: ['APP_DEBUG' => true])] +class BootloaderJ extends AbstractBootloader +{ +} diff --git a/src/Boot/tests/Fixtures/BootloaderK.php b/src/Boot/tests/Fixtures/BootloaderK.php new file mode 100644 index 000000000..ecc7d5c2e --- /dev/null +++ b/src/Boot/tests/Fixtures/BootloaderK.php @@ -0,0 +1,12 @@ +container = new Container(); + $this->container->bindSingleton(EnvironmentInterface::class, Environment::class, true); + } + + public function getBootloadManager(): StrategyBasedBootloadManager { - $initializer = new Initializer($container, $container); + $initializer = new Initializer($this->container, $this->container); return new StrategyBasedBootloadManager( - new DefaultInvokerStrategy($initializer, $container, $container), - $container, + new DefaultInvokerStrategy($initializer, $this->container, $this->container), + $this->container, $initializer ); } From 2d2886f6136dc3a3bf51cd64254e9f8f6c39d678 Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Thu, 23 Nov 2023 16:33:58 +0200 Subject: [PATCH 2/2] Rename BootloaderRules to BootloadConfig --- ...BootloaderRules.php => BootloadConfig.php} | 2 +- .../AbstractBootloadManager.php | 6 +- .../Checker/BootloaderChecker.php | 6 +- .../Checker/BootloaderCheckerInterface.php | 4 +- .../Checker/CanBootedChecker.php | 4 +- .../Checker/ClassExistsChecker.php | 4 +- .../{RulesChecker.php => ConfigChecker.php} | 14 ++--- .../DefaultInvokerStrategy.php | 4 +- src/Boot/src/BootloadManager/Initializer.php | 52 ++++++++--------- .../StrategyBasedBootloadManager.php | 4 +- ...st.php => AttributeBootloadConfigTest.php} | 6 +- ...erRulesTest.php => BootloadConfigTest.php} | 39 ++++++------- .../Checker/ConfigCheckerTest.php | 46 +++++++++++++++ .../Checker/RulesCheckerTest.php | 56 ------------------- ...esTest.php => MergeBootloadConfigTest.php} | 42 +++++++------- .../tests/Fixtures/Attribute/TargetWorker.php | 4 +- src/Boot/tests/Fixtures/BootloaderE.php | 4 +- src/Boot/tests/Fixtures/BootloaderF.php | 4 +- src/Boot/tests/Fixtures/BootloaderG.php | 4 +- src/Boot/tests/Fixtures/BootloaderH.php | 4 +- src/Boot/tests/Fixtures/BootloaderI.php | 4 +- src/Boot/tests/Fixtures/BootloaderJ.php | 4 +- 22 files changed, 150 insertions(+), 167 deletions(-) rename src/Boot/src/Attribute/{BootloaderRules.php => BootloadConfig.php} (94%) rename src/Boot/src/BootloadManager/Checker/{RulesChecker.php => ConfigChecker.php} (70%) rename src/Boot/tests/BootloadManager/{AttributeBootloaderRulesTest.php => AttributeBootloadConfigTest.php} (96%) rename src/Boot/tests/BootloadManager/{BootloaderRulesTest.php => BootloadConfigTest.php} (82%) create mode 100644 src/Boot/tests/BootloadManager/Checker/ConfigCheckerTest.php delete mode 100644 src/Boot/tests/BootloadManager/Checker/RulesCheckerTest.php rename src/Boot/tests/BootloadManager/{MergeBootloaderRulesTest.php => MergeBootloadConfigTest.php} (70%) diff --git a/src/Boot/src/Attribute/BootloaderRules.php b/src/Boot/src/Attribute/BootloadConfig.php similarity index 94% rename from src/Boot/src/Attribute/BootloaderRules.php rename to src/Boot/src/Attribute/BootloadConfig.php index c7d23d0e9..2ab9ae3b7 100644 --- a/src/Boot/src/Attribute/BootloaderRules.php +++ b/src/Boot/src/Attribute/BootloadConfig.php @@ -7,7 +7,7 @@ use Spiral\Attributes\NamedArgumentConstructor; #[\Attribute(\Attribute::TARGET_CLASS), NamedArgumentConstructor] -class BootloaderRules +class BootloadConfig { public function __construct( public array $args = [], diff --git a/src/Boot/src/BootloadManager/AbstractBootloadManager.php b/src/Boot/src/BootloadManager/AbstractBootloadManager.php index cb4200a78..d419f967d 100644 --- a/src/Boot/src/BootloadManager/AbstractBootloadManager.php +++ b/src/Boot/src/BootloadManager/AbstractBootloadManager.php @@ -28,13 +28,13 @@ public function bootload( array $classes, array $bootingCallbacks = [], array $bootedCallbacks = [], - bool $useRules = true + bool $useConfig = true ): void { $this->scope->runScope( [self::class => $this], - function () use ($classes, $bootingCallbacks, $bootedCallbacks, $useRules): void { + function () use ($classes, $bootingCallbacks, $bootedCallbacks, $useConfig): void { /** @psalm-suppress TooManyArguments */ - $this->boot($classes, $bootingCallbacks, $bootedCallbacks, $useRules); + $this->boot($classes, $bootingCallbacks, $bootedCallbacks, $useConfig); } ); } diff --git a/src/Boot/src/BootloadManager/Checker/BootloaderChecker.php b/src/Boot/src/BootloadManager/Checker/BootloaderChecker.php index d2ce96e38..234eefca0 100644 --- a/src/Boot/src/BootloadManager/Checker/BootloaderChecker.php +++ b/src/Boot/src/BootloadManager/Checker/BootloaderChecker.php @@ -4,7 +4,7 @@ namespace Spiral\Boot\BootloadManager\Checker; -use Spiral\Boot\Attribute\BootloaderRules; +use Spiral\Boot\Attribute\BootloadConfig; use Spiral\Boot\Bootloader\BootloaderInterface; final class BootloaderChecker implements BootloaderCheckerInterface @@ -14,10 +14,10 @@ public function __construct( ) { } - public function canInitialize(BootloaderInterface|string $bootloader, ?BootloaderRules $rules = null): bool + public function canInitialize(BootloaderInterface|string $bootloader, ?BootloadConfig $config = null): bool { foreach ($this->registry->getCheckers() as $checker) { - if (!$checker->canInitialize($bootloader, $rules)) { + if (!$checker->canInitialize($bootloader, $config)) { return false; } } diff --git a/src/Boot/src/BootloadManager/Checker/BootloaderCheckerInterface.php b/src/Boot/src/BootloadManager/Checker/BootloaderCheckerInterface.php index fabde876b..f69da67cf 100644 --- a/src/Boot/src/BootloadManager/Checker/BootloaderCheckerInterface.php +++ b/src/Boot/src/BootloadManager/Checker/BootloaderCheckerInterface.php @@ -4,7 +4,7 @@ namespace Spiral\Boot\BootloadManager\Checker; -use Spiral\Boot\Attribute\BootloaderRules; +use Spiral\Boot\Attribute\BootloadConfig; use Spiral\Boot\Bootloader\BootloaderInterface; interface BootloaderCheckerInterface @@ -12,5 +12,5 @@ interface BootloaderCheckerInterface /** * @param class-string|BootloaderInterface $bootloader */ - public function canInitialize(string|BootloaderInterface $bootloader, ?BootloaderRules $rules = null): bool; + public function canInitialize(string|BootloaderInterface $bootloader, ?BootloadConfig $config = null): bool; } diff --git a/src/Boot/src/BootloadManager/Checker/CanBootedChecker.php b/src/Boot/src/BootloadManager/Checker/CanBootedChecker.php index 91441f7d2..1e4f3358c 100644 --- a/src/Boot/src/BootloadManager/Checker/CanBootedChecker.php +++ b/src/Boot/src/BootloadManager/Checker/CanBootedChecker.php @@ -4,7 +4,7 @@ namespace Spiral\Boot\BootloadManager\Checker; -use Spiral\Boot\Attribute\BootloaderRules; +use Spiral\Boot\Attribute\BootloadConfig; use Spiral\Boot\Bootloader\BootloaderInterface; use Spiral\Boot\BootloadManager\ClassesRegistry; @@ -15,7 +15,7 @@ public function __construct( ) { } - public function canInitialize(BootloaderInterface|string $bootloader, ?BootloaderRules $rules = null): bool + public function canInitialize(BootloaderInterface|string $bootloader, ?BootloadConfig $config = null): bool { $ref = new \ReflectionClass($bootloader); diff --git a/src/Boot/src/BootloadManager/Checker/ClassExistsChecker.php b/src/Boot/src/BootloadManager/Checker/ClassExistsChecker.php index 34fc36ea6..0d0f0b894 100644 --- a/src/Boot/src/BootloadManager/Checker/ClassExistsChecker.php +++ b/src/Boot/src/BootloadManager/Checker/ClassExistsChecker.php @@ -4,7 +4,7 @@ namespace Spiral\Boot\BootloadManager\Checker; -use Spiral\Boot\Attribute\BootloaderRules; +use Spiral\Boot\Attribute\BootloadConfig; use Spiral\Boot\Bootloader\BootloaderInterface; use Spiral\Boot\Exception\ClassNotFoundException; @@ -13,7 +13,7 @@ final class ClassExistsChecker implements BootloaderCheckerInterface /** * @throws ClassNotFoundException */ - public function canInitialize(BootloaderInterface|string $bootloader, ?BootloaderRules $rules = null): bool + public function canInitialize(BootloaderInterface|string $bootloader, ?BootloadConfig $config = null): bool { if (!\is_string($bootloader)) { return true; diff --git a/src/Boot/src/BootloadManager/Checker/RulesChecker.php b/src/Boot/src/BootloadManager/Checker/ConfigChecker.php similarity index 70% rename from src/Boot/src/BootloadManager/Checker/RulesChecker.php rename to src/Boot/src/BootloadManager/Checker/ConfigChecker.php index a909e07c8..891119313 100644 --- a/src/Boot/src/BootloadManager/Checker/RulesChecker.php +++ b/src/Boot/src/BootloadManager/Checker/ConfigChecker.php @@ -4,35 +4,35 @@ namespace Spiral\Boot\BootloadManager\Checker; -use Spiral\Boot\Attribute\BootloaderRules; +use Spiral\Boot\Attribute\BootloadConfig; use Spiral\Boot\Bootloader\BootloaderInterface; use Spiral\Boot\EnvironmentInterface; -final class RulesChecker implements BootloaderCheckerInterface +final class ConfigChecker implements BootloaderCheckerInterface { public function __construct( private readonly EnvironmentInterface $environment, ) { } - public function canInitialize(BootloaderInterface|string $bootloader, ?BootloaderRules $rules = null): bool + public function canInitialize(BootloaderInterface|string $bootloader, ?BootloadConfig $config = null): bool { - if ($rules === null) { + if ($config === null) { return true; } - if (!$rules->enabled) { + if (!$config->enabled) { return false; } - foreach ($rules->denyEnv as $env => $denyValues) { + foreach ($config->denyEnv as $env => $denyValues) { $value = $this->environment->get($env); if ($value !== null && \in_array($value, (array) $denyValues, true)) { return false; } } - foreach ($rules->allowEnv as $env => $allowValues) { + foreach ($config->allowEnv as $env => $allowValues) { $value = $this->environment->get($env); if ($value === null || !\in_array($value, (array) $allowValues, true)) { return false; diff --git a/src/Boot/src/BootloadManager/DefaultInvokerStrategy.php b/src/Boot/src/BootloadManager/DefaultInvokerStrategy.php index a5a355fb7..2dc939b97 100644 --- a/src/Boot/src/BootloadManager/DefaultInvokerStrategy.php +++ b/src/Boot/src/BootloadManager/DefaultInvokerStrategy.php @@ -21,10 +21,10 @@ public function invokeBootloaders( array $classes, array $bootingCallbacks, array $bootedCallbacks, - bool $useRules = true + bool $useConfig = true ): void { /** @psalm-suppress TooManyArguments */ - $bootloaders = \iterator_to_array($this->initializer->init($classes, $useRules)); + $bootloaders = \iterator_to_array($this->initializer->init($classes, $useConfig)); foreach ($bootloaders as $data) { $this->invokeBootloader($data['bootloader'], Methods::INIT, $data['options']); diff --git a/src/Boot/src/BootloadManager/Initializer.php b/src/Boot/src/BootloadManager/Initializer.php index 462cec8cb..6bdd9dc84 100644 --- a/src/Boot/src/BootloadManager/Initializer.php +++ b/src/Boot/src/BootloadManager/Initializer.php @@ -5,7 +5,7 @@ namespace Spiral\Boot\BootloadManager; use Psr\Container\ContainerInterface; -use Spiral\Boot\Attribute\BootloaderRules; +use Spiral\Boot\Attribute\BootloadConfig; use Spiral\Boot\Bootloader\BootloaderInterface; use Spiral\Boot\Bootloader\DependedInterface; use Spiral\Boot\BootloadManager\Checker\BootloaderChecker; @@ -13,7 +13,7 @@ use Spiral\Boot\BootloadManager\Checker\CanBootedChecker; use Spiral\Boot\BootloadManager\Checker\CheckerRegistry; use Spiral\Boot\BootloadManager\Checker\ClassExistsChecker; -use Spiral\Boot\BootloadManager\Checker\RulesChecker; +use Spiral\Boot\BootloadManager\Checker\ConfigChecker; use Spiral\Boot\BootloadManagerInterface; use Spiral\Core\BinderInterface; use Spiral\Core\Container; @@ -41,7 +41,7 @@ public function __construct( * * @param TClass[]|array> $classes */ - public function init(array $classes, bool $useRules = true): \Generator + public function init(array $classes, bool $useConfig = true): \Generator { $this->checker ??= $this->initDefaultChecker(); @@ -51,9 +51,9 @@ public function init(array $classes, bool $useRules = true): \Generator $bootloader = $options; $options = []; } - $options = $useRules ? $this->getBootloaderRules($bootloader, $options) : []; + $options = $useConfig ? $this->getBootloadConfig($bootloader, $options) : []; - if (!$this->checker->canInitialize($bootloader, $useRules ? $options : null)) { + if (!$this->checker->canInitialize($bootloader, $useConfig ? $options : null)) { continue; } @@ -67,7 +67,7 @@ public function init(array $classes, bool $useRules = true): \Generator yield from $this->initBootloader($bootloader); yield $bootloader::class => [ 'bootloader' => $bootloader, - 'options' => $options instanceof BootloaderRules ? $options->args : $options, + 'options' => $options instanceof BootloadConfig ? $options->args : $options, ]; } } @@ -162,7 +162,7 @@ protected function isBootloader(string|object $class): bool protected function initDefaultChecker(): BootloaderCheckerInterface { $registry = new CheckerRegistry(); - $registry->register($this->container->get(RulesChecker::class)); + $registry->register($this->container->get(ConfigChecker::class)); $registry->register(new ClassExistsChecker()); $registry->register(new CanBootedChecker($this->bootloaders)); @@ -170,35 +170,35 @@ protected function initDefaultChecker(): BootloaderCheckerInterface } /** - * Returns merged rules. Attribute rules have lower priority. + * Returns merged config. Attribute config have lower priority. * * @param class-string|BootloaderInterface $bootloader */ - private function getBootloaderRules( + private function getBootloadConfig( string|BootloaderInterface $bootloader, - array|callable|BootloaderRules $rules - ): BootloaderRules { - if ($rules instanceof \Closure) { - $rules = $this->container instanceof ResolverInterface - ? $rules(...$this->container->resolveArguments(new \ReflectionFunction($rules))) - : $rules(); + array|callable|BootloadConfig $config + ): BootloadConfig { + if ($config instanceof \Closure) { + $config = $this->container instanceof ResolverInterface + ? $config(...$this->container->resolveArguments(new \ReflectionFunction($config))) + : $config(); } - $attr = $this->getBootloaderRulesAttribute($bootloader); + $attr = $this->getBootloadConfigAttribute($bootloader); - $getArgument = static function (string $key, bool $override, mixed $default = []) use ($rules, $attr): mixed { + $getArgument = static function (string $key, bool $override, mixed $default = []) use ($config, $attr): mixed { return match (true) { - $rules instanceof BootloaderRules && $override => $rules->{$key}, - $rules instanceof BootloaderRules && !$override && \is_array($default) => - $rules->{$key} + ($attr->{$key} ?? []), - $rules instanceof BootloaderRules && !$override && \is_bool($default) => $rules->{$key}, - \is_array($rules) && $rules !== [] && $key === 'args' => $rules, + $config instanceof BootloadConfig && $override => $config->{$key}, + $config instanceof BootloadConfig && !$override && \is_array($default) => + $config->{$key} + ($attr->{$key} ?? []), + $config instanceof BootloadConfig && !$override && \is_bool($default) => $config->{$key}, + \is_array($config) && $config !== [] && $key === 'args' => $config, default => $attr->{$key} ?? $default, }; }; - $override = $rules instanceof BootloaderRules ? $rules->override : true; + $override = $config instanceof BootloadConfig ? $config->override : true; - return new BootloaderRules( + return new BootloadConfig( args: $getArgument('args', $override), enabled: $getArgument('enabled', $override, true), allowEnv: $getArgument('allowEnv', $override), @@ -209,12 +209,12 @@ private function getBootloaderRules( /** * @param class-string|BootloaderInterface $bootloader */ - private function getBootloaderRulesAttribute(string|BootloaderInterface $bootloader): ?BootloaderRules + private function getBootloadConfigAttribute(string|BootloaderInterface $bootloader): ?BootloadConfig { $attribute = null; if ($bootloader instanceof BootloaderInterface || \class_exists($bootloader)) { $ref = new \ReflectionClass($bootloader); - $attribute = $ref->getAttributes(BootloaderRules::class)[0] ?? null; + $attribute = $ref->getAttributes(BootloadConfig::class)[0] ?? null; } if ($attribute === null) { diff --git a/src/Boot/src/BootloadManager/StrategyBasedBootloadManager.php b/src/Boot/src/BootloadManager/StrategyBasedBootloadManager.php index ea572f1d0..308719147 100644 --- a/src/Boot/src/BootloadManager/StrategyBasedBootloadManager.php +++ b/src/Boot/src/BootloadManager/StrategyBasedBootloadManager.php @@ -27,9 +27,9 @@ protected function boot( array $classes, array $bootingCallbacks, array $bootedCallbacks, - bool $useRules = true + bool $useConfig = true ): void { /** @psalm-suppress TooManyArguments */ - $this->invoker->invokeBootloaders($classes, $bootingCallbacks, $bootedCallbacks, $useRules); + $this->invoker->invokeBootloaders($classes, $bootingCallbacks, $bootedCallbacks, $useConfig); } } diff --git a/src/Boot/tests/BootloadManager/AttributeBootloaderRulesTest.php b/src/Boot/tests/BootloadManager/AttributeBootloadConfigTest.php similarity index 96% rename from src/Boot/tests/BootloadManager/AttributeBootloaderRulesTest.php rename to src/Boot/tests/BootloadManager/AttributeBootloadConfigTest.php index 617156d08..cd37245e4 100644 --- a/src/Boot/tests/BootloadManager/AttributeBootloaderRulesTest.php +++ b/src/Boot/tests/BootloadManager/AttributeBootloadConfigTest.php @@ -16,9 +16,9 @@ use Spiral\Tests\Boot\Fixtures\BootloaderJ; use Spiral\Tests\Boot\Fixtures\BootloaderK; -final class AttributeBootloaderRulesTest extends InitializerTestCase +final class AttributeBootloadConfigTest extends InitializerTestCase { - public function testDefaultBootloaderRules(): void + public function testDefaultBootloadConfig(): void { $result = \iterator_to_array($this->initializer->init([BootloaderE::class, BootloaderD::class])); @@ -46,7 +46,7 @@ public function testArguments(): void ], $result); } - public function testDisabledRules(): void + public function testDisabledConfig(): void { $result = \iterator_to_array($this->initializer->init([BootloaderF::class, BootloaderD::class], false)); diff --git a/src/Boot/tests/BootloadManager/BootloaderRulesTest.php b/src/Boot/tests/BootloadManager/BootloadConfigTest.php similarity index 82% rename from src/Boot/tests/BootloadManager/BootloaderRulesTest.php rename to src/Boot/tests/BootloadManager/BootloadConfigTest.php index 174a9a5bc..ce4549a76 100644 --- a/src/Boot/tests/BootloadManager/BootloaderRulesTest.php +++ b/src/Boot/tests/BootloadManager/BootloadConfigTest.php @@ -5,19 +5,19 @@ namespace Spiral\Tests\Boot\BootloadManager; use PHPUnit\Framework\Attributes\DataProvider; -use Spiral\Boot\Attribute\BootloaderRules; +use Spiral\Boot\Attribute\BootloadConfig; use Spiral\Boot\Environment; use Spiral\Boot\Environment\AppEnvironment; use Spiral\Boot\EnvironmentInterface; use Spiral\Tests\Boot\Fixtures\BootloaderA; use Spiral\Tests\Boot\Fixtures\BootloaderD; -final class BootloaderRulesTest extends InitializerTestCase +final class BootloadConfigTest extends InitializerTestCase { - public function testDefaultBootloaderRules(): void + public function testDefaultBootloadConfig(): void { $result = \iterator_to_array($this->initializer->init([ - BootloaderA::class => new BootloaderRules(), + BootloaderA::class => new BootloadConfig(), BootloaderD::class ])); @@ -30,7 +30,7 @@ public function testDefaultBootloaderRules(): void public function testDisabledBootloader(): void { $result = \iterator_to_array($this->initializer->init([ - BootloaderA::class => new BootloaderRules(enabled: false), + BootloaderA::class => new BootloadConfig(enabled: false), BootloaderD::class ])); @@ -42,7 +42,7 @@ public function testDisabledBootloader(): void public function testArguments(): void { $result = \iterator_to_array($this->initializer->init([ - BootloaderA::class => new BootloaderRules(args: ['a' => 'b']) + BootloaderA::class => new BootloadConfig(args: ['a' => 'b']) ])); $this->assertEquals([ @@ -50,10 +50,10 @@ public function testArguments(): void ], $result); } - public function testDisabledRules(): void + public function testDisabledConfig(): void { $result = \iterator_to_array($this->initializer->init([ - BootloaderA::class => new BootloaderRules(enabled: false), + BootloaderA::class => new BootloadConfig(enabled: false), BootloaderD::class ], false)); @@ -63,10 +63,10 @@ public function testDisabledRules(): void ], $result); } - public function testCallableRules(): void + public function testCallableConfig(): void { $result = \iterator_to_array($this->initializer->init([ - BootloaderA::class => static fn () => new BootloaderRules(args: ['a' => 'b']), + BootloaderA::class => static fn () => new BootloadConfig(args: ['a' => 'b']), ])); $this->assertEquals([ @@ -74,17 +74,17 @@ public function testCallableRules(): void ], $result); } - public function testCallableRulesWithArguments(): void + public function testCallableConfigWithArguments(): void { $this->container->bind(AppEnvironment::class, AppEnvironment::Production); $result = \iterator_to_array($this->initializer->init([ - BootloaderA::class => static fn (AppEnvironment $env) => new BootloaderRules(enabled: $env->isLocal()), + BootloaderA::class => static fn (AppEnvironment $env) => new BootloadConfig(enabled: $env->isLocal()), ])); $this->assertEquals([], $result); $result = \iterator_to_array($this->initializer->init([ - BootloaderA::class => static fn (AppEnvironment $env) => new BootloaderRules(enabled: $env->isProduction()), + BootloaderA::class => static fn (AppEnvironment $env) => new BootloadConfig(enabled: $env->isProduction()), ])); $this->assertEquals([BootloaderA::class => ['bootloader' => new BootloaderA(), 'options' => []]], $result); } @@ -95,7 +95,7 @@ public function testAllowEnv(array $env, array $expected): void $this->container->bindSingleton(EnvironmentInterface::class, new Environment($env), true); $result = \iterator_to_array($this->initializer->init([ - BootloaderA::class => new BootloaderRules(allowEnv: [ + BootloaderA::class => new BootloadConfig(allowEnv: [ 'APP_ENV' => 'prod', 'APP_DEBUG' => false, 'RR_MODE' => ['http'] @@ -111,7 +111,7 @@ public function testDenyEnv(array $env, array $expected): void $this->container->bindSingleton(EnvironmentInterface::class, new Environment($env), true); $result = \iterator_to_array($this->initializer->init([ - BootloaderA::class => new BootloaderRules(denyEnv: [ + BootloaderA::class => new BootloadConfig(denyEnv: [ 'RR_MODE' => 'http', 'APP_ENV' => ['production', 'prod'], 'DB_HOST' => 'db.example.com', @@ -126,14 +126,7 @@ public function testDenyEnvShouldHaveHigherPriority(): void $this->container->bindSingleton(EnvironmentInterface::class, new Environment(['APP_DEBUG' => true]), true); $result = \iterator_to_array($this->initializer->init([ - BootloaderA::class => new BootloaderRules( - allowEnv: [ - 'APP_DEBUG' => true, - ], - denyEnv: [ - 'APP_DEBUG' => true, - ] - ), + BootloaderA::class => new BootloadConfig(allowEnv: ['APP_DEBUG' => true], denyEnv: ['APP_DEBUG' => true]), ])); $this->assertEquals([], $result); diff --git a/src/Boot/tests/BootloadManager/Checker/ConfigCheckerTest.php b/src/Boot/tests/BootloadManager/Checker/ConfigCheckerTest.php new file mode 100644 index 000000000..e040a1770 --- /dev/null +++ b/src/Boot/tests/BootloadManager/Checker/ConfigCheckerTest.php @@ -0,0 +1,46 @@ + 'dev' + ])); + + $this->assertSame($expected, $checker->canInitialize(BootloaderA::class, $config)); + } + + public static function canInitializeDataProvider(): \Traversable + { + yield [true, null]; + yield [true, new BootloadConfig()]; + yield [false, new BootloadConfig(enabled: false)]; + + yield [true, new BootloadConfig(allowEnv: ['APP_ENV' => 'dev'])]; + yield [true, new BootloadConfig(allowEnv: ['APP_ENV' => ['dev']])]; + yield [false, new BootloadConfig(allowEnv: ['APP_ENV' => 'dev', 'DEBUG' => true])]; + yield [false, new BootloadConfig(allowEnv: ['APP_ENV' => 'prod'])]; + yield [false, new BootloadConfig(allowEnv: ['APP_ENV' => ['prod']])]; + yield [false, new BootloadConfig(allowEnv: ['APP_ENV' => ['prod'], 'DEBUG' => true])]; + + yield [false, new BootloadConfig(denyEnv: ['APP_ENV' => 'dev'])]; + yield [false, new BootloadConfig(denyEnv: ['APP_ENV' => ['dev']])]; + yield [false, new BootloadConfig(denyEnv: ['APP_ENV' => 'dev', 'DEBUG' => true])]; + yield [true, new BootloadConfig(denyEnv: ['APP_ENV' => 'prod'])]; + yield [true, new BootloadConfig(denyEnv: ['APP_ENV' => ['prod']])]; + yield [true, new BootloadConfig(denyEnv: ['APP_ENV' => ['prod'], 'DEBUG' => true])]; + } +} diff --git a/src/Boot/tests/BootloadManager/Checker/RulesCheckerTest.php b/src/Boot/tests/BootloadManager/Checker/RulesCheckerTest.php deleted file mode 100644 index 6ceaa5d30..000000000 --- a/src/Boot/tests/BootloadManager/Checker/RulesCheckerTest.php +++ /dev/null @@ -1,56 +0,0 @@ - 'dev' - ])); - - $this->assertSame($expected, $checker->canInitialize(BootloaderA::class, $rules)); - } - - public function testCanInitializeException(): void - { - $checker = new ClassExistsChecker(); - - $this->expectException(ClassNotFoundException::class); - $checker->canInitialize('foo'); - } - - public static function canInitializeDataProvider(): \Traversable - { - yield [true, null]; - yield [true, new BootloaderRules()]; - yield [false, new BootloaderRules(enabled: false)]; - - yield [true, new BootloaderRules(allowEnv: ['APP_ENV' => 'dev'])]; - yield [true, new BootloaderRules(allowEnv: ['APP_ENV' => ['dev']])]; - yield [false, new BootloaderRules(allowEnv: ['APP_ENV' => 'dev', 'DEBUG' => true])]; - yield [false, new BootloaderRules(allowEnv: ['APP_ENV' => 'prod'])]; - yield [false, new BootloaderRules(allowEnv: ['APP_ENV' => ['prod']])]; - yield [false, new BootloaderRules(allowEnv: ['APP_ENV' => ['prod'], 'DEBUG' => true])]; - - yield [false, new BootloaderRules(denyEnv: ['APP_ENV' => 'dev'])]; - yield [false, new BootloaderRules(denyEnv: ['APP_ENV' => ['dev']])]; - yield [false, new BootloaderRules(denyEnv: ['APP_ENV' => 'dev', 'DEBUG' => true])]; - yield [true, new BootloaderRules(denyEnv: ['APP_ENV' => 'prod'])]; - yield [true, new BootloaderRules(denyEnv: ['APP_ENV' => ['prod']])]; - yield [true, new BootloaderRules(denyEnv: ['APP_ENV' => ['prod'], 'DEBUG' => true])]; - } -} diff --git a/src/Boot/tests/BootloadManager/MergeBootloaderRulesTest.php b/src/Boot/tests/BootloadManager/MergeBootloadConfigTest.php similarity index 70% rename from src/Boot/tests/BootloadManager/MergeBootloaderRulesTest.php rename to src/Boot/tests/BootloadManager/MergeBootloadConfigTest.php index 27a8f2281..8e1b28f72 100644 --- a/src/Boot/tests/BootloadManager/MergeBootloaderRulesTest.php +++ b/src/Boot/tests/BootloadManager/MergeBootloadConfigTest.php @@ -4,19 +4,19 @@ namespace Spiral\Tests\Boot\BootloadManager; -use Spiral\Boot\Attribute\BootloaderRules; +use Spiral\Boot\Attribute\BootloadConfig; use Spiral\Tests\Boot\Fixtures\BootloaderD; use Spiral\Tests\Boot\Fixtures\BootloaderF; use Spiral\Tests\Boot\Fixtures\BootloaderG; use Spiral\Tests\Boot\Fixtures\BootloaderH; use Spiral\Tests\Boot\Fixtures\BootloaderI; -final class MergeBootloaderRulesTest extends InitializerTestCase +final class MergeBootloadConfigTest extends InitializerTestCase { public function testOverrideEnabled(): void { $result = \iterator_to_array($this->initializer->init([ - BootloaderF::class => new BootloaderRules(enabled: true), + BootloaderF::class => new BootloadConfig(enabled: true), BootloaderD::class ])); @@ -29,7 +29,7 @@ public function testOverrideEnabled(): void public function testOverrideArgs(): void { $result = \iterator_to_array($this->initializer->init([ - BootloaderG::class => new BootloaderRules(args: ['foo' => 'bar']), + BootloaderG::class => new BootloadConfig(args: ['foo' => 'bar']), ])); $this->assertEquals([ @@ -40,7 +40,7 @@ public function testOverrideArgs(): void public function testMergeArgs(): void { $result = \iterator_to_array($this->initializer->init([ - BootloaderG::class => new BootloaderRules(args: ['foo' => 'bar', 'a' => 'baz'], override: false), + BootloaderG::class => new BootloadConfig(args: ['foo' => 'bar', 'a' => 'baz'], override: false), ])); $this->assertEquals([ @@ -54,23 +54,23 @@ public function testMergeArgs(): void public function testOverrideAllowEnv(): void { - $ref = new \ReflectionMethod($this->initializer, 'getBootloaderRules'); - $rules = $ref->invoke( + $ref = new \ReflectionMethod($this->initializer, 'getBootloadConfig'); + $config = $ref->invoke( $this->initializer, BootloaderH::class, - new BootloaderRules(allowEnv: ['foo' => 'bar']) + new BootloadConfig(allowEnv: ['foo' => 'bar']) ); - $this->assertEquals(['foo' => 'bar'], $rules->allowEnv); + $this->assertEquals(['foo' => 'bar'], $config->allowEnv); } public function testMergeAllowEnv(): void { - $ref = new \ReflectionMethod($this->initializer, 'getBootloaderRules'); - $rules = $ref->invoke( + $ref = new \ReflectionMethod($this->initializer, 'getBootloadConfig'); + $config = $ref->invoke( $this->initializer, BootloaderH::class, - new BootloaderRules(allowEnv: ['APP_ENV' => 'dev', 'foo' => 'bar'], override: false) + new BootloadConfig(allowEnv: ['APP_ENV' => 'dev', 'foo' => 'bar'], override: false) ); $this->assertEquals([ @@ -78,28 +78,28 @@ public function testMergeAllowEnv(): void 'APP_ENV' => 'dev', 'APP_DEBUG' => false, 'RR_MODE' => ['http'] - ], $rules->allowEnv); + ], $config->allowEnv); } public function testOverrideDenyEnv(): void { - $ref = new \ReflectionMethod($this->initializer, 'getBootloaderRules'); - $rules = $ref->invoke( + $ref = new \ReflectionMethod($this->initializer, 'getBootloadConfig'); + $config = $ref->invoke( $this->initializer, BootloaderI::class, - new BootloaderRules(denyEnv: ['foo' => 'bar']) + new BootloadConfig(denyEnv: ['foo' => 'bar']) ); - $this->assertEquals(['foo' => 'bar'], $rules->denyEnv); + $this->assertEquals(['foo' => 'bar'], $config->denyEnv); } public function testMergeDenyEnv(): void { - $ref = new \ReflectionMethod($this->initializer, 'getBootloaderRules'); - $rules = $ref->invoke( + $ref = new \ReflectionMethod($this->initializer, 'getBootloadConfig'); + $config = $ref->invoke( $this->initializer, BootloaderI::class, - new BootloaderRules(denyEnv: ['DB_HOST' => 'localhost', 'foo' => 'bar'], override: false) + new BootloadConfig(denyEnv: ['DB_HOST' => 'localhost', 'foo' => 'bar'], override: false) ); $this->assertEquals([ @@ -107,6 +107,6 @@ public function testMergeDenyEnv(): void 'RR_MODE' => 'http', 'APP_ENV' => ['production', 'prod'], 'DB_HOST' => 'localhost', - ], $rules->denyEnv); + ], $config->denyEnv); } } diff --git a/src/Boot/tests/Fixtures/Attribute/TargetWorker.php b/src/Boot/tests/Fixtures/Attribute/TargetWorker.php index 031ae6430..b9b05ea9a 100644 --- a/src/Boot/tests/Fixtures/Attribute/TargetWorker.php +++ b/src/Boot/tests/Fixtures/Attribute/TargetWorker.php @@ -4,11 +4,11 @@ namespace Spiral\Tests\Boot\Fixtures\Attribute; -use Spiral\Boot\Attribute\BootloaderRules; +use Spiral\Boot\Attribute\BootloadConfig; use Spiral\Attributes\NamedArgumentConstructor; #[\Attribute(\Attribute::TARGET_CLASS), NamedArgumentConstructor] -final class TargetWorker extends BootloaderRules +final class TargetWorker extends BootloadConfig { public function __construct(array|string $workers) { diff --git a/src/Boot/tests/Fixtures/BootloaderE.php b/src/Boot/tests/Fixtures/BootloaderE.php index 0a544d7c3..cbcc0cc30 100644 --- a/src/Boot/tests/Fixtures/BootloaderE.php +++ b/src/Boot/tests/Fixtures/BootloaderE.php @@ -4,9 +4,9 @@ namespace Spiral\Tests\Boot\Fixtures; -use Spiral\Boot\Attribute\BootloaderRules; +use Spiral\Boot\Attribute\BootloadConfig; -#[BootloaderRules] +#[BootloadConfig] class BootloaderE extends AbstractBootloader { } diff --git a/src/Boot/tests/Fixtures/BootloaderF.php b/src/Boot/tests/Fixtures/BootloaderF.php index ca1982ec5..42f699d78 100644 --- a/src/Boot/tests/Fixtures/BootloaderF.php +++ b/src/Boot/tests/Fixtures/BootloaderF.php @@ -4,9 +4,9 @@ namespace Spiral\Tests\Boot\Fixtures; -use Spiral\Boot\Attribute\BootloaderRules; +use Spiral\Boot\Attribute\BootloadConfig; -#[BootloaderRules(enabled: false)] +#[BootloadConfig(enabled: false)] class BootloaderF extends AbstractBootloader { } diff --git a/src/Boot/tests/Fixtures/BootloaderG.php b/src/Boot/tests/Fixtures/BootloaderG.php index fb43fbf1a..7c735dcd0 100644 --- a/src/Boot/tests/Fixtures/BootloaderG.php +++ b/src/Boot/tests/Fixtures/BootloaderG.php @@ -4,9 +4,9 @@ namespace Spiral\Tests\Boot\Fixtures; -use Spiral\Boot\Attribute\BootloaderRules; +use Spiral\Boot\Attribute\BootloadConfig; -#[BootloaderRules(args: ['a' => 'b', 'c' => 'd'])] +#[BootloadConfig(args: ['a' => 'b', 'c' => 'd'])] class BootloaderG extends AbstractBootloader { } diff --git a/src/Boot/tests/Fixtures/BootloaderH.php b/src/Boot/tests/Fixtures/BootloaderH.php index 4d7a53352..f2b92d879 100644 --- a/src/Boot/tests/Fixtures/BootloaderH.php +++ b/src/Boot/tests/Fixtures/BootloaderH.php @@ -4,9 +4,9 @@ namespace Spiral\Tests\Boot\Fixtures; -use Spiral\Boot\Attribute\BootloaderRules; +use Spiral\Boot\Attribute\BootloadConfig; -#[BootloaderRules(allowEnv: [ +#[BootloadConfig(allowEnv: [ 'APP_ENV' => 'prod', 'APP_DEBUG' => false, 'RR_MODE' => ['http'] diff --git a/src/Boot/tests/Fixtures/BootloaderI.php b/src/Boot/tests/Fixtures/BootloaderI.php index eb6affa1f..bb331ec20 100644 --- a/src/Boot/tests/Fixtures/BootloaderI.php +++ b/src/Boot/tests/Fixtures/BootloaderI.php @@ -4,9 +4,9 @@ namespace Spiral\Tests\Boot\Fixtures; -use Spiral\Boot\Attribute\BootloaderRules; +use Spiral\Boot\Attribute\BootloadConfig; -#[BootloaderRules(denyEnv: [ +#[BootloadConfig(denyEnv: [ 'RR_MODE' => 'http', 'APP_ENV' => ['production', 'prod'], 'DB_HOST' => 'db.example.com', diff --git a/src/Boot/tests/Fixtures/BootloaderJ.php b/src/Boot/tests/Fixtures/BootloaderJ.php index 7b4ba3569..78b1b4c16 100644 --- a/src/Boot/tests/Fixtures/BootloaderJ.php +++ b/src/Boot/tests/Fixtures/BootloaderJ.php @@ -4,9 +4,9 @@ namespace Spiral\Tests\Boot\Fixtures; -use Spiral\Boot\Attribute\BootloaderRules; +use Spiral\Boot\Attribute\BootloadConfig; -#[BootloaderRules(allowEnv: ['APP_DEBUG' => true], denyEnv: ['APP_DEBUG' => true])] +#[BootloadConfig(allowEnv: ['APP_DEBUG' => true], denyEnv: ['APP_DEBUG' => true])] class BootloaderJ extends AbstractBootloader { }