8000 [PropertyInfo] Deprecate PropertyInfo Type · symfony/symfony@bf280d3 · GitHub
[go: up one dir, main page]

Skip to content

Commit bf280d3

Browse files
mtarldKorbeil
andcommitted
[PropertyInfo] Deprecate PropertyInfo Type
Co-authored-by: Baptiste Leduc <baptiste.leduc@gmail.com>
1 parent 3f2ed0f commit bf280d3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+3063
-729
lines changed

UPGRADE-7.1.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ Cache
1111

1212
* Deprecate `CouchbaseBucketAdapter`, use `CouchbaseCollectionAdapter` instead
1313

14+
DoctrineBridge
15+
--------------
16+
17+
* The `DoctrineExtractor::getTypes()` method is deprecated, use `DoctrineExtractor::getType()` instead
18+
1419
ExpressionLanguage
1520
------------------
1621

@@ -22,6 +27,11 @@ FrameworkBundle
2227

2328
* Mark classes `ConfigBuilderCacheWarmer`, `Router`, `SerializerCacheWarmer`, `TranslationsCacheWarmer`, `Translator` and `ValidatorCacheWarmer` as `final`
2429

30+
PropertyInfo
31+
------------
32+
33+
* The `PropertyTypeExtractorInterface::getTypes()` method is deprecated, use `PropertyTypeExtractorInterface::getType()` instead
34+
2535
SecurityBundle
2636
--------------
2737

src/Symfony/Bridge/Doctrine/CHANGELOG.md

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

4+
7.1
5+
---
6+
7+
* Deprecate the `DoctrineExtractor::getTypes()` method, use `DoctrineExtractor::getType()` instead
8+
49
7.0
510
---
611

@@ -17,7 +22,7 @@ CHANGELOG
1722
6.4
1823
---
1924

20-
* [BC BREAK] Add argument `$buildDir` to `ProxyCacheWarmer::warmUp()`
25+
* [BC BREAK] Add argument `$buildDir` to `ProxyCacheWarmer::warmUp()`
2126
* [BC BREAK] Add return type-hints to `EntityFactory`
2227
* Deprecate `DbalLogger`, use a middleware instead
2328
* Deprecate not constructing `DoctrineDataCollector` with an instance of `DebugDataHolder`

src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php

Lines changed: 133 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface;
2525
use Symfony\Component\PropertyInfo\PropertyListExtractorInterface;
2626
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
27-
use Symfony\Component\PropertyInfo\Type;
27+
use Symfony\Component\PropertyInfo\Type as LegacyType;
28+
use Symfony\Component\TypeInfo\Type;
29+
use Symfony\Component\TypeInfo\TypeIdentifier;
2830

