From a40a777e658c2c0ab0663b5abec4763680db50e6 Mon Sep 17 00:00:00 2001 From: Nicolas Guilloux Date: Fri, 24 Dec 2021 10:50:46 +0100 Subject: [PATCH 1/2] Prepare v1.1.0 --- CHANGELOG.md | 5 ++ docs/ServiceArgumentInjection.adoc | 36 ++++++++- .../AbstractServiceInjectionAnnotation.php | 24 ++++++ src/Annotation/Argument.php | 15 +--- src/Annotation/Method.php | 36 +++++++++ src/Annotation/Property.php | 15 +--- .../ServiceAutoConfiguratorInterface.php | 4 +- ...stractServiceInjectionAutoConfigurator.php | 40 ++++++++++ .../Partials/ArgumentAutoConfigurator.php | 28 +------ .../Partials/DecorationAutoConfigurator.php | 4 +- .../Partials/MethodCallAutoConfigurator.php | 42 +++++++++-- .../Partials/PropertyAutoConfigurator.php | 26 ++----- .../Partials/TagAutoConfigurator.php | 4 +- ...nAnnotationServiceConfigurationFactory.php | 9 ++- ...dAnnotationServiceConfigurationFactory.php | 36 +++++++++ src/Factory/ServiceConfigurationFactory.php | 2 + src/Model/ServiceConfiguration.php | 7 +- .../Configuration/ServiceWithArgumentTest.php | 11 +++ tests/Configuration/ServiceWithMethodTest.php | 52 +++++++++++++ .../Configuration/ServiceWithPropertyTest.php | 9 +++ tests/Definition/ServiceWithArgumentTest.php | 11 +++ tests/Definition/ServiceWithMethodTest.php | 73 +++++++++++++++++++ tests/Definition/ServiceWithPropertyTest.php | 11 +++ .../Resources/Service/ServiceWithArgument.php | 8 +- tests/Resources/Service/ServiceWithMethod.php | 45 ++++++++++++ .../Resources/Service/ServiceWithProperty.php | 5 ++ .../Resources/TestCase/DefinitionTestCase.php | 5 ++ 27 files changed, 475 insertions(+), 88 deletions(-) create mode 100644 src/Annotation/AbstractServiceInjectionAnnotation.php create mode 100644 src/Annotation/Method.php create mode 100644 src/Configurators/Partials/AbstractServiceInjectionAutoConfigurator.php create mode 100644 src/Factory/Partials/MethodAnnotationServiceConfigurationFactory.php create mode 100644 tests/Configuration/ServiceWithMethodTest.php create mode 100644 tests/Definition/ServiceWithMethodTest.php create mode 100644 tests/Resources/Service/ServiceWithMethod.php diff --git a/CHANGELOG.md b/CHANGELOG.md index e159b73..11a32bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## Version 1.1.0 + +- Add service tag injection +- Add method annotation to add MethodCall to the service definition + ## Version 1.0.1 - Fix annotation dependency where it was diff --git a/docs/ServiceArgumentInjection.adoc b/docs/ServiceArgumentInjection.adoc index 159fe62..46be201 100644 --- a/docs/ServiceArgumentInjection.adoc +++ b/docs/ServiceArgumentInjection.adoc @@ -4,7 +4,7 @@ Sometimes it is required to inject a service that is not autowired, or a specifi === In the constructor -To do so, add the `Argument` annotation/attribute on the class with the appropriate values. Here is an example where we inject the `doctrine` service and the default locale into the constructor: +To do so, add the `Argument` annotation/attribute on the class with the appropriate values. Here is an example where we inject the `doctrine` service, the default locale and all the tagged command into the constructor: [source, php] ---- @@ -13,10 +13,11 @@ use RichId\AutoconfigureBundle\Annotation as Service; #[ Service\Argument('$doctrine', 'doctrine'), Service\Argument('$locale', 'kernel.default_locale', type='parameter'), + Service\Argyment('commands', 'console.command', type='services_by_tag'), ] class RandomService { - public function __construct($doctrine, string $locale) + public function __construct($doctrine, string $locale, array $commands) { ... } @@ -25,7 +26,7 @@ class RandomService === In a public property -To do so, add the `Property` annotation/attribute on the class with the appropriate values. Here is an example where we inject the `doctrine` service and the default locale into the corresponding public properties: +To do so, add the `Property` annotation/attribute on the class with the appropriate values. Here is an example where we inject the `doctrine` service, the default locale and all the tagged commands into the corresponding public properties: [source, php] ---- @@ -34,10 +35,39 @@ use RichId\AutoconfigureBundle\Annotation as Service; #[ Service\Property('doctrine', 'doctrine'), Service\Property('locale', 'kernel.default_locale', type='parameter'), + Service\Property('commands', 'console.command', type='services_by_tag'), ] class RandomService { public $doctrine; public string $locale; + public array $commands; +} +---- + +=== In a public method + +To do so, add the `Method` annotation/attribute on the class with the appropriate values. Here is an example where we inject the 2 values to a method and all the tagged commands to another one. + +[source, php] +---- +use RichId\AutoconfigureBundle\Annotation as Service; + +#[ + Service\Method('setValues', 'doctrine'), + Service\Method('setValues', 'kernel.default_locale', type='parameter', position=1), + Service\Method('setCommands', 'console.command', type='services_by_tag'), +] +class RandomService +{ + public function setValues($doctrine, string $locale): void + { + // ... + } + + public function setCommands(array $commands): void + { + // ... + } } ---- diff --git a/src/Annotation/AbstractServiceInjectionAnnotation.php b/src/Annotation/AbstractServiceInjectionAnnotation.php new file mode 100644 index 0000000..86e82d0 --- /dev/null +++ b/src/Annotation/AbstractServiceInjectionAnnotation.php @@ -0,0 +1,24 @@ +value = $value; + $this->type = $type; + } +} diff --git a/src/Annotation/Argument.php b/src/Annotation/Argument.php index de3bc64..74444ba 100644 --- a/src/Annotation/Argument.php +++ b/src/Annotation/Argument.php @@ -18,24 +18,15 @@ * @NamedArgumentConstructor() */ #[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS)] -final class Argument implements AutoconfigureAnnotation +final class Argument extends AbstractServiceInjectionAnnotation { - public const SERVICE_TYPE = 'service'; - public const PARAMETER_TYPE = 'parameter'; - /** @var string */ public $argument; - /** @var string */ - public $value; - - /** @var string */ - public $type; - public function __construct(string $argument, string $value, string $type = self::SERVICE_TYPE) { + parent::__construct($value, $type); + $this->argument = $argument; - $this->value = $value; - $this->type = $type; } } diff --git a/src/Annotation/Method.php b/src/Annotation/Method.php new file mode 100644 index 0000000..6e1479e --- /dev/null +++ b/src/Annotation/Method.php @@ -0,0 +1,36 @@ + + * @copyright 2014 - 2021 Rich ID (https://www.rich-id.fr) + * + * @Annotation({"CLASS"}) + * @NamedArgumentConstructor() + */ +#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS)] +final class Method extends AbstractServiceInjectionAnnotation +{ + /** @var string */ + public $method; + + /** @var int */ + public $position = 0; + + public function __construct(string $method, string $value, string $type = self::SERVICE_TYPE, int $position = 0) + { + parent::__construct($value, $type); + + $this->method = $method; + $this->position = $position; + } +} diff --git a/src/Annotation/Property.php b/src/Annotation/Property.php index 5af1a50..184da12 100644 --- a/src/Annotation/Property.php +++ b/src/Annotation/Property.php @@ -18,24 +18,15 @@ * @NamedArgumentConstructor() */ #[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS)] -final class Property implements AutoconfigureAnnotation +final class Property extends AbstractServiceInjectionAnnotation { - public const SERVICE_TYPE = 'service'; - public const PARAMETER_TYPE = 'parameter'; - /** @var string */ public $property; - /** @var string */ - public $value; - - /** @var string */ - public $type; - public function __construct(string $property, string $value, string $type = self::SERVICE_TYPE) { + parent::__construct($value, $type); + $this->property = $property; - $this->value = $value; - $this->type = $type; } } diff --git a/src/Configurators/Basics/ServiceAutoConfiguratorInterface.php b/src/Configurators/Basics/ServiceAutoConfiguratorInterface.php index 233d552..e12869c 100644 --- a/src/Configurators/Basics/ServiceAutoConfiguratorInterface.php +++ b/src/Configurators/Basics/ServiceAutoConfiguratorInterface.php @@ -5,7 +5,7 @@ namespace RichId\AutoconfigureBundle\Configurators\Basics; use RichId\AutoconfigureBundle\Model\ServiceConfiguration; -use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; /** @@ -17,7 +17,7 @@ interface ServiceAutoConfiguratorInterface { public function autoconfigure( - Container $container, + ContainerBuilder $container, Definition $definition, ServiceConfiguration $configuration ): void; diff --git a/src/Configurators/Partials/AbstractServiceInjectionAutoConfigurator.php b/src/Configurators/Partials/AbstractServiceInjectionAutoConfigurator.php new file mode 100644 index 0000000..ce2e90c --- /dev/null +++ b/src/Configurators/Partials/AbstractServiceInjectionAutoConfigurator.php @@ -0,0 +1,40 @@ +getParameter($value); + + case AbstractServiceInjectionAnnotation::SERVICES_BY_TAG: + $serviceTags = $container->findTaggedServiceIds($value); + + return \array_map( + static function (string $serviceId): Reference { + return new Reference($serviceId); + }, + \array_keys($serviceTags) + ); + + default: + throw new \UnexpectedValueException('The type used a service configuration is wrong.'); + } + } +} diff --git a/src/Configurators/Partials/ArgumentAutoConfigurator.php b/src/Configurators/Partials/ArgumentAutoConfigurator.php index d29c812..9c09544 100644 --- a/src/Configurators/Partials/ArgumentAutoConfigurator.php +++ b/src/Configurators/Partials/ArgumentAutoConfigurator.php @@ -4,12 +4,9 @@ namespace RichId\AutoconfigureBundle\Configurators\Partials; -use RichId\AutoconfigureBundle\Annotation\Argument; -use RichId\AutoconfigureBundle\Configurators\Basics\ServiceAutoConfiguratorInterface; use RichId\AutoconfigureBundle\Model\ServiceConfiguration; -use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; /** * Class ArgumentAutoConfigurator. @@ -17,10 +14,10 @@ * @author Nicolas Guilloux * @copyright 2014 - 2021 Rich ID (https://www.rich-id.fr) */ -final class ArgumentAutoConfigurator implements ServiceAutoConfiguratorInterface +final class ArgumentAutoConfigurator extends AbstractServiceInjectionAutoConfigurator { public function autoconfigure( - Container $container, + ContainerBuilder $container, Definition $definition, ServiceConfiguration $configuration ): void { @@ -29,25 +26,8 @@ public function autoconfigure( $definition->setArgument( $sanitizedArgument, - $this->getObject($container, $options) + $this->resolveObject($container, $options) ); } } - - public function getObject(Container $container, array $options) - { - $type = $options['type'] ?? null; - $value = $options['value'] ?? null; - - switch ($type) { - case Argument::SERVICE_TYPE: - return new Reference($value); - - case Argument::PARAMETER_TYPE: - return $container->getParameter($value); - - default: - throw new \UnexpectedValueException('The type used a service configuration is wrong.'); - } - } } diff --git a/src/Configurators/Partials/DecorationAutoConfigurator.php b/src/Configurators/Partials/DecorationAutoConfigurator.php index a870077..aee4131 100644 --- a/src/Configurators/Partials/DecorationAutoConfigurator.php +++ b/src/Configurators/Partials/DecorationAutoConfigurator.php @@ -6,7 +6,7 @@ use RichId\AutoconfigureBundle\Configurators\Basics\ServiceAutoConfiguratorInterface; use RichId\AutoconfigureBundle\Model\ServiceConfiguration; -use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; /** @@ -18,7 +18,7 @@ final class DecorationAutoConfigurator implements ServiceAutoConfiguratorInterface { public function autoconfigure( - Container $container, + ContainerBuilder $container, Definition $definition, ServiceConfiguration $configuration ): void { diff --git a/src/Configurators/Partials/MethodCallAutoConfigurator.php b/src/Configurators/Partials/MethodCallAutoConfigurator.php index deaa9ac..0aef553 100644 --- a/src/Configurators/Partials/MethodCallAutoConfigurator.php +++ b/src/Configurators/Partials/MethodCallAutoConfigurator.php @@ -4,9 +4,8 @@ namespace RichId\AutoconfigureBundle\Configurators\Partials; -use RichId\AutoconfigureBundle\Configurators\Basics\ServiceAutoConfiguratorInterface; use RichId\AutoconfigureBundle\Model\ServiceConfiguration; -use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; /** @@ -15,15 +14,48 @@ * @author Nicolas Guilloux * @copyright 2014 - 2021 Rich ID (https://www.rich-id.fr) */ -final class MethodCallAutoConfigurator implements ServiceAutoConfiguratorInterface +final class MethodCallAutoConfigurator extends AbstractServiceInjectionAutoConfigurator { public function autoconfigure( - Container $container, + ContainerBuilder $container, Definition $definition, ServiceConfiguration $configuration ): void { foreach ($configuration->getMethodCalls() as $method => $arguments) { - $definition->addMethodCall($method, $arguments); + $resolvedArguments = $this->findMethodCallExistingArguments($definition, $method); + + foreach ($arguments as $key => $value) { + $resolvedArguments[$key] = $this->resolveObject($container, $value); + } + + $this->setMethodCall($definition, $method, $resolvedArguments); + } + } + + private function findMethodCallExistingArguments(Definition $definition, string $method): array + { + foreach ($definition->getMethodCalls() as $data) { + if ($data[0] === $method) { + return $data[1] ?? []; + } + } + + return []; + } + + private function setMethodCall(Definition $definition, string $method, array $arguments): void + { + $methodCalls = $definition->getMethodCalls(); + + foreach ($methodCalls as $key => $data) { + if ($data[0] === $method) { + $methodCalls[$key] = [$method, $arguments]; + $definition->setMethodCalls($methodCalls); + + return; + } } + + $definition->addMethodCall($method, $arguments); } } diff --git a/src/Configurators/Partials/PropertyAutoConfigurator.php b/src/Configurators/Partials/PropertyAutoConfigurator.php index 89cb133..d83e840 100644 --- a/src/Configurators/Partials/PropertyAutoConfigurator.php +++ b/src/Configurators/Partials/PropertyAutoConfigurator.php @@ -4,12 +4,9 @@ namespace RichId\AutoconfigureBundle\Configurators\Partials; -use RichId\AutoconfigureBundle\Annotation\Property; -use RichId\AutoconfigureBundle\Configurators\Basics\ServiceAutoConfiguratorInterface; use RichId\AutoconfigureBundle\Model\ServiceConfiguration; -use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; /** * Class PropertyAutoConfigurator. @@ -17,30 +14,17 @@ * @author Nicolas Guilloux * @copyright 2014 - 2021 Rich ID (https://www.rich-id.fr) */ -final class PropertyAutoConfigurator implements ServiceAutoConfiguratorInterface +final class PropertyAutoConfigurator extends AbstractServiceInjectionAutoConfigurator { public function autoconfigure( - Container $container, + ContainerBuilder $container, Definition $definition, ServiceConfiguration $configuration ): void { foreach ($configuration->getProperties() as $property => $options) { - $type = $options['type'] ?? null; - $value = $options['value'] ?? null; $sanitizedProperty = \str_replace('$', '', $property); - - switch ($type) { - case Property::SERVICE_TYPE: - $definition->setProperty($sanitizedProperty, new Reference($value)); - break; - - case Property::PARAMETER_TYPE: - $definition->setProperty($sanitizedProperty, $container->getParameter($value)); - break; - - default: - throw new \UnexpectedValueException('The property type used a service configuration is wrong.'); - } + $value = $this->resolveObject($container, $options); + $definition->setProperty($sanitizedProperty, $value); } } } diff --git a/src/Configurators/Partials/TagAutoConfigurator.php b/src/Configurators/Partials/TagAutoConfigurator.php index 729e184..d1b5a48 100644 --- a/src/Configurators/Partials/TagAutoConfigurator.php +++ b/src/Configurators/Partials/TagAutoConfigurator.php @@ -6,7 +6,7 @@ use RichId\AutoconfigureBundle\Configurators\Basics\ServiceAutoConfiguratorInterface; use RichId\AutoconfigureBundle\Model\ServiceConfiguration; -use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; /** @@ -18,7 +18,7 @@ final class TagAutoConfigurator implements ServiceAutoConfiguratorInterface { public function autoconfigure( - Container $container, + ContainerBuilder $container, Definition $definition, ServiceConfiguration $configuration ): void { diff --git a/src/Factory/Partials/DecorationAnnotationServiceConfigurationFactory.php b/src/Factory/Partials/DecorationAnnotationServiceConfigurationFactory.php index be1cfb2..7c5e4bd 100644 --- a/src/Factory/Partials/DecorationAnnotationServiceConfigurationFactory.php +++ b/src/Factory/Partials/DecorationAnnotationServiceConfigurationFactory.php @@ -4,13 +4,13 @@ namespace RichId\AutoconfigureBundle\Factory\Partials; +use RichId\AutoconfigureBundle\Annotation\AbstractServiceInjectionAnnotation; use RichId\AutoconfigureBundle\Annotation\Argument; use RichId\AutoconfigureBundle\Annotation\AutoconfigureAnnotation; use RichId\AutoconfigureBundle\Annotation\Decoration; use RichId\AutoconfigureBundle\Annotation\Property; use RichId\AutoconfigureBundle\Factory\Basics\AbstractAnnotationServiceConfigurationFactory; use RichId\AutoconfigureBundle\Model\ServiceConfiguration; -use Symfony\Component\DependencyInjection\Reference; /** * Class DecorationAnnotationServiceConfigurationFactory. @@ -111,8 +111,11 @@ private static function bindToMethod(ServiceConfiguration $configuration): void return; } - $configuration->addMethodCall('setInnerService', [ - new Reference($reflectionClass->getName() . '.inner'), + $configuration->setMethodCall('setInnerService', [ + [ + 'type' => AbstractServiceInjectionAnnotation::SERVICE_TYPE, + 'value' => $reflectionClass->getName() . '.inner', + ], ]); } } diff --git a/src/Factory/Partials/MethodAnnotationServiceConfigurationFactory.php b/src/Factory/Partials/MethodAnnotationServiceConfigurationFactory.php new file mode 100644 index 0000000..243b5b3 --- /dev/null +++ b/src/Factory/Partials/MethodAnnotationServiceConfigurationFactory.php @@ -0,0 +1,36 @@ + + * @copyright 2014 - 2021 Rich ID (https://www.rich-id.fr) + */ +final class MethodAnnotationServiceConfigurationFactory extends AbstractAnnotationServiceConfigurationFactory +{ + /** @var string */ + protected static $annotationClass = Method::class; + + /** @param AutoconfigureAnnotation|Method $annotation */ + protected static function hydrateServiceConfiguration( + ServiceConfiguration $configuration, + AutoconfigureAnnotation $annotation + ): ServiceConfiguration { + $methodCall = $configuration->getMethodCall($annotation->method); + $methodCall[$annotation->position] = [ + 'type' => $annotation->type, + 'value' => $annotation->value, + ]; + + $configuration->setMethodCall($annotation->method, $methodCall); + + return $configuration; + } +} diff --git a/src/Factory/ServiceConfigurationFactory.php b/src/Factory/ServiceConfigurationFactory.php index fee0657..7fbe052 100644 --- a/src/Factory/ServiceConfigurationFactory.php +++ b/src/Factory/ServiceConfigurationFactory.php @@ -8,6 +8,7 @@ use RichId\AutoconfigureBundle\Factory\Partials\ArgumentAnnotationServiceConfigurationFactory; use RichId\AutoconfigureBundle\Factory\Partials\DecorationAnnotationServiceConfigurationFactory; use RichId\AutoconfigureBundle\Factory\Partials\EventListenerServiceConfigurationFactory; +use RichId\AutoconfigureBundle\Factory\Partials\MethodAnnotationServiceConfigurationFactory; use RichId\AutoconfigureBundle\Factory\Partials\PropertyAnnotationServiceConfigurationFactory; use RichId\AutoconfigureBundle\Factory\Partials\TagAnnotationServiceConfigurationFactory; use RichId\AutoconfigureBundle\Model\ServiceConfiguration; @@ -25,6 +26,7 @@ final class ServiceConfigurationFactory ArgumentAnnotationServiceConfigurationFactory::class, DecorationAnnotationServiceConfigurationFactory::class, EventListenerServiceConfigurationFactory::class, + MethodAnnotationServiceConfigurationFactory::class, PropertyAnnotationServiceConfigurationFactory::class, TagAnnotationServiceConfigurationFactory::class, ]; diff --git a/src/Model/ServiceConfiguration.php b/src/Model/ServiceConfiguration.php index 35c29e1..4362e56 100644 --- a/src/Model/ServiceConfiguration.php +++ b/src/Model/ServiceConfiguration.php @@ -63,6 +63,11 @@ public function getMethodCalls(): array return $this->methodCalls; } + public function getMethodCall(string $method): array + { + return $this->methodCalls[$method] ?? []; + } + /** @return array[] */ public function getTags(): array { @@ -90,7 +95,7 @@ public function setArgument(string $argument, array $options): self return $this; } - public function addMethodCall(string $method, array $arguments): self + public function setMethodCall(string $method, array $arguments): self { $this->methodCalls[$method] = $arguments; diff --git a/tests/Configuration/ServiceWithArgumentTest.php b/tests/Configuration/ServiceWithArgumentTest.php index 069d12d..ca29834 100644 --- a/tests/Configuration/ServiceWithArgumentTest.php +++ b/tests/Configuration/ServiceWithArgumentTest.php @@ -8,6 +8,7 @@ use RichCongress\TestSuite\TestCase\TestCase; use RichId\AutoconfigureBundle\Tests\Resources\Decorator\DecorationWithInnerServicePropertyEventListener; use RichId\AutoconfigureBundle\Tests\Resources\Service\ServiceWithArgument; +use Symfony\Component\Console\Command\Command; /** * Class ServiceWithArgumentTest. @@ -17,7 +18,9 @@ * * @TestConfig("container") * + * @covers \RichId\AutoconfigureBundle\Annotation\AbstractServiceInjectionAnnotation * @covers \RichId\AutoconfigureBundle\Annotation\Argument + * @covers \RichId\AutoconfigureBundle\Configurators\Partials\AbstractServiceInjectionAutoConfigurator * @covers \RichId\AutoconfigureBundle\Configurators\Partials\ArgumentAutoConfigurator * @covers \RichId\AutoconfigureBundle\Configurators\ServiceAutoConfigurator * @covers \RichId\AutoconfigureBundle\Factory\Basics\AbstractAnnotationServiceConfigurationFactory @@ -38,4 +41,12 @@ public function testArgumentParameterInjected(): void $service = $this->getService(ServiceWithArgument::class); self::assertSame('This is a test', $service->parameter); } + + public function testArgumentServicesByTagInjected(): void + { + $service = $this->getService(ServiceWithArgument::class); + + self::assertNotEmpty($service->commands); + self::assertContainsOnlyInstancesOf(Command::class, $service->commands); + } } diff --git a/tests/Configuration/ServiceWithMethodTest.php b/tests/Configuration/ServiceWithMethodTest.php new file mode 100644 index 0000000..9a96e62 --- /dev/null +++ b/tests/Configuration/ServiceWithMethodTest.php @@ -0,0 +1,52 @@ + + * @copyright 2014 - 2021 Rich ID (https://www.rich-id.fr) + * + * @TestConfig("container") + * + * @covers \RichId\AutoconfigureBundle\Annotation\AbstractServiceInjectionAnnotation + * @covers \RichId\AutoconfigureBundle\Annotation\Method + * @covers \RichId\AutoconfigureBundle\Configurators\Partials\AbstractServiceInjectionAutoConfigurator + * @covers \RichId\AutoconfigureBundle\Configurators\Partials\MethodCallAutoConfigurator + * @covers \RichId\AutoconfigureBundle\Configurators\ServiceAutoConfigurator + * @covers \RichId\AutoconfigureBundle\Factory\Basics\AbstractAnnotationServiceConfigurationFactory + * @covers \RichId\AutoconfigureBundle\Factory\Partials\MethodAnnotationServiceConfigurationFactory + * @covers \RichId\AutoconfigureBundle\Factory\ServiceConfigurationFactory + * @covers \RichId\AutoconfigureBundle\Model\ServiceConfiguration + */ +final class ServiceWithMethodTest extends TestCase +{ + public function testMethodServiceInjected(): void + { + $service = $this->getService(ServiceWithMethod::class); + self::assertInstanceOf(DecorationWithInnerServicePropertyEventListener::class, $service->service); + } + + public function testMethodParameterInjected(): void + { + $service = $this->getService(ServiceWithMethod::class); + self::assertSame('This is a test', $service->parameter); + } + + public function testMethodServicesByTagInjected(): void + { + $service = $this->getService(ServiceWithMethod::class); + + self::assertNotEmpty($service->commands); + self::assertContainsOnlyInstancesOf(Command::class, $service->commands); + } +} diff --git a/tests/Configuration/ServiceWithPropertyTest.php b/tests/Configuration/ServiceWithPropertyTest.php index 68b2470..3845add 100644 --- a/tests/Configuration/ServiceWithPropertyTest.php +++ b/tests/Configuration/ServiceWithPropertyTest.php @@ -8,6 +8,7 @@ use RichCongress\TestSuite\TestCase\TestCase; use RichId\AutoconfigureBundle\Tests\Resources\Decorator\DecorationWithInnerServicePropertyEventListener; use RichId\AutoconfigureBundle\Tests\Resources\Service\ServiceWithProperty; +use Symfony\Component\Console\Command\Command; /** * Class ServiceWithPropertyTest. @@ -38,4 +39,12 @@ public function testPropertyParameterInjected(): void $service = $this->getService(ServiceWithProperty::class); self::assertSame('This is a test', $service->parameter); } + + public function testArgumentServicesByTagInjected(): void + { + $service = $this->getService(ServiceWithProperty::class); + + self::assertNotEmpty($service->commands); + self::assertContainsOnlyInstancesOf(Command::class, $service->commands); + } } diff --git a/tests/Definition/ServiceWithArgumentTest.php b/tests/Definition/ServiceWithArgumentTest.php index ab16cb5..19a710a 100644 --- a/tests/Definition/ServiceWithArgumentTest.php +++ b/tests/Definition/ServiceWithArgumentTest.php @@ -46,4 +46,15 @@ public function testArgumentParameterInjected(): void self::assertArrayHasKey('$parameter', $arguments); self::assertSame('This is a test', $arguments['$parameter']); } + + public function testArgumentServicesByTagInjected(): void + { + $definition = self::getDefinition(ServiceWithArgument::class); + $arguments = $definition->getArguments(); + + self::assertArrayHasKey('$commands', $arguments); + self::assertIsArray($arguments['$commands']); + self::assertCount(1, $arguments['$commands']); + self::assertSame('random_command', (string) $arguments['$commands'][0]); + } } diff --git a/tests/Definition/ServiceWithMethodTest.php b/tests/Definition/ServiceWithMethodTest.php new file mode 100644 index 0000000..3be4731 --- /dev/null +++ b/tests/Definition/ServiceWithMethodTest.php @@ -0,0 +1,73 @@ + + * @copyright 2014 - 2021 Rich ID (https://www.rich-id.fr) + * + * @TestConfig("container") + * + * @covers \RichId\AutoconfigureBundle\Annotation\Method + * @covers \RichId\AutoconfigureBundle\Configurators\Partials\MethodCallAutoConfigurator + * @covers \RichId\AutoconfigureBundle\Configurators\ServiceAutoConfigurator + * @covers \RichId\AutoconfigureBundle\Factory\Basics\AbstractAnnotationServiceConfigurationFactory + * @covers \RichId\AutoconfigureBundle\Factory\Partials\MethodAnnotationServiceConfigurationFactory + * @covers \RichId\AutoconfigureBundle\Factory\ServiceConfigurationFactory + * @covers \RichId\AutoconfigureBundle\Model\ServiceConfiguration + */ +final class ServiceWithMethodTest extends DefinitionTestCase +{ + public function testMethodServiceInjected(): void + { + $definition = self::getDefinition(ServiceWithMethod::class); + $methodsCalls = $this->getMethodCalls($definition); + + self::assertArrayHasKey('setValues', $methodsCalls); + self::assertInstanceOf(Reference::class, $methodsCalls['setValues'][0]); + self::assertSame(DecorationWithInnerServicePropertyEventListener::class, (string) $methodsCalls['setValues'][0]); + } + + public function testMethodParameterInjected(): void + { + $definition = self::getDefinition(ServiceWithMethod::class); + $methodsCalls = $this->getMethodCalls($definition); + + self::assertArrayHasKey('setValues', $methodsCalls); + self::assertSame('This is a test', $methodsCalls['setValues'][1]); + } + + public function testMethodServicesByTagInjected(): void + { + $definition = self::getDefinition(ServiceWithMethod::class); + $methodsCalls = $this->getMethodCalls($definition); + + self::assertArrayHasKey('setCommands', $methodsCalls); + self::assertCount(1, $methodsCalls['setCommands']); + self::assertIsArray($methodsCalls['setCommands'][0]); + self::assertCount(1, $methodsCalls['setCommands'][0]); + self::assertSame('random_command', (string) $methodsCalls['setCommands'][0][0]); + } + + private function getMethodCalls(Definition $definition): array + { + $methodsCalls = []; + + foreach ($definition->getMethodCalls() as $data) { + $methodsCalls[$data[0]] = $data[1]; + } + + return $methodsCalls; + } +} diff --git a/tests/Definition/ServiceWithPropertyTest.php b/tests/Definition/ServiceWithPropertyTest.php index 7f4f692..8425a6b 100644 --- a/tests/Definition/ServiceWithPropertyTest.php +++ b/tests/Definition/ServiceWithPropertyTest.php @@ -46,4 +46,15 @@ public function testArgumentParameterInjected(): void self::assertArrayHasKey('parameter', $properties); self::assertSame('This is a test', $properties['parameter']); } + + public function testArgumentServicesByTagInjected(): void + { + $definition = self::getDefinition(ServiceWithProperty::class); + $properties = $definition->getProperties(); + + self::assertArrayHasKey('commands', $properties); + self::assertIsArray($properties['commands']); + self::assertCount(1, $properties['commands']); + self::assertSame('random_command', (string) $properties['commands'][0]); + } } diff --git a/tests/Resources/Service/ServiceWithArgument.php b/tests/Resources/Service/ServiceWithArgument.php index 3a29a67..1b3aa21 100644 --- a/tests/Resources/Service/ServiceWithArgument.php +++ b/tests/Resources/Service/ServiceWithArgument.php @@ -6,6 +6,7 @@ use RichId\AutoconfigureBundle\Annotation as Service; use RichId\AutoconfigureBundle\Tests\Resources\Decorator\DecorationWithInnerServicePropertyEventListener; +use Symfony\Component\Console\Command\Command; /** * Class ServiceWithArgument. @@ -15,6 +16,7 @@ * * @Service\Argument("service", DecorationWithInnerServicePropertyEventListener::class) * @Service\Argument("$parameter", "test_parameter", type="parameter") + * @Service\Argument("commands", value="console.command", type="services_by_tag") */ final class ServiceWithArgument { @@ -24,9 +26,13 @@ final class ServiceWithArgument /** @var string */ public $parameter; - public function __construct($service, $parameter) + /** @var Command[] */ + public $commands; + + public function __construct($service, $parameter, $commands) { $this->service = $service; $this->parameter = $parameter; + $this->commands = $commands; } } diff --git a/tests/Resources/Service/ServiceWithMethod.php b/tests/Resources/Service/ServiceWithMethod.php new file mode 100644 index 0000000..83fdc70 --- /dev/null +++ b/tests/Resources/Service/ServiceWithMethod.php @@ -0,0 +1,45 @@ + + * @copyright 2014 - 2021 Rich ID (https://www.rich-id.fr) + * + * @Service\Method("setValues", DecorationWithInnerServicePropertyEventListener::class) + * @Service\Method("setValues", "test_parameter", type="parameter", position=1) + * @Service\Method("setCommands", value="console.command", type="services_by_tag") + */ +final class ServiceWithMethod +{ + /** @var DecorationWithInnerServicePropertyEventListener */ + public $service; + + /** @var string */ + public $parameter; + + /** @var Command[] */ + public $commands; + + public function setValues(DecorationWithInnerServicePropertyEventListener $service, string $parameter): void + { + $this->service = $service; + $this->parameter = $parameter; + } + + /** @param Command[] $commands */ + public function setCommands(array $commands): self + { + $this->commands = $commands; + + return $this; + } +} diff --git a/tests/Resources/Service/ServiceWithProperty.php b/tests/Resources/Service/ServiceWithProperty.php index 875e425..a817190 100644 --- a/tests/Resources/Service/ServiceWithProperty.php +++ b/tests/Resources/Service/ServiceWithProperty.php @@ -6,6 +6,7 @@ use RichId\AutoconfigureBundle\Annotation as Service; use RichId\AutoconfigureBundle\Tests\Resources\Decorator\DecorationWithInnerServicePropertyEventListener; +use Symfony\Component\Console\Command\Command; /** * Class ServiceWithArgument. @@ -15,6 +16,7 @@ * * @Service\Property("$service", DecorationWithInnerServicePropertyEventListener::class) * @Service\Property("parameter", "test_parameter", type="parameter") + * @Service\Property("commands", value="console.command", type="services_by_tag") */ final class ServiceWithProperty { @@ -23,4 +25,7 @@ final class ServiceWithProperty /** @var string */ public $parameter; + + /** @var Command[] */ + public $commands; } diff --git a/tests/Resources/TestCase/DefinitionTestCase.php b/tests/Resources/TestCase/DefinitionTestCase.php index 4e527d2..45e1f54 100644 --- a/tests/Resources/TestCase/DefinitionTestCase.php +++ b/tests/Resources/TestCase/DefinitionTestCase.php @@ -15,6 +15,11 @@ protected static function getDefinition(string $class): Definition { $containerBuilder = new ContainerBuilder(); $containerBuilder->setParameter('test_parameter', 'This is a test'); + + $definition = new Definition(); + $definition->addTag('console.command'); + $containerBuilder->setDefinition('random_command', $definition); + $definition = new Definition($class); ServiceAutoConfigurator::autoconfigure($containerBuilder, $definition); From 68553c60fd45adc79fcf3ca577da78ae275ac913 Mon Sep 17 00:00:00 2001 From: Nicolas Guilloux Date: Fri, 24 Dec 2021 15:46:19 +0100 Subject: [PATCH 2/2] Increase coverage --- tests/Definition/AutoConfiguratorTest.php | 72 +++++++++++++++++++ tests/Definition/EventListenerAutoTagTest.php | 3 +- tests/Definition/ServiceWithArgumentTest.php | 16 +++-- tests/Definition/ServiceWithMethodTest.php | 16 +++-- tests/Definition/ServiceWithPropertyTest.php | 16 +++-- 5 files changed, 101 insertions(+), 22 deletions(-) create mode 100644 tests/Definition/AutoConfiguratorTest.php diff --git a/tests/Definition/AutoConfiguratorTest.php b/tests/Definition/AutoConfiguratorTest.php new file mode 100644 index 0000000..d492344 --- /dev/null +++ b/tests/Definition/AutoConfiguratorTest.php @@ -0,0 +1,72 @@ +setAbstract(true); + ServiceAutoConfigurator::autoconfigure(new ContainerBuilder(), $definition); + + self::assertEmpty($definition->getProperties()); + self::assertEmpty($definition->getArguments()); + self::assertEmpty($definition->getMethodCalls()); + } + + public function testSkippedSynthetic(): void + { + $definition = new Definition(); + $definition->setSynthetic(true); + ServiceAutoConfigurator::autoconfigure(new ContainerBuilder(), $definition); + + self::assertEmpty($definition->getProperties()); + self::assertEmpty($definition->getArguments()); + self::assertEmpty($definition->getMethodCalls()); + } + + public function testSkippedClass(): void + { + $definition = new Definition(); + $definition->setClass(Psr16Cache::class); + ServiceAutoConfigurator::autoconfigure(new ContainerBuilder(), $definition); + + self::assertEmpty($definition->getProperties()); + self::assertEmpty($definition->getArguments()); + self::assertEmpty($definition->getMethodCalls()); + } + + public function testUnsupportedType(): void + { + $autoConfigurator = new ArgumentAutoConfigurator(); + $reflectionClass = new \ReflectionClass($this); + $configuration = new ServiceConfiguration($reflectionClass); + $configuration->setArgument('test', [ + 'type' => 'unsupported', + 'value' => 'test', + ]); + + $this->expectException(\UnexpectedValueException::class); + $this->expectErrorMessage('The type used a service configuration is wrong.'); + + $autoConfigurator->autoconfigure( + new ContainerBuilder(), + new Definition(), + $configuration + ); + } +} diff --git a/tests/Definition/EventListenerAutoTagTest.php b/tests/Definition/EventListenerAutoTagTest.php index fc6c3c0..02bdd2b 100644 --- a/tests/Definition/EventListenerAutoTagTest.php +++ b/tests/Definition/EventListenerAutoTagTest.php @@ -21,10 +21,11 @@ * @TestConfig("container") * * @covers \RichId\AutoconfigureBundle\Annotation\EventListener - * @covers \RichId\AutoconfigureBundle\Model\ServiceConfiguration + * @covers \RichId\AutoconfigureBundle\Configurators\Partials\TagAutoConfigurator * @covers \RichId\AutoconfigureBundle\Factory\Partials\EventListenerServiceConfigurationFactory * @covers \RichId\AutoconfigureBundle\Factory\Partials\TagAnnotationServiceConfigurationFactory * @covers \RichId\AutoconfigureBundle\Factory\ServiceConfigurationFactory + * @covers \RichId\AutoconfigureBundle\Model\ServiceConfiguration */ final class EventListenerAutoTagTest extends DefinitionTestCase { diff --git a/tests/Definition/ServiceWithArgumentTest.php b/tests/Definition/ServiceWithArgumentTest.php index 19a710a..8338296 100644 --- a/tests/Definition/ServiceWithArgumentTest.php +++ b/tests/Definition/ServiceWithArgumentTest.php @@ -18,13 +18,15 @@ * * @TestConfig("container") * - * @covers \RichId\AutoconfigureBundle\Annotation\Argument - * @covers \RichId\AutoconfigureBundle\Configurators\Partials\ArgumentAutoConfigurator - * @covers \RichId\AutoconfigureBundle\Configurators\ServiceAutoConfigurator - * @covers \RichId\AutoconfigureBundle\Factory\Basics\AbstractAnnotationServiceConfigurationFactory - * @covers \RichId\AutoconfigureBundle\Factory\Partials\ArgumentAnnotationServiceConfigurationFactory - * @covers \RichId\AutoconfigureBundle\Factory\ServiceConfigurationFactory - * @covers \RichId\AutoconfigureBundle\Model\ServiceConfiguration + * @covers \RichId\AutoconfigureBundle\Annotation\AbstractServiceInjectionAnnotation + * @covers \RichId\AutoconfigureBundle\Annotation\Argument + * @covers \RichId\AutoconfigureBundle\Configurators\Partials\AbstractServiceInjectionAutoConfigurator + * @covers \RichId\AutoconfigureBundle\Configurators\Partials\ArgumentAutoConfigurator + * @covers \RichId\AutoconfigureBundle\Configurators\ServiceAutoConfigurator + * @covers \RichId\AutoconfigureBundle\Factory\Basics\AbstractAnnotationServiceConfigurationFactory + * @covers \RichId\AutoconfigureBundle\Factory\Partials\ArgumentAnnotationServiceConfigurationFactory + * @covers \RichId\AutoconfigureBundle\Factory\ServiceConfigurationFactory + * @covers \RichId\AutoconfigureBundle\Model\ServiceConfiguration */ final class ServiceWithArgumentTest extends DefinitionTestCase { diff --git a/tests/Definition/ServiceWithMethodTest.php b/tests/Definition/ServiceWithMethodTest.php index 3be4731..197aaf3 100644 --- a/tests/Definition/ServiceWithMethodTest.php +++ b/tests/Definition/ServiceWithMethodTest.php @@ -19,13 +19,15 @@ * * @TestConfig("container") * - * @covers \RichId\AutoconfigureBundle\Annotation\Method - * @covers \RichId\AutoconfigureBundle\Configurators\Partials\MethodCallAutoConfigurator - * @covers \RichId\AutoconfigureBundle\Configurators\ServiceAutoConfigurator - * @covers \RichId\AutoconfigureBundle\Factory\Basics\AbstractAnnotationServiceConfigurationFactory - * @covers \RichId\AutoconfigureBundle\Factory\Partials\MethodAnnotationServiceConfigurationFactory - * @covers \RichId\AutoconfigureBundle\Factory\ServiceConfigurationFactory - * @covers \RichId\AutoconfigureBundle\Model\ServiceConfiguration + * @covers \RichId\AutoconfigureBundle\Annotation\AbstractServiceInjectionAnnotation + * @covers \RichId\AutoconfigureBundle\Annotation\Method + * @covers \RichId\AutoconfigureBundle\Configurators\Partials\AbstractServiceInjectionAutoConfigurator + * @covers \RichId\AutoconfigureBundle\Configurators\Partials\MethodCallAutoConfigurator + * @covers \RichId\AutoconfigureBundle\Configurators\ServiceAutoConfigurator + * @covers \RichId\AutoconfigureBundle\Factory\Basics\AbstractAnnotationServiceConfigurationFactory + * @covers \RichId\AutoconfigureBundle\Factory\Partials\MethodAnnotationServiceConfigurationFactory + * @covers \RichId\AutoconfigureBundle\Factory\ServiceConfigurationFactory + * @covers \RichId\AutoconfigureBundle\Model\ServiceConfiguration */ final class ServiceWithMethodTest extends DefinitionTestCase { diff --git a/tests/Definition/ServiceWithPropertyTest.php b/tests/Definition/ServiceWithPropertyTest.php index 8425a6b..3b050f6 100644 --- a/tests/Definition/ServiceWithPropertyTest.php +++ b/tests/Definition/ServiceWithPropertyTest.php @@ -18,13 +18,15 @@ * * @TestConfig("container") * - * @covers \RichId\AutoconfigureBundle\Annotation\Property - * @covers \RichId\AutoconfigureBundle\Configurators\Partials\PropertyAutoConfigurator - * @covers \RichId\AutoconfigureBundle\Configurators\ServiceAutoConfigurator - * @covers \RichId\AutoconfigureBundle\Factory\Basics\AbstractAnnotationServiceConfigurationFactory - * @covers \RichId\AutoconfigureBundle\Factory\Partials\PropertyAnnotationServiceConfigurationFactory - * @covers \RichId\AutoconfigureBundle\Factory\ServiceConfigurationFactory - * @covers \RichId\AutoconfigureBundle\Model\ServiceConfiguration + * @covers \RichId\AutoconfigureBundle\Annotation\AbstractServiceInjectionAnnotation + * @covers \RichId\AutoconfigureBundle\Annotation\Property + * @covers \RichId\AutoconfigureBundle\Configurators\Partials\AbstractServiceInjectionAutoConfigurator + * @covers \RichId\AutoconfigureBundle\Configurators\Partials\PropertyAutoConfigurator + * @covers \RichId\AutoconfigureBundle\Configurators\ServiceAutoConfigurator + * @covers \RichId\AutoconfigureBundle\Factory\Basics\AbstractAnnotationServiceConfigurationFactory + * @covers \RichId\AutoconfigureBundle\Factory\Partials\PropertyAnnotationServiceConfigurationFactory + * @covers \RichId\AutoconfigureBundle\Factory\ServiceConfigurationFactory + * @covers \RichId\AutoconfigureBundle\Model\ServiceConfiguration */ final class ServiceWithPropertyTest extends DefinitionTestCase {