From 9a386c05431a88cf1af39e57c5720c06b7f35679 Mon Sep 17 00:00:00 2001 From: Michael Diodone Date: Tue, 1 Feb 2022 16:26:31 +0100 Subject: [PATCH] Support injection into typed properties --- .../injektor/DependencyInjectionContainer.php | 25 ++++++++++----- src/rg/injektor/SimpleAnnotationReader.php | 2 -- src/rg/injektor/generators/FileGenerator.php | 2 +- .../injektor/generators/InjectionProperty.php | 2 +- .../DependencyInjectionContainerTest.php | 21 +++++++++++++ ...ryOnlyDependencyInjectionContainerTest.php | 20 +++++++++--- test/rg/injektor/test_classes_php74.php | 31 +++++++++++++++++++ 7 files changed, 87 insertions(+), 16 deletions(-) create mode 100644 test/rg/injektor/test_classes_php74.php diff --git a/src/rg/injektor/DependencyInjectionContainer.php b/src/rg/injektor/DependencyInjectionContainer.php index b73bb9d..207bed6 100644 --- a/src/rg/injektor/DependencyInjectionContainer.php +++ b/src/rg/injektor/DependencyInjectionContainer.php @@ -15,7 +15,10 @@ use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy; use ProxyManager\Proxy\LazyLoadingInterface; use Psr\Log\LoggerInterface; +use ReflectionNamedType; +use ReflectionProperty; use rg\injektor\annotations\Named; +use const PHP_VERSION_ID; /** * @implementedBy rg\injektor\FactoryDependencyInjectionContainer @@ -400,9 +403,9 @@ public function getInjectableProperties($classReflection) { * @throws InjectionException */ private function injectProperty($property, $instance) { - $fullClassName = $this->getClassFromVarTypeHint($property->getDocComment()); + $fullClassName = $this->getClassFromProperty($property); if (!$fullClassName) { - throw new InjectionException('Expected tag @var not found in doc comment.'); + throw new InjectionException('Expected tag @var not found in doc comment. A typed property was also not found.'); } $fullClassName = $this->getFullClassNameBecauseOfImports($property, $fullClassName); @@ -454,12 +457,20 @@ public function getFullClassNameBecauseOfImports($property, $fullClassName) { } /** - * @param string $docComment - * @return string - * @throws InjectionException + * @param ReflectionProperty $property + * @return string|null */ - public function getClassFromVarTypeHint($docComment) { - return $this->annotationReader->getClassFromVarTypeHint($docComment); + public function getClassFromProperty($property) { + $fullClassName = $this->annotationReader->getClassFromVarTypeHint($property->getDocComment()); + + if (!$fullClassName && PHP_VERSION_ID >= 70400) { + $namedType = $property->getType(); + if ($namedType instanceof ReflectionNamedType && $namedType->getName()) { + $fullClassName = '\\' . $namedType->getName(); + } + } + + return $fullClassName; } /** diff --git a/src/rg/injektor/SimpleAnnotationReader.php b/src/rg/injektor/SimpleAnnotationReader.php index 11e7a15..e492170 100644 --- a/src/rg/injektor/SimpleAnnotationReader.php +++ b/src/rg/injektor/SimpleAnnotationReader.php @@ -14,7 +14,6 @@ class SimpleAnnotationReader { /** * @param string $docComment * @return string - * @throws InjectionException */ public function getClassFromVarTypeHint($docComment) { return $this->getClassFromTypeHint($docComment, '@var'); @@ -24,7 +23,6 @@ public function getClassFromVarTypeHint($docComment) { * @param string $docComment * @param string $tag * @return string mixed - * @throws InjectionException */ private function getClassFromTypeHint($docComment, $tag) { $matches = array(); diff --git a/src/rg/injektor/generators/FileGenerator.php b/src/rg/injektor/generators/FileGenerator.php index f6fce95..a2e1b6f 100644 --- a/src/rg/injektor/generators/FileGenerator.php +++ b/src/rg/injektor/generators/FileGenerator.php @@ -376,7 +376,7 @@ private function injectProperties(array $classConfig, \ReflectionClass $classRef $this->injectableProperties = $this->dic->getInjectableProperties($classReflection); foreach ($this->injectableProperties as $key => $injectableProperty) { /** @var \ReflectionProperty $injectableProperty */ - $propertyClass = $this->dic->getClassFromVarTypeHint($injectableProperty->getDocComment()); + $propertyClass = $this->dic->getClassFromProperty($injectableProperty); if (!$propertyClass) { unset($this->injectableProperties[$key]); continue; diff --git a/src/rg/injektor/generators/InjectionProperty.php b/src/rg/injektor/generators/InjectionProperty.php index 8237b02..7805320 100644 --- a/src/rg/injektor/generators/InjectionProperty.php +++ b/src/rg/injektor/generators/InjectionProperty.php @@ -46,7 +46,7 @@ protected function hasClass() { } protected function getClass() { - return $this->dic->getFullClassNameBecauseOfImports($this->property, $this->dic->getClassFromVarTypeHint($this->docComment)); + return $this->dic->getFullClassNameBecauseOfImports($this->property, $this->dic->getClassFromProperty($this->property)); } public function getProcessingBody() { diff --git a/test/rg/injektor/DependencyInjectionContainerTest.php b/test/rg/injektor/DependencyInjectionContainerTest.php index 042d2cf..994e7a1 100644 --- a/test/rg/injektor/DependencyInjectionContainerTest.php +++ b/test/rg/injektor/DependencyInjectionContainerTest.php @@ -9,6 +9,8 @@ */ namespace rg\injektor; +use const PHP_VERSION_ID; + include_once 'test_classes.php'; class DependencyInjectionContainerTest extends \PHPUnit\Framework\TestCase { @@ -833,6 +835,25 @@ public function testPropertyInjectionWithUseStatement() { $this->assertInstanceOf('rg\injektor\DICTestClassThatAlsoExistsInPublicNamespace', $instance->dependencyWithOtherClassInPublicNamespace); } + public function test_getInstanceOfClass_givenClassWithTypedProperties_injectsCorrectClassesIntoProperties() { + if (PHP_VERSION_ID < 70400) { + $this->markTestSkipped('Needs PHP 7.4 or higher'); + } + include_once 'test_classes_php74.php'; + + $config = new Configuration(null, __DIR__ . '/_factories'); + + $dic = $this->getContainer($config); + + $instance = $dic->getInstanceOfClass('rg\injektor\DICTestClassWithTypedProperties'); + + $this->assertInstanceOf('rg\injektor\DICTestClassWithTypedProperties', $instance); + + $this->assertInstanceOf('rg\injektor\DICTestClassOne', $instance->one); + $this->assertInstanceOf('rg\injektor\DICTestClassTwo', $instance->two); + $this->assertInstanceOf('rg\injektor\DICTestClassThree', $instance->three); + } + public function testClearDoesNotThrow() { $config = new Configuration(null, __DIR__ . '/_factories'); $dic = $this->getContainer($config); diff --git a/test/rg/injektor/FactoryOnlyDependencyInjectionContainerTest.php b/test/rg/injektor/FactoryOnlyDependencyInjectionContainerTest.php index f38aef9..288bcdf 100644 --- a/test/rg/injektor/FactoryOnlyDependencyInjectionContainerTest.php +++ b/test/rg/injektor/FactoryOnlyDependencyInjectionContainerTest.php @@ -9,7 +9,9 @@ */ namespace rg\injektor; +use Laminas\Code\Reflection\FileReflection; use rg\injektor\generators\WritingFactoryGenerator; +use const PHP_VERSION_ID; require_once 'DependencyInjectionContainerTest.php'; @@ -30,11 +32,10 @@ public function setUp(): void { public function getContainer(Configuration $config) { $generator = new WritingFactoryGenerator($config, __DIR__ . '/_factories'); - $fileReflection = new \Laminas\Code\Reflection\FileReflection(__DIR__ . '/test_classes.php'); - $classes = $fileReflection->getClasses(); - foreach ($classes as $class) { - /** @var \ReflectionClass $class */ - $generator->processFileForClass($class->getName()); + $this->processClassesOfFile(__DIR__ . '/test_classes.php', $generator); + + if (PHP_VERSION_ID >= 70400) { + $this->processClassesOfFile(__DIR__ . '/test_classes_php74.php', $generator); } return new FactoryOnlyDependencyInjectionContainer($config); @@ -47,4 +48,13 @@ public function tearDown(): void { public static function tearDownAfterClass(): void { WritingFactoryGenerator::cleanUpGenerationDirectory(__DIR__ . '/_factories'); } + + private function processClassesOfFile(string $fileName, WritingFactoryGenerator $generator): void + { + $fileReflection = new FileReflection($fileName); + $classes = $fileReflection->getClasses(); + foreach ($classes as $class) { + $generator->processFileForClass($class->getName()); + } + } } diff --git a/test/rg/injektor/test_classes_php74.php b/test/rg/injektor/test_classes_php74.php new file mode 100644 index 0000000..dc24e36 --- /dev/null +++ b/test/rg/injektor/test_classes_php74.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace rg\injektor { + + require_once 'test_classes.php'; + + class DICTestClassWithTypedProperties { + + /** + * @inject + */ + public DICTestClassOne $one; + + /** + * @inject + */ + public \rg\injektor\DICTestClassTwo $two; + + /** + * @inject + */ + public ?DICTestClassThree $three; + } +}