2931
/**
3032
* Extracts data using Doctrine ORM and ODM metadata.
@@ -55,8 +57,110 @@ public function getProperties(string $class, array $context = []): ?array
5557
return $properties;
5658
}
5759

60+
public function getType(string $class, string $property, array $context = []): ?Type
61+
{
62+
if (null === $metadata = $this->getMetadata($class)) {
63+
return null;
64+
}
65+
66+
if ($metadata->hasAssociation($property)) {
67+
$class = $metadata->getAssociationTargetClass($property);
68+
69+
if ($metadata->isSingleValuedAssociation($property)) {
70+
if ($metadata instanceof ClassMetadata) {
71+
$associationMapping = $metadata->getAssociationMapping($property);
72+
$nullable = $this->isAssociationNullable($associationMapping);
73+
} else {
74+
$nullable = false;
75+
}
76+
77+
return $nullable ? Type::nullable(Type::object($class)) : Type::object($class);
78+
}
79+
80+
$collectionKeyType = TypeIdentifier::INT;
81+
82+
if ($metadata instanceof ClassMetadata) {
83+
$associationMapping = $metadata->getAssociationMapping($property);
84+
85+
if (self::getMappingValue($associationMapping, 'indexBy')) {
86+
$subMetadata = $this->entityManager->getClassMetadata(self::getMappingValue($associationMapping, 'targetEntity'));
87+
88+
// Check if indexBy value is a property
89+
$fieldName = self::getMappingValue($associationMapping, 'indexBy');
90+
if (null === ($typeOfField = $subMetadata->getTypeOfField($fieldName))) {
91+
$fieldName = $subMetadata->getFieldForColumn(self::getMappingValue($associationMapping, 'indexBy'));
92+
// Not a property, maybe a column name?
93+
if (null === ($typeOfField = $subMetadata->getTypeOfField($fieldName))) {
94+
// Maybe the column name is the association join column?
95+
$associationMapping = $subMetadata->getAssociationMapping($fieldName);
96+
97+
$indexProperty = $subMetadata->getSingleAssociationReferencedJoinColumnName($fieldName);
98+
$subMetadata = $this->entityManager->getClassMetadata(self::getMappingValue($associationMapping, 'targetEntity'));
99+
100+
// Not a property, maybe a column name?
101+
if (null === ($typeOfField = $subMetadata->getTypeOfField($indexProperty))) {
102+
$fieldName = $subMetadata->getFieldForColumn($indexProperty);
103+
$typeOfField = $subMetadata->getTypeOfField($fieldName);
104+
}
105+
}
106+
}
107+
108+
if (!$collectionKeyType = $this->getTypeIdentifier($typeOfField)) {
109+
return null;
110+
}
111+
}
112+
}
113+
114+
return Type::collection(Type::object(Collection::class), Type::object($class), Type::builtin($collectionKeyType));
115+
}
116+
117+
if ($metadata instanceof ClassMetadata && isset($metadata->embeddedClasses[$property])) {
118+
return Type::object(self::getMappingValue($metadata->embeddedClasses[$property], 'class'));
119+
}
120+
121+
if (!$metadata->hasField($property)) {
122+
return null;
123+
}
124+
125+
$typeOfField = $metadata->getTypeOfField($property);
126+
127+
if (!$typeIdentifier = $this->getTypeIdentifier($typeOfField)) {
128+
return null;
129+
}
130+
131+
$nullable = $metadata instanceof ClassMetadata && $metadata->isNullable($property);
132+
$enumType = null;
133+
134+
if (null !== $enumClass = self::getMappingValue($metadata->getFieldMapping($property), 'enumType') ?? null) {
135+
$enumType = $nullable ? Type::nullable(Type::enum($enumClass)) : Type::enum($enumClass);
136+
}
137+
138+
$builtinType = $nullable ? Type::nullable(Type::builtin($typeIdentifier)) : Type::builtin($typeIdentifier);
139+
140+
return match ($typeIdentifier) {
141+
TypeIdentifier::OBJECT => match ($typeOfField) {
142+
Types::DATE_MUTABLE, Types::DATETIME_MUTABLE, Types::DATETIMETZ_MUTABLE, 'vardatetime', Types::TIME_MUTABLE => $nullable ? Type::nullable(Type::object(\DateTime::class)) : Type::object(\DateTime::class),
143+
Types::DATE_IMMUTABLE, Types::DATETIME_IMMUTABLE, Types::DATETIMETZ_IMMUTABLE, Types::TIME_IMMUTABLE => $nullable ? Type::nullable(Type::object(\DateTimeImmutable::class)) : Type::object(\DateTimeImmutable::class),
144+
Types::DATEINTERVAL => $nullable ? Type::nullable(Type::object(\DateInterval::class)) : Type::object(\DateInterval::class),
145+
default => $builtinType,
146+
},
147+
TypeIdentifier::ARRAY => match ($typeOfField) {
148+
'array', 'json_array' => $enumType ? null : ($nullable ? Type::nullable(Type::array()) : Type::array()),
149+
Types::SIMPLE_ARRAY => $nullable ? Type::nullable(Type::list($enumType ?? Type::string())) : Type::list($enumType ?? Type::string()),
150+
default => $builtinType,
151+
},
152+
TypeIdentifier::INT, TypeIdentifier::STRING => $enumType ? $enumType : $builtinType,
153+
default => $builtinType,
154+
};
155+
}
156+
157+
/**
158+
* @deprecated since Symfony 7.1, use "getType" instead
159+
*/
58160
public function getTypes(string $class, string $property, array $context = []): ?array
59161
{
162+
trigger_deprecation('symfony/property-info', '7.1', 'The "%s()" method is deprecated, use "%s::getType()" instead.', __METHOD__, self::class);
163+
60164
if (null === $metadata = $this->getMetadata($class)) {
61165
return null;
62166
}
@@ -73,10 +177,10 @@ public function getTypes(string $class, string $property, array $context = []):
73177
$nullable = false;
74178
}
75179

