bug #36975 [PropertyInfo] Make PhpDocExtractor compatible with phpDocumentor v5 (DerManoMann)

This PR was merged into the 4.4 branch.

Discussion
----------

[PropertyInfo] Make PhpDocExtractor compatible with phpDocumentor v5

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #36049
| License       | MIT
| Doc PR        | N/A

Version 5 of phpDocumentor introduced some changes to the `getTagsByName()` method that break the `PhpDocExtractor`.

More specific, it now returns an instance of `InvalidTag` instead of `null` when parsing an invalid tag.

Commits
-------

b1f8e5a80a Make PhpDocExtractor compatible with phpDocumentor v5
This commit is contained in:
Fabien Potencier 2020-06-15 07:20:14 +02:00
commit bb8e66bc5f
5 changed files with 92 additions and 7 deletions

View File

@ -121,7 +121,7 @@
"egulias/email-validator": "~1.2,>=1.2.8|~2.0",
"symfony/phpunit-bridge": "^5.0.8",
"symfony/security-acl": "~2.8|~3.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
"twig/cssinliner-extra": "^2.12",
"twig/inky-extra": "^2.12",
"twig/markdown-extra": "^2.12"

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\PropertyInfo\Extractor;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
use phpDocumentor\Reflection\DocBlockFactory;
use phpDocumentor\Reflection\DocBlockFactoryInterface;
use phpDocumentor\Reflection\Types\Context;
@ -88,10 +89,12 @@ class PhpDocExtractor implements PropertyDescriptionExtractorInterface, Property
}
foreach ($docBlock->getTagsByName('var') as $var) {
$varDescription = $var->getDescription()->render();
if ($var && !$var instanceof InvalidTag) {
$varDescription = $var->getDescription()->render();
if (!empty($varDescription)) {
return $varDescription;
if (!empty($varDescription)) {
return $varDescription;
}
}
}
@ -142,7 +145,7 @@ class PhpDocExtractor implements PropertyDescriptionExtractorInterface, Property
$types = [];
/** @var DocBlock\Tags\Var_|DocBlock\Tags\Return_|DocBlock\Tags\Param $tag */
foreach ($docBlock->getTagsByName($tag) as $tag) {
if ($tag && null !== $tag->getType()) {
if ($tag && !$tag instanceof InvalidTag && null !== $tag->getType()) {
$types = array_merge($types, $this->phpDocTypeHelper->getTypes($tag->getType()));
}
}

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\PropertyInfo\Tests\Extractor;
use phpDocumentor\Reflection\DocBlock\StandardTagFactory;
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
use phpDocumentor\Reflection\Types\Collection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
@ -46,6 +48,26 @@ class PhpDocExtractorTest extends TestCase
$this->assertNull($this->extractor->getTypes(OmittedParamTagTypeDocBlock::class, 'omittedType'));
}
public function invalidTypesProvider()
{
return [
'pub' => ['pub', null, null],
'stat' => ['stat', null, null],
'foo' => ['foo', $this->isPhpDocumentorV5() ? 'Foo.' : null, null],
'bar' => ['bar', $this->isPhpDocumentorV5() ? 'Bar.' : null, null],
];
}
/**
* @dataProvider invalidTypesProvider
*/
public function testInvalid($property, $shortDescription, $longDescription)
{
$this->assertNull($this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\InvalidDummy', $property));
$this->assertSame($shortDescription, $this->extractor->getShortDescription('Symfony\Component\PropertyInfo\Tests\Fixtures\InvalidDummy', $property));
$this->assertSame($longDescription, $this->extractor->getLongDescription('Symfony\Component\PropertyInfo\Tests\Fixtures\InvalidDummy', $property));
}
/**
* @dataProvider typesWithNoPrefixesProvider
*/
@ -94,7 +116,7 @@ class PhpDocExtractorTest extends TestCase
['donotexist', null, null, null],
['staticGetter', null, null, null],
['staticSetter', null, null, null],
['emptyVar', null, null, null],
['emptyVar', null, $this->isPhpDocumentorV5() ? 'This should not be removed.' : null, null],
];
}
@ -250,6 +272,16 @@ class PhpDocExtractorTest extends TestCase
{
$this->assertEquals($types, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\DockBlockFallback', $property));
}
protected function isPhpDocumentorV5()
{
if (class_exists(InvalidTag::class)) {
return true;
}
return (new \ReflectionMethod(StandardTagFactory::class, 'create'))
->hasReturnType();
}
}
class EmptyDocBlock

View File

@ -0,0 +1,50 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\PropertyInfo\Tests\Fixtures;
/**
* @author Martin Rademacher <mano@radebatz.net>
*/
class InvalidDummy
{
/**
* @var
*/
public $pub;
/**
* @return
*/
public static function getStat()
{
return 'stat';
}
/**
* Foo.
*
* @param
*/
public function setFoo($foo)
{
}
/**
* Bar.
*
* @return
*/
public function getBar()
{
return 'bar';
}
}

View File

@ -30,7 +30,7 @@
"symfony/serializer": "^3.4|^4.0|^5.0",
"symfony/cache": "^3.4|^4.0|^5.0",
"symfony/dependency-injection": "^3.4|^4.0|^5.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
"doctrine/annotations": "~1.7"
},
"conflict": {