10BC0 Merge branch '8.0' into 8.1 · symfony/symfony@c81fce4 · GitHub
[go: up one dir, main page]

Skip to content

Commit c81fce4

Browse files
Merge branch '8.0' into 8.1
* 8.0: fix merge [PropertyInfo] Conflict with phpdocumentor/reflection-docblock >= 6 [PropertyInfo] Fix resolution of self/parent types in inherited DocBlocks [PropertyInfo] Fix resolution of self/parent types in inherited DocBlocks chore(translation): remove state needs-review-translation fixes #59413
2 parents 5568a77 + 76f665a commit c81fce4

File tree

10 files changed

+214
-61
lines changed

10 files changed

+214
-61
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@
177177
"doctrine/orm": "<3.4",
178178
"egulias/email-validator": "~3.0.0",
179179
"masterminds/html5": "<2.6",
180-
"phpdocumentor/reflection-docblock": "<5.2",
180+
"phpdocumentor/reflection-docblock": "<5.2|>=6",
181181
"phpdocumentor/type-resolver": "<1.5.1",
182182
"phpunit/phpunit": "<7.5|9.1.2",
183183
"symfony/flex": "<2.10"

src/Symfony/Bridge/Twig/composer.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"require-dev": {
2424
"egulias/email-validator": "^2.1.10|^3|^4",
2525
"league/html-to-markdown": "^5.0",
26-
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
26+
"phpdocumentor/reflection-docblock": "^5.2",
2727
"symfony/asset": "^7.4|^8.0",
2828
"symfony/asset-mapper": "^7.4|^8.0",
2929
"symfony/console": "^7.4|^8.0",
@@ -56,8 +56,8 @@
5656
"twig/markdown-extra": "^3"
5757
},
5858
"conflict": {
59-
"phpdocumentor/reflection-docblock": "<3.2.2",
60-
"phpdocumentor/type-resolver": "<1.4.0",
59+
"phpdocumentor/reflection-docblock": "<5.2|>=6",
60+
"phpdocumentor/type-resolver": "<1.5.1",
6161
"symfony/form": "<7.4.4|>8.0,<8.0.4"
6262
},
6363
"autoload": {

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"require-dev": {
3737
"doctrine/persistence": "^1.3|^2|^3",
3838
"dragonmantank/cron-expression": "^3.1",
39-
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
39+
"phpdocumentor/reflection-docblock": "^5.2",
4040
"phpstan/phpdoc-parser": "^1.0|^2.0",
4141
"seld/jsonlint": "^1.10",
4242
"symfony/asset": "^7.4|^8.0",
@@ -81,8 +81,8 @@
8181
},
8282
"conflict": {
8383
"doctrine/persistence": "<1.3",
84-
"phpdocumentor/reflection-docblock": "<3.2.2",
85-
"phpdocumentor/type-resolver": "<1.4.0",
84+
"phpdocumentor/reflection-docblock": "<5.2|>=6",
85+
"phpdocumentor/type-resolver": "<1.5.1",
8686
"symfony/console": "<7.4",
8787
"symfony/form": "<7.4",
8888
"symfony/json-streamer": "<7.4",

src/Symfony/Component/Mime/composer.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"require-dev": {
2424
"egulias/email-validator": "^2.1.10|^3.1|^4",
2525
"league/html-to-markdown": "^5.0",
26-
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
26+
"phpdocumentor/reflection-docblock": "^5.2",
2727
"symfony/dependency-injection": "^7.4|^8.0",
2828
"symfony/process": "^7.4|^8.0",
2929
"symfony/property-access": "^7.4|^8.0",
@@ -32,8 +32,8 @@
3232
},
3333
"conflict": {
3434
"egulias/email-validator": "~3.0.0",
35-
"phpdocumentor/reflection-docblock": "<3.2.2",
36-
"phpdocumentor/type-resolver": "<1.4.0"
35+
"phpdocumentor/reflection-docblock": "<5.2|>=6",
36+
"phpdocumentor/type-resolver": "<1.5.1"
3737
},
3838
"autoload": {
3939
"psr-4": { "Symfony\\Component\\Mime\\": "" },

src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
namespace Symfony\Component\PropertyInfo\Extractor;
1313

1414
use phpDocumentor\Reflection\DocBlock;
15-
use phpDocumentor\Reflection\DocBlock\Tags\Factory\StaticMethod;
16-
use phpDocumentor\Reflection\DocBlock\Tags\Generic;
1715
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
1816
use phpDocumentor\Reflection\DocBlockFactory;
1917
use phpDocumentor\Reflection\DocBlockFactoryInterface;
@@ -42,7 +40,7 @@ class PhpDocExtractor implements PropertyDescriptionExtractorInterface, Property
4240
public const MUTATOR = 2;
4341

4442
/**
45-
* @var array<string, array{DocBlock|null, int|null, string|null}>
43+
* @var array<string, array{DocBlock|null, int|null, string|null, string|null}>
4644
*/
4745
private array $docBlocks = [];
4846

@@ -70,10 +68,6 @@ public function __construct(?DocBlockFactoryInterface $docBlockFactory = null, ?
7068
throw new \LogicException(\sprintf('Unable to use the "%s" class as the "phpdocumentor/reflection-docblock" package is not installed. Try running composer require "phpdocumentor/reflection-docblock".', __CLASS__));
7169
}
7270

73-
if (!is_subclass_of(Generic::class, StaticMethod::class)) {
74-
throw new \LogicException('symfony/property-info v6 does not support phpdocumentor/reflection-docblock v6. Please stick to ^5.2 in your composer.json file.');
75-
}
76-
7771
$this->docBlockFactory = $docBlockFactory ?: DocBlockFactory::createInstance();
7872
$this->contextFactory = new ContextFactory();
7973
$this->typeContextFactory = new TypeContextFactory();
@@ -124,7 +118,7 @@ public function getLongDescription(string $class, string $property, array $conte
124118
public function getType(string $class, string $property, array $context = []): ?Type
125119
{
126120
/** @var DocBlock $docBlock */
127-
[$docBlock, $source, $prefix] = $this->findDocBlock($class, $property);
121+
[$docBlock, $source, $prefix, $declaringClass] = $this->findDocBlock($class, $property);
128122
if (!$docBlock) {
129123
return null;
130124
}
@@ -136,7 +130,7 @@ public function getType(string $class, string $property, array $context = []): ?
136130
};
137131

138132
$types = [];
139-
$typeContext = $this->typeContextFactory->createFromClassName($class);
133+
$typeContext = $this->typeContextFactory->createFromClassName($class, $declaringClass ?? $class);
140134

141135
/** @var DocBlock\Tags\Var_|DocBlock\Tags\Return_|DocBlock\Tags\Param $tag */
142136
foreach ($docBlock->getTagsByName($tag) as $tag) {
@@ -236,7 +230,7 @@ private function filterDocBlockParams(DocBlock $docBlock, string $allowedParam):
236230
}
237231

238232
/**
239-
* @return array{DocBlock|null, int|null, string|null}
233+
* @return array{DocBlock|null, int|null, string|null, string|null}
240234
*/
241235
private function findDocBlock(string $class, string $property): array
242236
{
@@ -256,30 +250,35 @@ private function findDocBlock(string $class, string $property): array
256250

257251
switch (true) {
258252
case $reflectionProperty?->isPromoted() && $docBlock = $this->getDocBlockFromConstructor($class, $property):
259-
$data = [$docBlock, self::MUTATOR, null];
253+
$data = [$docBlock, self::MUTATOR, null, $reflectionProperty->getDeclaringClass()->getName()];
260254
break;
261255

262-
case $docBlock = $this->getDocBlockFromProperty($class, $property):
263-
$data = [$docBlock, self::PROPERTY, null];
256+
case [$docBlock, $declaringClass] = $this->getDocBlockFromProperty($class, $property):
257+
$data = [$docBlock, self::PROPERTY, null, $declaringClass];
264258
break;
265259

266-
case [$docBlock] = $this->getDocBlockFromMethod($class, $ucFirstProperty, self::ACCESSOR):
267-
$data = [$docBlock, self::ACCESSOR, null];
260+
case [$docBlock, , $declaringClass] = $this->getDocBlockFromMethod($class, $ucFirstProperty, self::ACCESSOR):
261+
$data = [$docBlock, self::ACCESSOR, null, $declaringClass];
268262
break;
269263

270-
case [$docBlock, $prefix] = $this->getDocBlockFromMethod($class, $ucFirstProperty, self::MUTATOR):
271-
$data = [$docBlock, self::MUTATOR, $prefix];
264+
case [$docBlock, $prefix, $declaringClass] = $this->getDocBlockFromMethod($class, $ucFirstProperty, self::MUTATOR):
265+
$data = [$docBlock, self::MUTATOR, $prefix, $declaringClass];
272266
break;
273267

274268
default:
275-
$data = [null, null, null];
269+
$data = [null, null, null, null];
276270
}
277271

278272
return $this->docBlocks[$propertyHash] = $data;
279273
}
280274

281-
private function getDocBlockFromProperty(string $class, string $property): ?DocBlock
275+
/**
276+
* @return array{DocBlock, string}|null
277+
*/
278+
private function getDocBlockFromProperty(string $class, string $property, ?string $originalClass = null): ?array
282279
{
280+
$originalClass ??= $class;
281+
283282
// Use a ReflectionProperty instead of $class to get the parent class if applicable
284283
try {
285284
$reflectionProperty = new \ReflectionProperty($class, $property);
@@ -291,22 +290,25 @@ private function getDocBlockFromProperty(string $class, string $property): ?DocB
291290

292291
foreach ($reflector->getTraits() as $trait) {
293292
if ($trait->hasProperty($property)) {
294-
return $this->getDocBlockFromProperty($trait->getName(), $property);
293+
return $this->getDocBlockFromProperty($trait->getName(), $property, $reflector->isTrait() ? $originalClass : $reflector->getName());
295294
}
296295
}
297296

298297
try {
299-
return $this->docBlockFactory->create($reflectionProperty, $this->createFromReflector($reflector));
298+
$declaringClass = $reflector->isTrait() ? $originalClass : $reflector->getName();
299+
300+
return [$this->docBlockFactory->create($reflectionProperty, $this->createFromReflector($reflector)), $declaringClass];
300301
} catch (\InvalidArgumentException|\RuntimeException) {
301302
return null;
302303
}
303304
}
304305

305306
/**
306-
* @return array{DocBlock, string}|null
307+
* @return array{DocBlock, string, string}|null
307308
*/
308-
private function getDocBlockFromMethod(string $class, string $ucFirstProperty, int $type): ?array
309+
private function getDocBlockFromMethod(string $class, string $ucFirstProperty, int $type, ?string $originalClass = null): ?array
309310
{
311+
$originalClass ??= $class;
310312
$prefixes = self::ACCESSOR === $type ? $this->accessorPrefixes : $this->mutatorPrefixes;
311313
$prefix = null;
312314
$method = null;
@@ -343,12 +345,14 @@ private function getDocBlockFromMethod(string $class, string $ucFirstProperty, i
343345

344346
foreach ($reflector->getTraits() as $trait) {
345347
if ($trait->hasMethod($methodName)) {
346-
return $this->getDocBlockFromMethod($trait->getName(), $ucFirstProperty, $type);
348+
return $this->getDocBlockFromMethod($trait->getName(), $ucFirstProperty, $type, $reflector->isTrait() ? $originalClass : $reflector->getName());
347349
}
348350
}
349351

350352
try {
351-
return [$this->docBlockFactory->create($method, $this->createFromReflector($reflector)), $prefix];
353+
$declaringClass = $reflector->isTrait() ? $originalClass : $reflector->getName();
354+
355+
return [$this->docBlockFactory->create($method, $this->createFromReflector($reflector)), $prefix, $declaringClass];
352356
} catch (\InvalidArgumentException|\RuntimeException) {
353357
return null;
354358
}

src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@
2121
use Symfony\Component\PropertyInfo\Tests\Fixtures\DockBlockFallback;
2222
use Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy;
2323
use Symfony\Component\PropertyInfo\Tests\Fixtures\DummyCollection;
24+
use Symfony\Component\PropertyInfo\Tests\Fixtures\Extractor\ChildOfParentUsingTrait;
25+
use Symfony\Component\PropertyInfo\Tests\Fixtures\Extractor\ChildOfParentWithPromotedSelfDocBlock;
26+
use Symfony\Component\PropertyInfo\Tests\Fixtures\Extractor\ChildWithSelfDocBlock;
27+
use Symfony\Component\PropertyInfo\Tests\Fixtures\Extractor\ClassUsingNestedTrait;
28+
use Symfony\Component\PropertyInfo\Tests\Fixtures\Extractor\ClassUsingTraitWithSelfDocBlock;
29+
use Symfony\Component\PropertyInfo\Tests\Fixtures\Extractor\ParentUsingTraitWithSelfDocBlock;
30+
use Symfony\Component\PropertyInfo\Tests\Fixtures\Extractor\ParentWithPromotedSelfDocBlock;
31+
use Symfony\Component\PropertyInfo\Tests\Fixtures\Extractor\ParentWithSelfDocBlock;
2432
use Symfony\Component\PropertyInfo\Tests\Fixtures\InvalidDummy;
2533
use Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy;
2634
use Symfony\Component\PropertyInfo\Tests\Fixtures\Php80Dummy;
@@ -319,6 +327,38 @@ public function testPropertiesParentType(string $class, string $property, ?Type
319327
$this->assertEquals($type, $this->extractor->getType($class, $property));
320328
}
321329

330+
/**
331+
* @param class-string $class
332+
* @param class-string $expectedResolvedClass
333+
*/
334+
#[DataProvider('selfDocBlockResolutionProvider')]
335+
public function testSelfDocBlockResolvesToDeclaringClass(string $class, string $property, string $expectedResolvedClass)
336+
{
337+
$this->assertEquals(Type::object($expectedResolvedClass), $this->extractor->getType($class, $property));
338+
}
339+
340+
/**
341+
* @return iterable<string, array{0: class-string, 1: string, 2: class-string}>
342+
*/
343+
public static function selfDocBlockResolutionProvider(): iterable
344+
{
345+
yield 'parent property' => [ParentWithSelfDocBlock::class, 'selfProp', ParentWithSelfDocBlock::class];
346+
yield 'parent property from child' => [ChildWithSelfDocBlock::class, 'selfProp', ParentWithSelfDocBlock::class];
347+
yield 'parent accessor' => [ParentWithSelfDocBlock::class, 'selfAccessor', ParentWithSelfDocBlock::class];
348+
yield 'parent accessor from child' => [ChildWithSelfDocBlock::class, 'selfAccessor', ParentWithSelfDocBlock::class];
349+
yield 'parent mutator' => [ParentWithSelfDocBlock::class, 'selfMutator', ParentWithSelfDocBlock::class];
350+
yield 'parent mutator from child' => [ChildWithSelfDocBlock::class, 'selfMutator', ParentWithSelfDocBlock::class];
351+
yield 'trait property' => [ClassUsingTraitWithSelfDocBlock::class, 'selfTraitProp', ClassUsingTraitWithSelfDocBlock::class];
352+
yield 'trait accessor' => [ClassUsingTraitWithSelfDocBlock::class, 'selfTraitAccessor', ClassUsingTraitWithSelfDocBlock::class];
353+
yield 'trait mutator' => [ClassUsingTraitWithSelfDocBlock::class, 'selfTraitMutator', ClassUsingTraitWithSelfDocBlock::class];
354+
yield 'trait property from child' => [ChildOfParentUsingTrait::class, 'selfTraitProp', ParentUsingTraitWithSelfDocBlock::class];
355+
yield 'trait accessor from child' => [ChildOfParentUsingTrait::class, 'selfTraitAccessor', ParentUsingTraitWithSelfDocBlock::class];
356+
yield 'trait mutator from child' => [ChildOfParentUsingTrait::class, 'selfTraitMutator', ParentUsingTraitWithSelfDocBlock::class];
357+
yield 'nested trait property' => [ClassUsingNestedTrait::class, 'innerSelfProp', ClassUsingNestedTrait::class];
358+
yield 'promoted property' => [ParentWithPromotedSelfDocBlock::class, 'promotedSelfProp', ParentWithPromotedSelfDocBlock::class];
359+
yield 'promoted property from child' => [ChildOfParentWithPromotedSelfDocBlock::class, 'promotedSelfProp', ParentWithPromotedSelfDocBlock::class];
360+
}
361+
322362
/**
323363
* @return iterable<array{0: class-string, 1: string, 2: ?Type}>
324364
*/
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\PropertyInfo\Tests\Fixtures\Extractor;
13+
14+
class ParentWithSelfDocBlock
15+
{
16+
/**
17+
* @var self
18+
*/
19+
public $selfProp;
20+
21+
/**
22+
* @return self
23+
*/
24+
public function getSelfAccessor()
25+
{
26+
return $this;
27+
}
28+
29+
/**
30+
* @param self $value
31+
*/
32+
public function setSelfMutator($value)
33+
{
34+
}
35+
}
36+
37+
class ChildWithSelfDocBlock extends ParentWithSelfDocBlock
38+
{
39+
}
40+
41+
trait TraitWithSelfDocBlock
42+
{
43+
/**
44+
* @var self
45+
*/
46+
public $selfTraitProp;
47+
48+
/**
49+
* @return self
50+
*/
51+
pub B72 lic function getSelfTraitAccessor()
52+
{
53+
return $this;
54+
}
55+
56+
/**
57+
* @param self $value
58+
*/
59+
public function setSelfTraitMutator($value)
60+
{
61+
}
62+
}
63+
64+
class ClassUsingTraitWithSelfDocBlock
65+
{
66+
use TraitWithSelfDocBlock;
67+
}
68+
69+
class ParentUsingTraitWithSelfDocBlock
70+
{
71+
use TraitWithSelfDocBlock;
72+
}
73+
74+
class ChildOfParentUsingTrait extends ParentUsingTraitWithSelfDocBlock
75+
{
76+
}
77+
78+
trait InnerTraitWithSelf
79+
{
80+
/**
81+
* @var self
82+
*/
83+
public $innerSelfProp;
84+
}
85+
86+
trait OuterTrait
87+
{
88+
use InnerTraitWithSelf;
89+
}
90+
91+
class ClassUsingNestedTrait
92+
{
93+
use OuterTrait;
94+
}
95+
96+
class ParentWithPromotedSelfDocBlock
97+
{
98+
/**
99+
* @param self $promotedSelfProp
100+
*/
101+
public function __construct(
102+
public $promotedSelfProp = null,
103+
) {
104+
}
105+
}
106+
107+
class ChildOfParentWithPromotedSelfDocBlock extends ParentWithPromotedSelfDocBlock
108+
{
109+
}

src/Symfony/Component/PropertyInfo/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"symfony/serializer": "^7.4|^8.0"
3636
},
3737
"conflict": {
38-
"phpdocumentor/reflection-docblock": "<5.2",
38+
"phpdocumentor/reflection-docblock": "<5.2|>=6",
3939
"phpdocumentor/type-resolver": "<1.5.1"
4040
},
4141
"autoload": {

0 commit comments

Comments
 (0)
0