76-
return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $class)];
180+
return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, $class)];
77181
}
78182

79-
$collectionKeyType = Type::BUILTIN_TYPE_INT;
183+
$collectionKeyType = LegacyType::BUILTIN_TYPE_INT;
80184

81185
if ($metadata instanceof ClassMetadata) {
82186
$associationMapping = $metadata->getAssociationMapping($property);
@@ -104,61 +208,61 @@ public function getTypes(string $class, string $property, array $context = []):
104208
}
105209
}
106210

107-
if (!$collectionKeyType = $this->getPhpType($typeOfField)) {
211+
if (!$collectionKeyType = $this->getTypeIdentifier($typeOfField)?->value) {
108212
return null;
109213
}
110214
}
111215
}
112216

113-
return [new Type(
114-
Type::BUILTIN_TYPE_OBJECT,
217+
return [new LegacyType(
218+
LegacyType::BUILTIN_TYPE_OBJECT,
115219
false,
116220
Collection::class,
117221
true,
118-
new Type($collectionKeyType),
119-
new Type(Type::BUILTIN_TYPE_OBJECT, false, $class)
222+
new LegacyType($collectionKeyType),
223+
new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, $class)
120224
)];
121225
}
122226

123227
if ($metadata instanceof ClassMetadata && isset($metadata->embeddedClasses[$property])) {
124-
return [new Type(Type::BUILTIN_TYPE_OBJECT, false, self::getMappingValue($metadata->embeddedClasses[$property], 'class'))];
228+
return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, self::getMappingValue($metadata->embeddedClasses[$property], 'class'))];
125229
}
126230

127231
if ($metadata->hasField($property)) {
128232
$typeOfField = $metadata->getTypeOfField($property);
129233

130-
if (!$builtinType = $this->getPhpType($typeOfField)) {
234+
if (!$builtinType = $this->getTypeIdentifier($typeOfField)?->value) {
131235
return null;
132236
}
133237

134238
$nullable = $metadata instanceof ClassMetadata && $metadata->isNullable($property);
135239
$enumType = null;
136240
if (null !== $enumClass = self::getMappingValue($metadata->getFieldMapping($property), 'enumType') ?? null) {
137-
$enumType = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $enumClass);
241+
$enumType = new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, $enumClass);
138242
}
139243

140244
switch ($builtinType) {
141-
case Type::BUILTIN_TYPE_OBJECT:
245+
case LegacyType::BUILTIN_TYPE_OBJECT:
142246
switch ($typeOfField) {
143247
case Types::DATE_MUTABLE:
144248
case Types::DATETIME_MUTABLE:
145249
case Types::DATETIMETZ_MUTABLE:
146250
case 'vardatetime':
147251
case Types::TIME_MUTABLE:
148-
return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateTime')];
252+
return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, 'DateTime')];
149253

150254
case Types::DATE_IMMUTABLE:
151255
case Types::DATETIME_IMMUTABLE:
152256
case Types::DATETIMETZ_IMMUTABLE:
153257
case Types::TIME_IMMUTABLE:
154-
return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateTimeImmutable')];
258+
return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, 'DateTimeImmutable')];
155259

