From 95f8c1db04b3cc96d5f175b449d7fdaaf25a4d79 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Fri, 17 Nov 2023 15:33:13 +0100 Subject: [PATCH] [PropertyInfo] Make `PhpDocExtractor::getDocBlock()` public --- .../Component/PropertyInfo/CHANGELOG.md | 5 +++ .../Extractor/PhpDocExtractor.php | 18 +++++++--- .../PropertyDocBlockExtractorInterface.php | 36 +++++++++++++++++++ .../Tests/Extractor/PhpDocExtractorTest.php | 24 ++++++++++--- .../Extractor/ReflectionExtractorTest.php | 3 ++ .../PropertyInfo/Tests/Fixtures/Dummy.php | 2 ++ 6 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 src/Symfony/Component/PropertyInfo/PropertyDocBlockExtractorInterface.php diff --git a/src/Symfony/Component/PropertyInfo/CHANGELOG.md b/src/Symfony/Component/PropertyInfo/CHANGELOG.md index ce7f220ce1dc1..6e0a2ff449dec 100644 --- a/src/Symfony/Component/PropertyInfo/CHANGELOG.md +++ b/src/Symfony/Component/PropertyInfo/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +7.1 +--- + + * Introduce `PropertyDocBlockExtractorInterface` to extract a property's doc block + 6.4 --- diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php index e329e9c0d2804..ab056e12b0eba 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php @@ -18,6 +18,7 @@ use phpDocumentor\Reflection\Types\Context; use phpDocumentor\Reflection\Types\ContextFactory; use Symfony\Component\PropertyInfo\PropertyDescriptionExtractorInterface; +use Symfony\Component\PropertyInfo\PropertyDocBlockExtractorInterface; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; use Symfony\Component\PropertyInfo\Type; use Symfony\Component\PropertyInfo\Util\PhpDocTypeHelper; @@ -29,7 +30,7 @@ * * @final */ -class PhpDocExtractor implements PropertyDescriptionExtractorInterface, PropertyTypeExtractorInterface, ConstructorArgumentTypeExtractorInterface +class PhpDocExtractor implements PropertyDescriptionExtractorInterface, PropertyTypeExtractorInterface, ConstructorArgumentTypeExtractorInterface, PropertyDocBlockExtractorInterface { public const PROPERTY = 0; public const ACCESSOR = 1; @@ -74,7 +75,7 @@ public function __construct(DocBlockFactoryInterface $docBlockFactory = null, ar public function getShortDescription(string $class, string $property, array $context = []): ?string { /** @var $docBlock DocBlock */ - [$docBlock] = $this->getDocBlock($class, $property); + [$docBlock] = $this->findDocBlock($class, $property); if (!$docBlock) { return null; } @@ -101,7 +102,7 @@ public function getShortDescription(string $class, string $property, array $cont public function getLongDescription(string $class, string $property, array $context = []): ?string { /** @var $docBlock DocBlock */ - [$docBlock] = $this->getDocBlock($class, $property); + [$docBlock] = $this->findDocBlock($class, $property); if (!$docBlock) { return null; } @@ -114,7 +115,7 @@ public function getLongDescription(string $class, string $property, array $conte public function getTypes(string $class, string $property, array $context = []): ?array { /** @var $docBlock DocBlock */ - [$docBlock, $source, $prefix] = $this->getDocBlock($class, $property); + [$docBlock, $source, $prefix] = $this->findDocBlock($class, $property); if (!$docBlock) { return null; } @@ -187,6 +188,13 @@ public function getTypesFromConstructor(string $class, string $property): ?array return array_merge([], ...$types); } + public function getDocBlock(string $class, string $property): ?DocBlock + { + $output = $this->findDocBlock($class, $property); + + return $output[0]; + } + private function getDocBlockFromConstructor(string $class, string $property): ?DocBlock { try { @@ -219,7 +227,7 @@ private function filterDocBlockParams(DocBlock $docBlock, string $allowedParam): /** * @return array{DocBlock|null, int|null, string|null} */ - private function getDocBlock(string $class, string $property): array + private function findDocBlock(string $class, string $property): array { $propertyHash = sprintf('%s::%s', $class, $property); diff --git a/src/Symfony/Component/PropertyInfo/PropertyDocBlockExtractorInterface.php b/src/Symfony/Component/PropertyInfo/PropertyDocBlockExtractorInterface.php new file mode 100644 index 0000000000000..4a51d7b79cfb5 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/PropertyDocBlockExtractorInterface.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo; + +use phpDocumentor\Reflection\DocBlock; + +/** + * Extract a property's doc block. + * + * A property's doc block may be located on a constructor promoted argument, on + * the property or on a mutator for that property. + * + * @author Tobias Nyholm + */ +interface PropertyDocBlockExtractorInterface +{ + /** + * Gets the first available doc block for a property. It finds the doc block + * by the following priority: + * - constructor promoted argument + * - the class property + * - a mutator method for that property + * + * If no doc block is found, it will return null. + */ + public function getDocBlock(string $class, string $property): ?DocBlock; +} diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php index ecb9f57079a1a..db39180b0a899 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\PropertyInfo\Tests\Extractor; +use phpDocumentor\Reflection\DocBlock; use PHPUnit\Framework\TestCase; use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; use Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy; @@ -38,9 +39,22 @@ protected function setUp(): void */ public function testExtract($property, ?array $type, $shortDescription, $longDescription) { - $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property)); - $this->assertSame($shortDescription, $this->extractor->getShortDescription('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property)); - $this->assertSame($longDescription, $this->extractor->getLongDescription('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property)); + $this->assertEquals($type, $this->extractor->getTypes(Dummy::class, $property)); + $this->assertSame($shortDescription, $this->extractor->getShortDescription(Dummy::class, $property)); + $this->assertSame($longDescription, $this->extractor->getLongDescription(Dummy::class, $property)); + } + + public function testGetDocBlock() + { + $docBlock = $this->extractor->getDocBlock(Dummy::class, 'g'); + $this->assertInstanceOf(DocBlock::class, $docBlock); + $this->assertSame('Nullable array.', $docBlock->getSummary()); + + $docBlock = $this->extractor->getDocBlock(Dummy::class, 'noDocBlock;'); + $this->assertNull($docBlock); + + $docBlock = $this->extractor->getDocBlock(Dummy::class, 'notAvailable'); + $this->assertNull($docBlock); } public function testParamTagTypeIsOmitted() @@ -75,7 +89,7 @@ public function testExtractTypesWithNoPrefixes($property, array $type = null) { $noPrefixExtractor = new PhpDocExtractor(null, [], [], []); - $this->assertEquals($type, $noPrefixExtractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property)); + $this->assertEquals($type, $noPrefixExtractor->getTypes(Dummy::class, $property)); } public static function typesProvider() @@ -197,7 +211,7 @@ public function testExtractTypesWithCustomPrefixes($property, array $type = null { $customExtractor = new PhpDocExtractor(null, ['add', 'remove'], ['is', 'can']); - $this->assertEquals($type, $customExtractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property)); + $this->assertEquals($type, $customExtractor->getTypes(Dummy::class, $property)); } public static function typesWithCustomPrefixesProvider() diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php index 39bcec722c752..1a312921671e3 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php @@ -66,6 +66,7 @@ public function testGetProperties() 'arrayWithKeys', 'arrayWithKeysAndComplexValue', 'arrayOfMixed', + 'noDocBlock', 'listOfStrings', 'parentAnnotation', 'foo', @@ -130,6 +131,7 @@ public function testGetPropertiesWithCustomPrefixes() 'arrayWithKeys', 'arrayWithKeysAndComplexValue', 'arrayOfMixed', + 'noDocBlock', 'listOfStrings', 'parentAnnotation', 'foo', @@ -183,6 +185,7 @@ public function testGetPropertiesWithNoPrefixes() 'arrayWithKeys', 'arrayWithKeysAndComplexValue', 'arrayOfMixed', + 'noDocBlock', 'listOfStrings', 'parentAnnotation', 'foo', diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php index ec3bb8da4e200..68b2e1d9928cb 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php @@ -155,6 +155,8 @@ class Dummy extends ParentDummy */ public $arrayOfMixed; + public $noDocBlock; + /** * @var list */