8000 Use TypeInfo Type by mtarld · Pull Request #6318 · api-platform/core · GitHub
[go: up one dir, main page]

Skip to content

Use TypeInfo Type #6318

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions composer.json
A36C
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"homepage": "https://dunglas.fr"
}
],
"minimum-stability": "dev",
"require": {
"php": ">=8.1",
"doctrine/inflector": "^1.0 || ^2.0",
Expand All @@ -34,6 +35,7 @@
"symfony/property-info": "^6.1 || ^7.0",
"symfony/serializer": "^6.1 || ^7.0",
"symfony/translation-contracts": "^3.3",
"symfony/type-info": "^7.1",
"symfony/web-link": "^6.1 || ^7.0",
"willdurand/negotiation": "^3.0"
},
Expand Down
40 changes: 40 additions & 0 deletions src/Api/UriVariableConverterInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Api;

use ApiPlatform\Exception\InvalidUriVariableException;
use Symfony\Component\TypeInfo\Type;

interface UriVariableConverterInterface
{
/**
* Converts the value of a URI variable (identifier) to its type.
*
* @param mixed $value The URI variable value to transform
* @param array $types The guessed type behind the URI variable
* @param array $context Options available to the transformer
*
* @throws InvalidUriVariableException Occurs when the URI variable could not be converted
*/
public function convert(mixed $value, Type $type, array $context = []);

/**
* Checks whether the value of a URI variable can be converted to its type by this converter.
*
* @param mixed $value The URI variable value to transform
* @param array $types The types to which the URI variable value should be transformed
* @param array $context Options available to the transformer
*/
public function supportsConversion(mixed $value, F438 Type $type, array $context = []): bool;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@

namespace ApiPlatform\Api\UriVariableTransformer;

use ApiPlatform\Api\UriVariableConverterInterface;
use ApiPlatform\Api\UriVariableTransformerInterface;
use ApiPlatform\Exception\InvalidUriVariableException;
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
use Symfony\Component\TypeInfo\Type;

final class DateTimeUriVariableTransformer implements UriVariableTransformerInterface
final class DateTimeUriVariableTransformer implements UriVariableTransformerInterface, UriVariableConverterInterface
{
private readonly DateTimeNormalizer $dateTimeNormalizer;

Expand All @@ -27,17 +29,41 @@ public function __construct()
$this->dateTimeNormalizer = new DateTimeNormalizer();
}

/**
* {@inheritdoc}
*/
public function transform(mixed $value, array $types, array $context = []): \DateTimeInterface
{
trigger_deprecation('api-platform/elasticsearch', '3.3', 'The "%s()" method is deprecated, use "TODO mtarld()" instead.', __METHOD__);

try {
return $this->dateTimeNormalizer->denormalize($value, $types[0], null, $context);
} catch (NotNormalizableValueException $e) {
throw new InvalidUriVariableException($e->getMessage(), $e->getCode(), $e);
}
}

/**
* {@inheritdoc}
*/
public function supportsTransformation(mixed $value, array $types, array $context = []): bool
{
trigger_deprecation('api-platform/elasticsearch', '3.3', 'The "%s()" method is deprecated, use "TODO mtarld()" instead.', __METHOD__);

return $this->dateTimeNormalizer->supportsDenormalization($value, $types[0]);
}

public function convert(mixed $value, Type $type, array $context = []): \DateTimeInterface
{
try {
return $this->dateTimeNormalizer->denormalize($value, (string) $type, null, $context);
} catch (NotNormalizableValueException $e) {
throw new InvalidUriVariableException($e->getMessage(), $e->getCode(), $e);
}
}

public function supportsConversion(mixed $value, Type $type, array $context = []): bool
{
return $this->dateTimeNormalizer->supportsDenormalization($value, (string) $type);
}
}
29 changes: 26 additions & 3 deletions src/Api/UriVariableTransformer/IntegerUriVariableTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,41 @@

namespace ApiPlatform\Api\UriVariableTransformer;

use ApiPlatform\Api\UriVariableConverterInterface;
use ApiPlatform\Api\UriVariableTransformerInterface;
use Symfony\Component\PropertyInfo\Type;
use Symfony\Component\PropertyInfo\Type as LegacyType;
use Symfony\Component\TypeInfo\Type;
use Symfony\Component\TypeInfo\TypeIdentifier;

final class IntegerUriVariableTransformer implements UriVariableTransformerInterface
final class IntegerUriVariableTransformer implements UriVariableTransformerInterface, UriVariableConverterInterface
{
/**
* {@inheritdoc}
*/
public function transform(mixed $value, array $types, array $context = []): int
{
trigger_deprecation('api-platform/elasticsearch', '3.3', 'The "%s()" method is deprecated, use "TODO mtarld()" instead.', __METHOD__);

return (int) $value;
}

/**
* {@inheritdoc}
*/
public function supportsTransformation(mixed $value, array $types, array $context = []): bool
{
return Type::BUILTIN_TYPE_INT === $types[0] && \is_string($value);
trigger_deprecation('api-platform/elasticsearch', '3.3', 'The "%s()" method is deprecated, use "TODO mtarld()" instead.', __METHOD__);

return LegacyType::BUILTIN_TYPE_INT === $types[0] && \is_string($value);
}

public function convert(mixed $value, Type $type, array $context = []): int
{
return (int) $value;
}

public function supportsConversion(mixed $value, Type $type, array $context = []): bool
{
return $type->isA(TypeIdentifier::INT) && \is_string($value);
}
}
7 changes: 7 additions & 0 deletions src/Api/UriVariableTransformerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@

