Skip to content

Commit 55461a8

Browse files
authored
feat: Use Type of TypeInfo instead of PropertyInfo (#6979)
Co-authored-by: soyuka <soyuka@users.noreply.github.com> scopes: metadata, doctrine, json-schema
1 parent 1f6d5c9 commit 55461a8

File tree

51 files changed

+1394
-233
lines changed

Some content is hidden

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

51 files changed

+1394
-233
lines changed

composer.json

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@
114114
"symfony/property-info": "^6.4 || ^7.1",
115115
"symfony/serializer": "^6.4 || ^7.0",
116116
"symfony/translation-contracts": "^3.3",
117-
"symfony/web-link": "^6.4 || ^7.1",
117+
"symfony/type-info": "^7.3-dev",
118+
"symfony/web-link": "^6.4 || ^7.0",
118119
"willdurand/negotiation": "^3.1"
119120
},
120121
"require-dev": {
@@ -164,7 +165,7 @@
164165
"symfony/console": "^6.4 || ^7.0",
165166
"symfony/css-selector": "^6.4 || ^7.0",
166167
"symfony/dependency-injection": "^6.4 || ^7.0",
167-
"symfony/doctrine-bridge": "^6.4.2 || ^7.0.2",
168+
"symfony/doctrine-bridge": "^6.4.2 || ^7.1",
168169
"symfony/dom-crawler": "^6.4 || ^7.0",
169170
"symfony/error-handler": "^6.4 || ^7.0",
170171
"symfony/event-dispatcher": "^6.4 || ^7.0",
@@ -208,5 +209,11 @@
208209
"symfony/web-profiler-bundle": "To use the data collector.",
209210
"webonyx/graphql-php": "To support GraphQL."
210211
},
211-
"type": "library"
212+
"type": "library",
213+
"repositories": [
214+
{
215+
"type": "vcs",
216+
"url": "https://github.com/symfony/type-info"
217+
}
218+
]
212219
}

docs/composer.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"symfony/property-info": "^7.0",
2626
"symfony/runtime": "^7.0",
2727
"symfony/security-bundle": "^7.0",
28+
"symfony/type-info": "^7.3-dev",
2829
"symfony/serializer": "^7.0",
2930
"symfony/validator": "^7.0",
3031
"symfony/yaml": "^7.0",
@@ -50,5 +51,11 @@
5051
"name": "api-platform/api-platform",
5152
"url": "https://github.com/api-platform/api-platform"
5253
}
53-
}
54+
},
55+
"repositories": [
56+
{
57+
"type": "vcs",
58+
"url": "https://github.com/symfony/type-info"
59+
}
60+
]
5461
}

docs/guides/create-a-custom-doctrine-filter.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
2727
use ApiPlatform\Metadata\Operation;
2828
use Doctrine\ORM\QueryBuilder;
29-
use Symfony\Component\PropertyInfo\Type;
3029