156260
case Types::DATEINTERVAL:
157-
return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateInterval')];
261+
return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, 'DateInterval')];
158262
}
159263

160264
break;
161-
case Type::BUILTIN_TYPE_ARRAY:
265+
case LegacyType::BUILTIN_TYPE_ARRAY:
162266
switch ($typeOfField) {
163267
case 'array': // DBAL < 4
164268
case 'json_array': // DBAL < 3
@@ -167,21 +271,21 @@ public function getTypes(string $class, string $property, array $context = []):
167271
return null;
168272
}
169273

170-
return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true)];
274+
return [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, $nullable, null, true)];
171275

172276
case Types::SIMPLE_ARRAY:
173-
return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, new Type(Type::BUILTIN_TYPE_INT), $enumType ?? new Type(Type::BUILTIN_TYPE_STRING))];
277+
return [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, $nullable, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), $enumType ?? new LegacyType(LegacyType::BUILTIN_TYPE_STRING))];
174278
}
175279
break;
176-
case Type::BUILTIN_TYPE_INT:
177-
case Type::BUILTIN_TYPE_STRING:
280+
case LegacyType::BUILTIN_TYPE_INT:
281+
case LegacyType::BUILTIN_TYPE_STRING:
178282
if ($enumType) {
179283
return [$enumType];
180284
}
181285
break;
182286
}
183287

184-
return [new Type($builtinType, $nullable)];
288+
return [new LegacyType($builtinType, $nullable)];
185289
}
186290

187291
return null;
@@ -244,20 +348,20 @@ private function isAssociationNullable(array|AssociationMapping $associationMapp
244348
/**
245349
* Gets the corresponding built-in PHP type.
246350
*/
247-
private function getPhpType(string $doctrineType): ?string
351+
private function getTypeIdentifier(string $doctrineType): ?TypeIdentifier
248352
{
249353
return match ($doctrineType) {
250354
Types::SMALLINT,
251-
Types::INTEGER => Type::BUILTIN_TYPE_INT,
252-
Types::FLOAT => Type::BUILTIN_TYPE_FLOAT,
355+
Types::INTEGER => TypeIdentifier::INT,
356+
Types::FLOAT => TypeIdentifier::FLOAT,
253357
Types::BIGINT,
254358
Types::STRING,
255359
Types::TEXT,
256360
Types::GUID,
257-
Types::DECIMAL => Type::BUILTIN_TYPE_STRING,
258-
Types::BOOLEAN => Type::BUILTIN_TYPE_BOOL,
361+
Types::DECIMAL => TypeIdentifier::STRING,
362+
Types::BOOLEAN => TypeIdentifier::BOOL,
259363
Types::BLOB,
260-
Types::BINARY => Type::BUILTIN_TYPE_RESOURCE,
364+
Types::BINARY => TypeIdentifier::RESOURCE,
261365
'object', // DBAL < 4
262366
Types::DATE_MUTABLE,
263367
Types::DATETIME_MUTABLE,
@@ -268,10 +372,10 @@ private function getPhpType(string $doctrineType): ?string
268372
Types::DATETIME_IMMUTABLE,
269373
Types::DATETIMETZ_IMMUTABLE,
270374
Types::TIME_IMMUTABLE,
271-
Types::DATEINTERVAL => Type::BUILTIN_TYPE_OBJECT,
375+
Types::DATEINTERVAL => TypeIdentifier::OBJECT,
272376
'array', // DBAL < 4
273377
'json_array', // DBAL < 3
274-
Types::SIMPLE_ARRAY => Type::BUILTIN_TYPE_ARRAY,
378+
Types::SIMPLE_ARRAY => TypeIdentifier::ARRAY,
275379
default => null,
276380
};
277381
}

0 commit comments

Comments
 (0)
0