Skip to content

Commit b78a76e

Browse files
committed
Support multiple types for collection keys & values
1 parent dc0d45d commit b78a76e

File tree

4 files changed

+136
-4
lines changed

4 files changed

+136
-4
lines changed

UPGRADE-5.3.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
UPGRADE FROM 5.2 to 5.3
2+
=======================
3+
4+
PropertyInfo
5+
------------
6+
7+
* Deprecated the `Type::getCollectionKeyType()` and `Type::getCollectionValueType()` methods, use `Type::getCollectionKeyTypes()` and `Type::getCollectionValueTypes()` instead.

src/Symfony/Component/PropertyInfo/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
CHANGELOG
22
=========
33

4+
5.3.0
5+
-----
6+
7+
* Added support for multiple types for collection keys & values
8+
* Deprecated the `Type::getCollectionKeyType()` and `Type::getCollectionValueType()` methods, use `Type::getCollectionKeyTypes()` and `Type::getCollectionValueTypes()` instead.
9+
410
5.2.0
511
-----
612

src/Symfony/Component/PropertyInfo/Tests/TypeTest.php

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,24 @@
1212
namespace Symfony\Component\PropertyInfo\Tests;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
1516
use Symfony\Component\PropertyInfo\Type;
1617

1718
/**
1819
* @author Kévin Dunglas <dunglas@gmail.com>
1920
*/
2021
class TypeTest extends TestCase
2122
{
22-
public function testConstruct()
23+
use ExpectDeprecationTrait;
24+
25+
/**
26+
* @group legacy
27+
*/
28+
public function testLegacyConstruct()
2329
{
30+
$this->expectDeprecation('Since symfony/property-info 5.3: The "Symfony\Component\PropertyInfo\Type::getCollectionKeyType()" method is deprecated, use "getCollectionKeyTypes()" instead.');
31+
$this->expectDeprecation('Since symfony/property-info 5.3: The "Symfony\Component\PropertyInfo\Type::getCollectionValueType()" method is deprecated, use "getCollectionValueTypes()" instead.');
32+
2433
$type = new Type('object', true, 'ArrayObject', true, new Type('int'), new Type('string'));
2534

2635
$this->assertEquals(Type::BUILTIN_TYPE_OBJECT, $type->getBuiltinType());
@@ -37,6 +46,26 @@ public function testConstruct()
3746
$this->assertEquals(Type::BUILTIN_TYPE_STRING, $collectionValueType->getBuiltinType());
3847
}
3948

49+
public function testConstruct()
50+
{
51+
$type = new Type('object', true, 'ArrayObject', true, new Type('int'), new Type('string'));
52+
53+
$this->assertEquals(Type::BUILTIN_TYPE_OBJECT, $type->getBuiltinType());
54+
$this->assertTrue($type->isNullable());
55+
$this->assertEquals('ArrayObject', $type->getClassName());
56+
$this->assertTrue($type->isCollection());
57+
58+
$collectionKeyTypes = $type->getCollectionKeyTypes();
59+
$this->assertIsArray($collectionKeyTypes);
60+
$this->assertContainsOnlyInstancesOf('Symfony\Component\PropertyInfo\Type', $collectionKeyTypes);
61+
$this->assertEquals(Type::BUILTIN_TYPE_INT, $collectionKeyTypes[0]->getBuiltinType());
62+
63+
$collectionValueTypes = $type->getCollectionValueTypes();
64+
$this->assertIsArray($collectionValueTypes);
65+
$this->assertContainsOnlyInstancesOf('Symfony\Component\PropertyInfo\Type', $collectionValueTypes);
66+
$this->assertEquals(Type::BUILTIN_TYPE_STRING, $collectionValueTypes[0]->getBuiltinType());
67+
}
68+
4069
public function testIterable()
4170
{
4271
$type = new Type('iterable');
@@ -49,4 +78,30 @@ public function testInvalidType()
4978
$this->expectExceptionMessage('"foo" is not a valid PHP type.');
5079
new Type('foo');
5180
}
81+
82+
public function testArrayCollection()
83+
{
84+
$type = new Type('array', false, null, true, [new Type('int'), new Type('string')], [new Type('object', false, \ArrayObject::class, true), new Type('array', false, null, true)]);
85+
86+
$this->assertEquals(Type::BUILTIN_TYPE_ARRAY, $type->getBuiltinType());
87+
$this->assertFalse($type->isNullable());
88+
$this->assertTrue($type->isCollection());
89+
90+
[$firstKeyType, $secondKeyType] = $type->getCollectionKeyTypes();
91+
$this->assertEquals(Type::BUILTIN_TYPE_INT, $firstKeyType->getBuiltinType());
92+
$this->assertFalse($firstKeyType->isNullable());
93+
$this->assertFalse($firstKeyType->isCollection());
94+
$this->assertEquals(Type::BUILTIN_TYPE_STRING, $secondKeyType->getBuiltinType());
95+
$this->assertFalse($secondKeyType->isNullable());
96+
$this->assertFalse($secondKeyType->isCollection());
97+
98+
[$firstValueType, $secondValueType] = $type->getCollectionValueTypes();
99+
$this->assertEquals(Type::BUILTIN_TYPE_OBJECT, $firstValueType->getBuiltinType());
100+
$this->assertEquals(\ArrayObject::class, $firstValueType->getClassName());
101+
$this->assertFalse($firstValueType->isNullable());
102+
$this->assertTrue($firstValueType->isCollection());
103+
$this->assertEquals(Type::BUILTIN_TYPE_ARRAY, $secondValueType->getBuiltinType());
104+
$this->assertFalse($secondValueType->isNullable());
105+
$this->assertTrue($firstValueType->isCollection());
106+
}
52107
}