use ApiPlatform\Exception\InvalidUriVariableException;

/**
* @deprecated TODO mtarld
*/
interface UriVariableTransformerInterface
{
/**
* Transforms the value of a URI variable (identifier) to its type.
*
* @deprecated TODO mtarld
*
* @param mixed $value The URI variable value to transform
* @param array $types The guessed type behind the URI variable
* @param array $context Options available to the transformer
Expand All @@ -31,6 +36,8 @@ public function transform(mixed $value, array $types, array $context = []);
/**
* Checks whether the value of a URI variable can be transformed to its type by this transformer.
*
* @deprecated TODO mtarld
*
* @param mixed $value The URI variable value to transform
* @param array $types The types to which the URI variable value should be transformed
* @param array $context Options available to the transformer
Expand Down
114 changes: 93 additions & 21 deletions src/Doctrine/Odm/PropertyInfo/DoctrineExtractor.php
6341
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyListExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
use Symfony\Component\PropertyInfo\Type;
use Symfony\Component\PropertyInfo\Type as LegacyType;
use Symfony\Component\TypeInfo\Type;
use Symfony\Component\TypeInfo\TypeIdentifier;

/**
* Extracts data using Doctrine MongoDB ODM metadata.
Expand Down Expand Up @@ -50,13 +52,70 @@ public function getProperties($class, array $context = []): ?array
return $metadata->getFieldNames();
}

public function getType($class, $property, array $context = []): ?Type
{
if (null === $metadata = $this->getMetadata($class)) {
return null;
}

if ($metadata->hasAssociation($property)) {
/** @var class-string|null */
$class = $metadata->getAssociationTargetClass($property);

if (null === $class) {
return null;
}

if ($metadata->isSingleValuedAssociation($property)) {
$nullable = $metadata instanceof MongoDbClassMetadata && $metadata->isNullable($property);

return $nullable ? Type::nullable(Type::object($class)) : Type::object($class);
}

return Type::collection(Type::object(Collection::class), Type::object($class), Type::int());
}

if (!$metadata->hasField($property)) {
return null;
}

$typeOfField = $metadata->getTypeOfField($property);

if (!$typeIdentifier = $this->getTypeIdentifier($typeOfField)) {
return null;
}

$nullable = $metadata instanceof MongoDbClassMetadata && $metadata->isNullable($property);
$enumType = null;

if (null !== $enumClass = $metadata instanceof MongoDbClassMetadata ? $metadata->getFieldMapping($property)['enumType'] ?? null : null) {
$enumType = $nullable ? Type::nullable(Type::enum($enumClass)) : Type::enum($enumClass);
}

$builtinType = $nullable ? Type::nullable(Type::builtin($typeIdentifier)) : Type::builtin($typeIdentifier);

return match ($typeOfField) {
MongoDbType::DATE => $nullable ? Type::nullable(Type::object(\DateTime::class)) : Type::object(\DateTime::class),
MongoDbType::DATE_IMMUTABLE => $nullable ? Type::nullable(Type::object(\DateTimeImmutable::class)) : Type::object(\DateTimeImmutable::class),
MongoDbType::HASH => $nullable ? Type::nullable(Type::array()) : Type::array(),
MongoDbType::COLLECTION => $nullable ? Type::nullable(Type::list()) : Type::list(),
MongoDbType::INT, MongoDbType::INTEGER, MongoDbType::STRING => $enumType ? $enumType : $builtinType,
default => $builtinType,
};
}

/**
* {@inheritdoc}
*
* @return Type[]|null
* @deprecated TODO mtarld
*
* @return LegacyType[]|null
*/
public function getTypes($class, $property, array $context = []): ?array
{
// TODO mtarld
// trigger_deprecation('symfony/property-info', '7.1', 'The "%s()" method is deprecated, use "%s::getType()" instead.', __METHOD__, self::class);

if (null === $metadata = $this->getMetadata($class)) {
return null;
}
Expand All @@ -72,19 +131,19 @@ public function getTypes($class, $property, array $context = []): ?array
if ($metadata->isSingleValuedAssociation($property)) {
$nullable = $metadata instanceof MongoDbClassMetadata && $metadata->isNullable($property);

return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $class)];
return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, $class)];
}

$collectionKeyType = Type::BUILTIN_TYPE_INT;
$collectionKeyType = LegacyType::BUILTIN_TYPE_INT;

