vendor/jms/serializer/src/Metadata/Driver/TypedPropertiesDriver.php line 66

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace JMS\Serializer\Metadata\Driver;
  4. use JMS\Serializer\Metadata\ClassMetadata as SerializerClassMetadata;
  5. use JMS\Serializer\Metadata\ExpressionPropertyMetadata;
  6. use JMS\Serializer\Metadata\PropertyMetadata;
  7. use JMS\Serializer\Metadata\StaticPropertyMetadata;
  8. use JMS\Serializer\Metadata\VirtualPropertyMetadata;
  9. use JMS\Serializer\Type\Parser;
  10. use JMS\Serializer\Type\ParserInterface;
  11. use Metadata\ClassMetadata;
  12. use Metadata\Driver\DriverInterface;
  13. use ReflectionClass;
  14. use ReflectionException;
  15. use ReflectionProperty;
  16. class TypedPropertiesDriver implements DriverInterface
  17. {
  18.     /**
  19.      * @var DriverInterface
  20.      */
  21.     protected $delegate;
  22.     /**
  23.      * @var ParserInterface
  24.      */
  25.     protected $typeParser;
  26.     /**
  27.      * @var string[]
  28.      */
  29.     private $allowList;
  30.     /**
  31.      * @param string[] $allowList
  32.      */
  33.     public function __construct(DriverInterface $delegate, ?ParserInterface $typeParser null, array $allowList = [])
  34.     {
  35.         $this->delegate $delegate;
  36.         $this->typeParser $typeParser ?: new Parser();
  37.         $this->allowList array_merge($allowList$this->getDefaultWhiteList());
  38.     }
  39.     private function getDefaultWhiteList(): array
  40.     {
  41.         return [
  42.             'int',
  43.             'float',
  44.             'bool',
  45.             'boolean',
  46.             'string',
  47.             'double',
  48.             'iterable',
  49.             'resource',
  50.         ];
  51.     }
  52.     /**
  53.      * @return SerializerClassMetadata|null
  54.      */
  55.     public function loadMetadataForClass(ReflectionClass $class): ?ClassMetadata
  56.     {
  57.         $classMetadata $this->delegate->loadMetadataForClass($class);
  58.         \assert($classMetadata instanceof SerializerClassMetadata);
  59.         if (PHP_VERSION_ID <= 70400) {
  60.             return $classMetadata;
  61.         }
  62.         // We base our scan on the internal driver's property list so that we
  63.         // respect any internal allow/blocklist like in the AnnotationDriver
  64.         foreach ($classMetadata->propertyMetadata as $propertyMetadata) {
  65.             // If the inner driver provides a type, don't guess anymore.
  66.             if ($propertyMetadata->type || $this->isVirtualProperty($propertyMetadata)) {
  67.                 continue;
  68.             }
  69.             try {
  70.                 $propertyReflection $this->getReflection($propertyMetadata);
  71.                 $reflectionType $propertyReflection->getType();
  72.                 if ($this->shouldTypeHint($reflectionType)) {
  73.                     $type $reflectionType->getName();
  74.                     $propertyMetadata->setType($this->typeParser->parse($type));
  75.                 }
  76.             } catch (ReflectionException $e) {
  77.                 continue;
  78.             }
  79.         }
  80.         return $classMetadata;
  81.     }
  82.     private function isVirtualProperty(PropertyMetadata $propertyMetadata): bool
  83.     {
  84.         return $propertyMetadata instanceof VirtualPropertyMetadata
  85.             || $propertyMetadata instanceof StaticPropertyMetadata
  86.             || $propertyMetadata instanceof ExpressionPropertyMetadata;
  87.     }
  88.     private function getReflection(PropertyMetadata $propertyMetadata): ReflectionProperty
  89.     {
  90.         return new ReflectionProperty($propertyMetadata->class$propertyMetadata->name);
  91.     }
  92.     /**
  93.      * @phpstan-assert-if-true \ReflectionNamedType $reflectionType
  94.      */
  95.     private function shouldTypeHint(?\ReflectionType $reflectionType): bool
  96.     {
  97.         if (!$reflectionType instanceof \ReflectionNamedType) {
  98.             return false;
  99.         }
  100.         if (in_array($reflectionType->getName(), $this->allowListtrue)) {
  101.             return true;
  102.         }
  103.         return class_exists($reflectionType->getName())
  104.             || interface_exists($reflectionType->getName());
  105.     }
  106. }