diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d77aef..2afcd19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ ## Changelog +### v5.5.0 +- extractor configuration can now contain an array of extractors ### v5.0.0 - deprecated PHP 7.3 - add PHP 8.1 diff --git a/src/Service/Extractor/Factory/ExtractorFactory.php b/src/Service/Extractor/Factory/ExtractorFactory.php index 679e725..bdfd1fc 100644 --- a/src/Service/Extractor/Factory/ExtractorFactory.php +++ b/src/Service/Extractor/Factory/ExtractorFactory.php @@ -22,13 +22,7 @@ public function __invoke(ContainerInterface $container): ExtractorInterface /** @var array $config */ $config = $container->get(ModuleConfig::class); - $extractors = []; - - $extractorFromConfig = $this->extractorFromConfig($container, $config); - - if ($extractorFromConfig instanceof ExtractorInterface) { - $extractors[] = $extractorFromConfig; - } + $extractors = $this->extractorsFromConfig($container, $config); if (class_exists('Doctrine\Common\Annotations\AnnotationReader')) { $extractors[] = $container->get(AnnotationExtractor::class); @@ -41,27 +35,45 @@ public function __invoke(ContainerInterface $container): ExtractorInterface return new ExtractorChain($extractors); } - private function extractorFromConfig( + /** + * @return ExtractorInterface[] + */ + private function extractorsFromConfig( ContainerInterface $container, array $config - ): ?ExtractorInterface { + ): array { $extractorConfiguration = $config['extractor'] ?? null; if ($extractorConfiguration === null) { - return null; + return []; } - $extractor = $container->get($extractorConfiguration); + if (! is_string($extractorConfiguration) && ! is_array($extractorConfiguration)) { + throw new InvalidArgumentException( + 'Configuration property "extractor" must be of either string or array of strings' + ); + } - if ($extractor instanceof ExtractorInterface) { - return $extractor; + if (is_string($extractorConfiguration)) { + $extractorConfiguration = [$extractorConfiguration]; } - throw new InvalidArgumentException( - sprintf( - 'Configuration property "extractor" must be of type %s', - ExtractorInterface::class - ) + return array_map( + function (string $extractorClassName) use ($container): ExtractorInterface { + $extractor = $container->get($extractorClassName); + + if ($extractor instanceof ExtractorInterface) { + return $extractor; + } + + throw new InvalidArgumentException( + sprintf( + 'Configuration property "extractor" must be of type %s', + ExtractorInterface::class + ) + ); + }, + $extractorConfiguration ); } } diff --git a/test/Unit/Service/Extractor/Factory/ExtractorFactoryTest.php b/test/Unit/Service/Extractor/Factory/ExtractorFactoryTest.php index a82d53b..5109b73 100644 --- a/test/Unit/Service/Extractor/Factory/ExtractorFactoryTest.php +++ b/test/Unit/Service/Extractor/Factory/ExtractorFactoryTest.php @@ -73,6 +73,57 @@ public function testItReturnsExtractorDefinedInConfig(): void self::assertContainsOnlyInstancesOf(ExtractorInterface::class, $chain); } + public function testItReturnsArrayOfExtractorsDefinedInConfig(): void + { + $isPhp8OrAbove = version_compare(PHP_VERSION, '8.0.0') >= 0; + + $moduleConfig = new Config([ + 'extractor' => [ + YamlExtractor::class, + ], + ]); + + $yamlExtractor = $this->prophesize(YamlExtractor::class); + $annotationExtractor = $this->prophesize(AnnotationExtractor::class); + $attributeExtractor = $this->prophesize(AttributeExtractor::class); + $container = $this->prophesize(ContainerInterface::class); + + $container->get(ModuleConfig::class) + ->willReturn($moduleConfig->toArray()) + ->shouldBeCalled(); + $container->get(YamlExtractor::class) + ->willReturn($yamlExtractor->reveal()) + ->shouldBeCalled(); + $container->get(AnnotationExtractor::class) + ->willReturn($annotationExtractor->reveal()) + ->shouldBeCalled(); + $container->get(AttributeExtractor::class) + ->willReturn($attributeExtractor->reveal()) + ->shouldBeCalledTimes($isPhp8OrAbove ? 1 : 0); + + $factory = new ExtractorFactory(); + + $extractor = $factory($container->reveal()); + + self::assertInstanceOf(ExtractorChain::class, $extractor); + + $reflectionClass = new ReflectionClass($extractor); + $chainProperty = $reflectionClass->getProperty('chain'); + $chainProperty->setAccessible(true); + + $chain = $chainProperty->getValue($extractor); + + self::assertTrue(is_array($chain)); + + if ($isPhp8OrAbove) { + self::assertCount(3, $chain); + } else { + self::assertCount(2, $chain); + } + + self::assertContainsOnlyInstancesOf(ExtractorInterface::class, $chain); + } + public function testItReturnsAnnotationExtractorIfNoneDefined(): void { $isPhp8OrAbove = version_compare(PHP_VERSION, '8.0.0') >= 0;