src/Symfony/Component/PropertyInfo/Type.php

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,12 @@ class Type
5757
private $collectionValueType;
5858

5959
/**
60+
* @param array|Type|null $collectionKeyType
61+
* @param array|Type|null $collectionValueType
62+
*
6063
* @throws \InvalidArgumentException
6164
*/
62-
public function __construct(string $builtinType, bool $nullable = false, string $class = null, bool $collection = false, self $collectionKeyType = null, self $collectionValueType = null)
65+
public function __construct(string $builtinType, bool $nullable = false, string $class = null, bool $collection = false, $collectionKeyType = null, $collectionValueType = null)
6366
{
6467
if (!\in_array($builtinType, self::$builtinTypes)) {
6568
throw new \InvalidArgumentException(sprintf('"%s" is not a valid PHP type.', $builtinType));
@@ -69,8 +72,31 @@ public function __construct(string $builtinType, bool $nullable = false, string
6972
$this->nullable = $nullable;
7073
$this->class = $class;
7174
$this->collection = $collection;
72-
$this->collectionKeyType = $collectionKeyType;
73-
$this->collectionValueType = $collectionValueType;
75+
$this->collectionKeyType = $this->validateCollectionArgument($collectionKeyType, 5, '$collectionKeyType');
76+
$this->collectionValueType = $this->validateCollectionArgument($collectionValueType, 6, '$collectionValueType');
77+
}
78+
79+
private function validateCollectionArgument($collectionArgument, int $argumentIndex, string $argumentName): ?array
80+
{
81+
if (null === $collectionArgument) {
82+
return null;
83+
}
84+
85+
if (null !== $collectionArgument && !\is_array($collectionArgument) && !$collectionArgument instanceof self) {
86+
throw new \TypeError(sprintf('"%s()": Argument #%d (%s) must be of type "array", "%s" or "null", "%s" given.', __METHOD__, $argumentIndex, $argumentName, self::class, get_debug_type($collectionArgument)));
87+
}
88+
89+
if (\is_array($collectionArgument)) {
90+
foreach ($collectionArgument as $type) {
91+
if (!$type instanceof self) {
92+
throw new \TypeError(sprintf('"%s()": Argument #%d (%s) must be an array with items of type "%s", "%s" given.', __METHOD__, $argumentIndex, $argumentName, self::class, get_debug_type($collectionArgument)));
93+
}
94+
}
95+
96+
return $collectionArgument;
97+
}
98+
99+
return [$collectionArgument];
74100
}
75101

76102
/**
@@ -107,8 +133,27 @@ public function isCollection(): bool
107133
* Gets collection key type.
108134
*
109135
* Only applicable for a collection type.
136+
*
137+
* @deprecated since Symfony 5.3, use "getCollectionKeyTypes()" instead
110138
*/
111139
public function getCollectionKeyType(): ?self
140+
{
141+
trigger_deprecation('symfony/property-info', '5.3', 'The "%s()" method is deprecated, use "getCollectionKeyTypes()" instead.', __METHOD__);
142+
143+
$type = $this->getCollectionKeyTypes();
144+
if (\is_array($type)) {
145+
[$type] = $type;
146+
}
147+
148+
return $type;
149+
}
150+
151+
/**
152+
* Gets collection key types.
153+
*
154+
* Only applicable for a collection type.
155+
*/
156+
public function getCollectionKeyTypes(): ?array
112157
{
113158
return $this->collectionKeyType;
114159
}
@@ -117,8 +162,27 @@ public function getCollectionKeyType(): ?self
117162
* Gets collection value type.
118163
*
119164
* Only applicable for a collection type.
165+
*
166+
* @deprecated since Symfony 5.3, use "getCollectionValueTypes()" instead
120167
*/
121168
public function getCollectionValueType(): ?self
169+
{
170+
trigger_deprecation('symfony/property-info', '5.3', 'The "%s()" method is deprecated, use "getCollectionValueTypes()" instead.', __METHOD__);
171+
172+
$type = $this->getCollectionValueTypes();
173+
if (\is_array($type)) {
174+
[$type] = $type;
175+
}
176+
177+
return $type;
178+
}
179+
180+
/**
181+
* Gets collection value types.
182+
*
183+
* Only applicable for a collection type.
184+
*/
185+
public function getCollectionValueTypes(): ?array
122186
{
123187
return $this->collectionValueType;
124188
}

0 commit comments

Comments
 (0)