vendor/symfony/serializer/Normalizer/ObjectNormalizer.php line 127

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Serializer\Normalizer;
  11. use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
  12. use Symfony\Component\PropertyAccess\PropertyAccess;
  13. use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
  14. use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
  15. use Symfony\Component\Serializer\Exception\LogicException;
  16. use Symfony\Component\Serializer\Mapping\AttributeMetadata;
  17. use Symfony\Component\Serializer\Mapping\ClassDiscriminatorResolverInterface;
  18. use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
  19. use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
  20. /**
  21.  * Converts between objects and arrays using the PropertyAccess component.
  22.  *
  23.  * @author Kévin Dunglas <dunglas@gmail.com>
  24.  */
  25. class ObjectNormalizer extends AbstractObjectNormalizer
  26. {
  27.     protected $propertyAccessor;
  28.     private $discriminatorCache = [];
  29.     private $objectClassResolver;
  30.     public function __construct(ClassMetadataFactoryInterface $classMetadataFactory nullNameConverterInterface $nameConverter nullPropertyAccessorInterface $propertyAccessor nullPropertyTypeExtractorInterface $propertyTypeExtractor nullClassDiscriminatorResolverInterface $classDiscriminatorResolver null, callable $objectClassResolver null, array $defaultContext = [])
  31.     {
  32.         if (!class_exists(PropertyAccess::class)) {
  33.             throw new LogicException('The ObjectNormalizer class requires the "PropertyAccess" component. Install "symfony/property-access" to use it.');
  34.         }
  35.         parent::__construct($classMetadataFactory$nameConverter$propertyTypeExtractor$classDiscriminatorResolver$objectClassResolver$defaultContext);
  36.         $this->propertyAccessor $propertyAccessor ?: PropertyAccess::createPropertyAccessor();
  37.         $this->objectClassResolver $objectClassResolver ?? function ($class) {
  38.             return \is_object($class) ? \get_class($class) : $class;
  39.         };
  40.     }
  41.     /**
  42.      * {@inheritdoc}
  43.      */
  44.     public function hasCacheableSupportsMethod(): bool
  45.     {
  46.         return __CLASS__ === static::class;
  47.     }
  48.     /**
  49.      * {@inheritdoc}
  50.      */
  51.     protected function extractAttributes($object$format null, array $context = [])
  52.     {
  53.         // If not using groups, detect manually
  54.         $attributes = [];
  55.         // methods
  56.         $class = ($this->objectClassResolver)($object);
  57.         $reflClass = new \ReflectionClass($class);
  58.         foreach ($reflClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflMethod) {
  59.             if (
  60.                 !== $reflMethod->getNumberOfRequiredParameters() ||
  61.                 $reflMethod->isStatic() ||
  62.                 $reflMethod->isConstructor() ||
  63.                 $reflMethod->isDestructor()
  64.             ) {
  65.                 continue;
  66.             }
  67.             $name $reflMethod->name;
  68.             $attributeName null;
  69.             if (=== strpos($name'get') || === strpos($name'has')) {
  70.                 // getters and hassers
  71.                 $attributeName substr($name3);
  72.                 if (!$reflClass->hasProperty($attributeName)) {
  73.                     $attributeName lcfirst($attributeName);
  74.                 }
  75.             } elseif (=== strpos($name'is')) {
  76.                 // issers
  77.                 $attributeName substr($name2);
  78.                 if (!$reflClass->hasProperty($attributeName)) {
  79.                     $attributeName lcfirst($attributeName);
  80.                 }
  81.             }
  82.             if (null !== $attributeName && $this->isAllowedAttribute($object$attributeName$format$context)) {
  83.                 $attributes[$attributeName] = true;
  84.             }
  85.         }
  86.         $checkPropertyInitialization = \PHP_VERSION_ID >= 70400;
  87.         // properties
  88.         foreach ($reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $reflProperty) {
  89.             if ($checkPropertyInitialization && !$reflProperty->isInitialized($object)) {
  90.                 continue;
  91.             }
  92.             if ($reflProperty->isStatic() || !$this->isAllowedAttribute($object$reflProperty->name$format$context)) {
  93.                 continue;
  94.             }
  95.             $attributes[$reflProperty->name] = true;
  96.         }
  97.         return array_keys($attributes);
  98.     }
  99.     /**
  100.      * {@inheritdoc}
  101.      */
  102.     protected function getAttributeValue($object$attribute$format null, array $context = [])
  103.     {
  104.         $cacheKey = \get_class($object);
  105.         if (!\array_key_exists($cacheKey$this->discriminatorCache)) {
  106.             $this->discriminatorCache[$cacheKey] = null;
  107.             if (null !== $this->classDiscriminatorResolver) {
  108.                 $mapping $this->classDiscriminatorResolver->getMappingForMappedObject($object);
  109.                 $this->discriminatorCache[$cacheKey] = null === $mapping null $mapping->getTypeProperty();
  110.             }
  111.         }
  112.         return $attribute === $this->discriminatorCache[$cacheKey] ? $this->classDiscriminatorResolver->getTypeForMappedObject($object) : $this->propertyAccessor->getValue($object$attribute);
  113.     }
  114.     /**
  115.      * {@inheritdoc}
  116.      */
  117.     protected function setAttributeValue($object$attribute$value$format null, array $context = [])
  118.     {
  119.         try {
  120.             $this->propertyAccessor->setValue($object$attribute$value);
  121.         } catch (NoSuchPropertyException $exception) {
  122.             // Properties not found are ignored
  123.         }
  124.     }
  125.     /**
  126.      * {@inheritdoc}
  127.      */
  128.     protected function getAllowedAttributes($classOrObject, array $context$attributesAsString false)
  129.     {
  130.         if (false === $allowedAttributes parent::getAllowedAttributes($classOrObject$context$attributesAsString)) {
  131.             return false;
  132.         }
  133.         if (null !== $this->classDiscriminatorResolver) {
  134.             $class = \is_object($classOrObject) ? \get_class($classOrObject) : $classOrObject;
  135.             if (null !== $discriminatorMapping $this->classDiscriminatorResolver->getMappingForMappedObject($classOrObject)) {
  136.                 $allowedAttributes[] = $attributesAsString $discriminatorMapping->getTypeProperty() : new AttributeMetadata($discriminatorMapping->getTypeProperty());
  137.             }
  138.             if (null !== $discriminatorMapping $this->classDiscriminatorResolver->getMappingForClass($class)) {
  139.                 foreach ($discriminatorMapping->getTypesMapping() as $mappedClass) {
  140.                     $allowedAttributes array_merge($allowedAttributesparent::getAllowedAttributes($mappedClass$context$attributesAsString));
  141.                 }
  142.             }
  143.         }
  144.         return $allowedAttributes;
  145.     }
  146. }