8000 feature #26300 [PropertyInfo] Implement "Collection" types in PhpDocE… · symfony/symfony@1a3d445 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1a3d445

Browse files
committed
feature #26300 [PropertyInfo] Implement "Collection" types in PhpDocExtractor (popy-dev)
This PR was squashed before being merged into the 4.2-dev branch (closes #26300). Discussion ---------- [PropertyInfo] Implement "Collection" types in PhpDocExtractor | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #26299 | License | MIT | Doc PR | todo Here's a proposition of implementation of my feature request #26299 : I added few tests covering the requested feature, and I had to change a few things in the ```Symfony\Component\PropertyInfo\Util\PhpDocTypeHelper``` class (createType no longer gets a string, but a ```phpDocumentor\Reflection\Type``` instance) to be able to detect properly Collections and their subtypes. Of course a simpler implementation is possible, without changing the PhpDocTypeHelper internal behaviour, by matching the input string against ```/^([^>]+)</``` and extracting the classname alone. Commits ------- 12bafe4 [PropertyInfo] Implement \"Collection\" types in PhpDocExtractor
2 parents 2b9c142 + 12bafe4 commit 1a3d445

File tree

4 files changed

+84
-10
lines changed

4 files changed

+84
-10
lines changed

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
1616
use Symfony\Component\PropertyInfo\Type;
17+
use phpDocumentor\Reflection\Types\Collection;
1718

1819
/**
1920
* @author Kévin Dunglas <dunglas@gmail.com>
@@ -77,6 +78,39 @@ public function typesProvider()
7778
);
7879
}
7980

81+
/**
82+
* @dataProvider provideCollectionTypes
83+
*/
84+
public function testExtractCollection($property, array $type = null, $shortDescription, $longDescription)
85+
{
86+
if (!class_exists(Collection::class)) {
87+
$this->markTestSkipped('Collections are not implemented in current phpdocumentor/type-resolver version');
88+
}
89+
90+
$this->testExtract($property, $type, $shortDescription, $longDescription);
91+
}
92+
93+
public function provideCollectionTypes()
94+
{
95+
return array(
96+
array('iteratorCollection', array(new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Iterator', true, null, new Type(Type::BUILTIN_TYPE_STRING))), null, null),
97+
array('iteratorCollectionWithKey', array(new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Iterator', true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING))), null, null),
98+
array(
99+
'nestedIterators',
100+
array(new Type(
101+
Type::BUILTIN_TYPE_OBJECT,
102+
false,
103+
'Iterator',
104+
true,
105+
new Type(Type::BUILTIN_TYPE_INT),
106+
new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Iterator', true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING))
107+
)),
108+
null,
109+
null,
110+
),
111+
);
112+
}
113+
80114
public function testParamTagTypeIsOmitted()
81115
{
82116
$this->assertNull($this->extractor->getTypes(OmittedParamTagTypeDocBlock::class, 'omittedType'));

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ public function testGetProperties()
4242
'Guid',
4343
'array',
4444
'emptyVar',
45+
'iteratorCollection',
46+
'iteratorCollectionWithKey',
47+
'nestedIterators',
4548
'foo',
4649
'foo2',
4750
'foo3',
@@ -79,6 +82,9 @@ public function testGetPropertiesWithCustomPrefixes()
7982
'Guid',
8083
'array',
8184
'emptyVar',
85+
'iteratorCollection',
86+
'iteratorCollectionWithKey',
87+
'nestedIterators',
8288
'foo',
8389
'foo2',
8490
'foo3',
@@ -107,6 +113,9 @@ public function testGetPropertiesWithNoPrefixes()
107113
'Guid',
108114
'array',
109115
'emptyVar',
116+
'iteratorCollection',
117+
'iteratorCollectionWithKey',
118+
'nestedIterators',
110119
'foo',
111120
'foo2',
112121
'foo3',

src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,21 @@ class Dummy extends ParentDummy
7575
*/
7676
public $emptyVar;
7777

78+
/**
79+
* @var \Iterator<string>
80+
*/
81+
public $iteratorCollection;
82+
83+
/**
84+
* @var \Iterator<integer,string>
85+
*/
86+
public $iteratorCollectionWithKey;
87+
88+
/**
89+
* @var \Iterator<integer,\Iterator<integer,string>>
90+
*/
91+
public $nestedIterators;
92+
7893
public static function getStatic()
7994
{
8095
}

src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\PropertyInfo\Util;
1313

1414
use phpDocumentor\Reflection\Type as DocType;
15+
use phpDocumentor\Reflection\Types\Collection;
1516
use phpDocumentor\Reflection\Types\Compound;
1617
use phpDocumentor\Reflection\Types\Null_;
1718
use Symfony\Component\PropertyInfo\Type;
@@ -39,7 +40,7 @@ public function getTypes(DocType $varType): array
3940
$nullable = true;
4041
}
4142

42-
$type = $this->createType((string) $varType, $nullable);
43+
$type = $this->createType($varType, $nullable);
4344
if (null !== $type) {
4445
$types[] = $type;
4546
}
@@ -49,16 +50,15 @@ public function getTypes(DocType $varType): array
4950

5051
$varTypes = array();
5152
for ($typeIndex = 0; $varType->has($typeIndex); ++$typeIndex) {
52-
$varTypes[] = (string) $varType->get($typeIndex);
53-
}
53+
$type = $varType->get($typeIndex);
5454

55-
// If null is present, all types are nullable
56-
$nullKey = array_search(Type::BUILTIN_TYPE_NULL, $varTypes);
57-
$nullable = false !== $nullKey;
55+
// If null is present, all types are nullable
56+
if ($type instanceof Null_) {
57+
$nullable = true;
58+
continue;
59+
}
5860

59-
// Remove the null type from the type if other types are defined
60-
if ($nullable && count($varTypes) > 1) {
61-
unset($varTypes[$nullKey]);
61+
$varTypes[] = $type;
6262
}
6363

6464
foreach ($varTypes as $varType) {
@@ -74,8 +74,24 @@ public function getTypes(DocType $varType): array
7474
/**
7575
* Creates a {@see Type} from a PHPDoc type.
7676
*/
77-
private function createType(string $docType, bool $nullable): ?Type
77+
private function createType(DocType $type, bool $nullable): ?Type
7878
{
79+
$docType = (string) $type;
80+
81+
if ($type instanceof Collection) {
82+
list($phpType, $class) = $this->getPhpTypeAndClass((string) $type->getFqsen());
83+
84+
$key = $this->getTypes($type->getKeyType());
85+
$value = $this->getTypes($type->getValueType());
86+
87+
// More than 1 type returned means it is a Compound type, which is
88+
// not handled by Type, so better use a null value.
89+
$key = 1 === \count($key) ? $key[0] : null;
90+
$value = 1 === \count($value) ? $value[0] : null;
91+
92+
return new Type($phpType, $nullable, $class, true, $key, $value);
93+
}
94+
7995
// Cannot guess
8096
if (!$docType || 'mixed' === $docType) {
8197
return null;

0 commit comments

Comments
 (0)
0