3130
final class RegexpFilter extends AbstractFilter
3231
{
@@ -67,7 +66,7 @@ public function getDescription(string $resourceClass): array
6766
foreach ($this->properties as $property => $strategy) {
6867
$description["regexp_$property"] = [
6968
'property' => $property,
70-
'type' => Type::BUILTIN_TYPE_STRING,
69+
'type' => 'string',
7170
'required' => false,
7271
'description' => 'Filter using a regex. This will appear in the OpenAPI documentation!',
7372
'openapi' => [

src/Doctrine/Common/composer.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
"doctrine/mongodb-odm": "^2.10",
3535
"doctrine/orm": "^2.17 || ^3.0",
3636
"phpspec/prophecy-phpunit": "^2.2",
37-
"phpunit/phpunit": "^11.2"
37+
"phpunit/phpunit": "^11.2",
38+
"symfony/type-info": "^7.3-dev"
3839
},
3940
"conflict": {
4041
"doctrine/persistence": "<1.3"
@@ -73,5 +74,11 @@
7374
},
7475
"scripts": {
7576
"test": "./vendor/bin/phpunit"
76-
}
77+
},
78+
"repositories": [
79+
{
80+
"type": "vcs",
81+
"url": "https://github.com/symfony/type-info"
82+
}
83+
]
7784
}

src/Doctrine/Odm/PropertyInfo/DoctrineExtractor.php

Lines changed: 75 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
namespace ApiPlatform\Doctrine\Odm\PropertyInfo;
1515

16-
use ApiPlatform\Metadata\Util\PropertyInfoToTypeInfoHelper;
1716
use Doctrine\Common\Collections\Collection;
1817
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata as MongoDbClassMetadata;
1918
use Doctrine\ODM\MongoDB\Types\Type as MongoDbType;
@@ -25,6 +24,7 @@
2524
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
2625
use Symfony\Component\PropertyInfo\Type as LegacyType;
2726
use Symfony\Component\TypeInfo\Type;
27+
use Symfony\Component\TypeInfo\TypeIdentifier;
2828

2929
/**
3030
* Extracts data using Doctrine MongoDB ODM metadata.
@@ -52,13 +52,71 @@ public function getProperties($class, array $context = []): ?array
5252
return $metadata->getFieldNames();
5353
}
5454

55+
public function getType(string $class, string $property, array $context = []): ?Type
56+
{
57+
if (null === $metadata = $this->getMetadata($class)) {
58+
return null;
59+
}
60+
61+
if ($metadata->hasAssociation($property)) {
62+
/** @var class-string|null */
63+
$class = $metadata->getAssociationTargetClass($property);
64+
65+
if (null === $class) {
66+
return null;
67+
}
68+
69+
if ($metadata->isSingleValuedAssociation($property)) {
70+
$nullable = $metadata instanceof MongoDbClassMetadata && $metadata->isNullable($property);
71+
72+
return $nullable ? Type::nullable(Type::object($class)) : Type::object($class);
73+
}
74+
75+
return Type::collection(Type::object(Collection::class), Type::object($class), Type::int());
76+
}
77+
78+
if (!$metadata->hasField($property)) {
79+
return null;
80+
}
81+
82+
$typeOfField = $metadata->getTypeOfField($property);
83+
84+
if (!$typeIdentifier = $this->getTypeIdentifier($typeOfField)) {
85+
return null;
86+
}
87+
88+
$nullable = $metadata instanceof MongoDbClassMetadata && $metadata->isNullable($property);
89+
$enumType = null;
90+
91+
if (null !== $enumClass = $metadata instanceof MongoDbClassMetadata ? $metadata->getFieldMapping($property)['enumType'] ?? null : null) {
92+
$enumType = $nullable ? Type::nullable(Type::enum($enumClass)) : Type::enum($enumClass);
93+
}
94+
95+
$builtinType = $nullable ? Type::nullable(Type::builtin($typeIdentifier)) : Type::builtin($typeIdentifier);
96+
97+
$type = match ($typeOfField) {
98+
MongoDbType::DATE => Type::object(\DateTime::class),
99+
MongoDbType::DATE_IMMUTABLE => Type::object(\DateTimeImmutable::class),
100+
MongoDbType::HASH => Type::array(),
101+
MongoDbType::COLLECTION => Type::list(),
102+
MongoDbType::INT, MongoDbType::INTEGER, MongoDbType::STRING => $enumType ? $enumType : $builtinType,
103+
default => $builtinType,
104+
};
105+
106+
return $nullable ? Type::nullable($type) : $type;
107+
}
108+
55109
/**
56110
* {@inheritdoc}
57111
*
112+
* // deprecated since 4.2 use "getType" instead
113+
*
58114
* @return LegacyType[]|null
59115
*/
60-
public function getTypes(string $class, string $property, array $context = []): ?array
116+
public function getTypes($class, $property, array $context = []): ?array
61117
{
118+
trigger_deprecation('api-platform/core', '4.2', 'The "%s()" method is deprecated, use "%s::getType()" instead.', __METHOD__, self::class);
119+
62120
if (null === $metadata = $this->getMetadata($class)) {
63121
return null;
64122
}
@@ -115,7 +173,7 @@ public function getTypes(string $class, string $property, array $context = []):
115173
}
116174
}
117175

118-
$builtinType = $this->getPhpType($typeOfField);
176+
$builtinType = $this->getNativeTypeLegacy($typeOfField);
119177

120178
return $builtinType ? [new LegacyType($builtinType, $nullable)] : null;
121179
}
@@ -156,15 +214,23 @@ private function getMetadata(string $class): ?ClassMetadata
156214
}
157215
}
158216

159-
public function getType(string $class, string $property, array $context = []): ?Type
217+
/**
218+
* Gets the corresponding built-in PHP type identifier.
219+
*/
220+
private function getTypeIdentifier(string $doctrineType): ?TypeIdentifier
160221
{
161-
return PropertyInfoToTypeInfoHelper::convertLegacyTypesToType($this->getTypes($class, $property, $context));
222+
return match ($doctrineType) {
223+
MongoDbType::INTEGER, MongoDbType::INT, MongoDbType::INTID, MongoDbType::KEY => TypeIdentifier::INT,
224+
MongoDbType::FLOAT => TypeIdentifier::FLOAT,
225+
MongoDbType::STRING, MongoDbType::ID, MongoDbType::OBJECTID, MongoDbType::TIMESTAMP, MongoDbType::BINDATA, MongoDbType::BINDATABYTEARRAY, MongoDbType::BINDATACUSTOM, MongoDbType::BINDATAFUNC, MongoDbType::BINDATAMD5, MongoDbType::BINDATAUUID, MongoDbType::BINDATAUUIDRFC4122 => TypeIdentifier::STRING,
226+
MongoDbType::BOOLEAN, MongoDbType::BOOL => TypeIdentifier::BOOL,
227+
MongoDbType::DATE, MongoDbType::DATE_IMMUTABLE => TypeIdentifier::OBJECT,
228+
MongoDbType::HASH, MongoDbType::COLLECTION => TypeIdentifier::ARRAY,
229+
default => null,
230+
};
162231
}
163232

164-
/**
165-
* Gets the corresponding built-in PHP type.
166-
*/
167-
private function getPhpType(string $doctrineType): ?string
233+
private function getNativeTypeLegacy(string $doctrineType): ?string
168234
{
169235
return match ($doctrineType) {
170236
MongoDbType::INTEGER, MongoDbType::INT, MongoDbType::INTID, MongoDbType::KEY => LegacyType::BUILTIN_TYPE_INT,

0 commit comments

Comments
 (0)