return [
new Type(
Type::BUILTIN_TYPE_OBJECT,
new LegacyType(
LegacyType::BUILTIN_TYPE_OBJECT,
false,
Collection::class,
true,
new Type($collectionKeyType),
new Type(Type::BUILTIN_TYPE_OBJECT, false, $class)
new LegacyType($collectionKeyType),
new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, $class)
),
];
}
Expand All @@ -94,28 +153,28 @@ public function getTypes($class, $property, array $context = []): ?array
$nullable = $metadata instanceof MongoDbClassMetadata && $metadata->isNullable($property);
$enumType = null;
if (null !== $enumClass = $metadata instanceof MongoDbClassMetadata ? $metadata->getFieldMapping($property)['enumType'] ?? null : null) {
$enumType = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $enumClass);
$enumType = new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, $enumClass);
}

switch ($typeOfField) {
case MongoDbType::DATE:
return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, \DateTime::class)];
return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, \DateTime::class)];
case MongoDbType::DATE_IMMUTABLE:
return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, \DateTimeImmutable::class)];
return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, \DateTimeImmutable::class)];
case MongoDbType::HASH:
return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true)];
return [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, $nullable, null, true)];
case MongoDbType::COLLECTION:
return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, new Type(Type::BUILTIN_TYPE_INT))];
return [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, $nullable, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT))];
case MongoDbType::INT:
case MongoDbType::STRING:
if ($enumType) {
return [$enumType];
}
}

$builtinType = $this->getPhpType($typeOfField);
$builtinType = $this->getPhpTypeLegacy($typeOfField);

return $builtinType ? [new Type($builtinType, $nullable)] : null;
return $builtinType ? [new LegacyType($builtinType, $nullable)] : null;
}

return null;
Expand Down Expand Up @@ -155,15 +214,28 @@ private function getMetadata(string $class): ?ClassMetadata
}

/**
* Gets the corresponding built-in PHP type.
* Gets the corresponding built-in PHP type identifier.
*/
private function getPhpType(string $doctrineType): ?string
private function getTypeIdentifier(string $doctrineType): ?TypeIdentifier
{
return match ($doctrineType) {
MongoDbType::INTEGER, MongoDbType::INT, MongoDbType::INTID, MongoDbType::KEY => TypeIdentifier::INT,
MongoDbType::FLOAT => TypeIdentifier::FLOAT,
MongoDbType::STRING, MongoDbType::ID, MongoDbType::OBJECTID, MongoDbType::TIMESTAMP, MongoDbType::BINDATA, MongoDbType::BINDATABYTEARRAY, MongoDbType::BINDATACUSTOM, MongoDbType::BINDATAFUNC, MongoDbType::BINDATAMD5, MongoDbType::BINDATAUUID, MongoDbType::BINDATAUUIDRFC4122 => TypeIdentifier::STRING,
MongoDbType::BOOLEAN, MongoDbType::BOOL => TypeIdentifier::BOOL,
MongoDbType::DATE, MongoDbType::DATE_IMMUTABLE => TypeIdentifier::OBJECT,
MongoDbType::HASH, MongoDbType::COLLECTION => TypeIdentifier::ARRAY,
default => null,
};
}

private function getPhpTypeLegacy(string $doctrineType): ?string
{
return match ($doctrineType) {
MongoDbType::INTEGER, MongoDbType::INT, MongoDbType::INTID, MongoDbType::KEY => Type::BUILTIN_TYPE_INT,
MongoDbType::FLOAT => Type::BUILTIN_TYPE_FLOAT,
MongoDbType::STRING, MongoDbType::ID, MongoDbType::OBJECTID, MongoDbType::TIMESTAMP, MongoDbType::BINDATA, MongoDbType::BINDATABYTEARRAY, MongoDbType::BINDATACUSTOM, MongoDbType::BINDATAFUNC, MongoDbType::BINDATAMD5, MongoDbType::BINDATAUUID, MongoDbType::BINDATAUUIDRFC4122 => Type::BUILTIN_TYPE_STRING,
MongoDbType::BOOLEAN, MongoDbType::BOOL => Type::BUILTIN_TYPE_BOOL,
MongoDbType::INTEGER, MongoDbType::INT, MongoDbType::INTID, MongoDbType::KEY => LegacyType::BUILTIN_TYPE_INT,
MongoDbType::FLOAT => LegacyType::BUILTIN_TYPE_FLOAT,
MongoDbType::STRING, MongoDbType::ID, MongoDbType::OBJECTID, MongoDbType::TIMESTAMP, MongoDbType::BINDATA, MongoDbType::BINDATABYTEARRAY, MongoDbType::BINDATACUSTOM, MongoDbType::BINDATAFUNC, MongoDbType::BINDATAMD5, MongoDbType::BINDATAUUID, MongoDbType::BINDATAUUIDRFC4122 => LegacyType::BUILTIN_TYPE_STRING,
MongoDbType::BOOLEAN, MongoDbType::BOOL => LegacyType::BUILTIN_TYPE_BOOL,
default => null,
};
}
Expand Down
Loading
0