Deprecated: Constant E_STRICT is deprecated in /home/normanv/www/annuairepro/vendor/symfony/error-handler/ErrorHandler.php on line 58

Deprecated: Constant E_STRICT is deprecated in /home/normanv/www/annuairepro/vendor/symfony/error-handler/ErrorHandler.php on line 76
Symfony Profiler

vendor/symfony/serializer/Normalizer/AbstractNormalizer.php line 200

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\Serializer\Exception\CircularReferenceException;
  12. use Symfony\Component\Serializer\Exception\InvalidArgumentException;
  13. use Symfony\Component\Serializer\Exception\LogicException;
  14. use Symfony\Component\Serializer\Exception\MissingConstructorArgumentsException;
  15. use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
  16. use Symfony\Component\Serializer\Exception\RuntimeException;
  17. use Symfony\Component\Serializer\Mapping\AttributeMetadataInterface;
  18. use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
  19. use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
  20. use Symfony\Component\Serializer\SerializerAwareInterface;
  21. use Symfony\Component\Serializer\SerializerAwareTrait;
  22. /**
  23.  * Normalizer implementation.
  24.  *
  25.  * @author Kévin Dunglas <dunglas@gmail.com>
  26.  */
  27. abstract class AbstractNormalizer implements NormalizerInterfaceDenormalizerInterfaceSerializerAwareInterfaceCacheableSupportsMethodInterface
  28. {
  29.     use ObjectToPopulateTrait;
  30.     use SerializerAwareTrait;
  31.     /* constants to configure the context */
  32.     /**
  33.      * How many loops of circular reference to allow while normalizing.
  34.      *
  35.      * The default value of 1 means that when we encounter the same object a
  36.      * second time, we consider that a circular reference.
  37.      *
  38.      * You can raise this value for special cases, e.g. in combination with the
  39.      * max depth setting of the object normalizer.
  40.      */
  41.     public const CIRCULAR_REFERENCE_LIMIT 'circular_reference_limit';
  42.     /**
  43.      * Instead of creating a new instance of an object, update the specified object.
  44.      *
  45.      * If you have a nested structure, child objects will be overwritten with
  46.      * new instances unless you set DEEP_OBJECT_TO_POPULATE to true.
  47.      */
  48.     public const OBJECT_TO_POPULATE 'object_to_populate';
  49.     /**
  50.      * Only (de)normalize attributes that are in the specified groups.
  51.      */
  52.     public const GROUPS 'groups';
  53.     /**
  54.      * Limit (de)normalize to the specified names.
  55.      *
  56.      * For nested structures, this list needs to reflect the object tree.
  57.      */
  58.     public const ATTRIBUTES 'attributes';
  59.     /**
  60.      * If ATTRIBUTES are specified, and the source has fields that are not part of that list,
  61.      * either ignore those attributes (true) or throw an ExtraAttributesException (false).
  62.      */
  63.     public const ALLOW_EXTRA_ATTRIBUTES 'allow_extra_attributes';
  64.     /**
  65.      * Hashmap of default values for constructor arguments.
  66.      *
  67.      * The names need to match the parameter names in the constructor arguments.
  68.      */
  69.     public const DEFAULT_CONSTRUCTOR_ARGUMENTS 'default_constructor_arguments';
  70.     /**
  71.      * Hashmap of field name => callable to (de)normalize this field.
  72.      *
  73.      * The callable is called if the field is encountered with the arguments:
  74.      *
  75.      * - mixed         $attributeValue value of this field
  76.      * - object|string $object         the whole object being normalized or the object's class being denormalized
  77.      * - string        $attributeName  name of the attribute being (de)normalized
  78.      * - string        $format         the requested format
  79.      * - array         $context        the serialization context
  80.      */
  81.     public const CALLBACKS 'callbacks';
  82.     /**
  83.      * Handler to call when a circular reference has been detected.
  84.      *
  85.      * If you specify no handler, a CircularReferenceException is thrown.
  86.      *
  87.      * The method will be called with ($object, $format, $context) and its
  88.      * return value is returned as the result of the normalize call.
  89.      */
  90.     public const CIRCULAR_REFERENCE_HANDLER 'circular_reference_handler';
  91.     /**
  92.      * Skip the specified attributes when normalizing an object tree.
  93.      *
  94.      * This list is applied to each element of nested structures.
  95.      *
  96.      * Note: The behaviour for nested structures is different from ATTRIBUTES
  97.      * for historical reason. Aligning the behaviour would be a BC break.
  98.      */
  99.     public const IGNORED_ATTRIBUTES 'ignored_attributes';
  100.     /**
  101.      * @internal
  102.      */
  103.     protected const CIRCULAR_REFERENCE_LIMIT_COUNTERS 'circular_reference_limit_counters';
  104.     protected $defaultContext = [
  105.         self::ALLOW_EXTRA_ATTRIBUTES => true,
  106.         self::CIRCULAR_REFERENCE_HANDLER => null,
  107.         self::CIRCULAR_REFERENCE_LIMIT => 1,
  108.         self::IGNORED_ATTRIBUTES => [],
  109.     ];
  110.     /**
  111.      * @var ClassMetadataFactoryInterface|null
  112.      */
  113.     protected $classMetadataFactory;
  114.     /**
  115.      * @var NameConverterInterface|null
  116.      */
  117.     protected $nameConverter;
  118.     /**
  119.      * Sets the {@link ClassMetadataFactoryInterface} to use.
  120.      */
  121.     public function __construct(ClassMetadataFactoryInterface $classMetadataFactory nullNameConverterInterface $nameConverter null, array $defaultContext = [])
  122.     {
  123.         $this->classMetadataFactory $classMetadataFactory;
  124.         $this->nameConverter $nameConverter;
  125.         $this->defaultContext array_merge($this->defaultContext$defaultContext);
  126.         $this->validateCallbackContext($this->defaultContext'default');
  127.         if (isset($this->defaultContext[self::CIRCULAR_REFERENCE_HANDLER]) && !\is_callable($this->defaultContext[self::CIRCULAR_REFERENCE_HANDLER])) {
  128.             throw new InvalidArgumentException(sprintf('Invalid callback found in the "%s" default context option.'self::CIRCULAR_REFERENCE_HANDLER));
  129.         }
  130.     }
  131.     /**
  132.      * {@inheritdoc}
  133.      */
  134.     public function hasCacheableSupportsMethod(): bool
  135.     {
  136.         return false;
  137.     }
  138.     /**
  139.      * Detects if the configured circular reference limit is reached.
  140.      *
  141.      * @return bool
  142.      *
  143.      * @throws CircularReferenceException
  144.      */
  145.     protected function isCircularReference(object $object, array &$context)
  146.     {
  147.         $objectHash spl_object_hash($object);
  148.         $circularReferenceLimit $context[self::CIRCULAR_REFERENCE_LIMIT] ?? $this->defaultContext[self::CIRCULAR_REFERENCE_LIMIT];
  149.         if (isset($context[self::CIRCULAR_REFERENCE_LIMIT_COUNTERS][$objectHash])) {
  150.             if ($context[self::CIRCULAR_REFERENCE_LIMIT_COUNTERS][$objectHash] >= $circularReferenceLimit) {
  151.                 unset($context[self::CIRCULAR_REFERENCE_LIMIT_COUNTERS][$objectHash]);
  152.                 return true;
  153.             }
  154.             ++$context[self::CIRCULAR_REFERENCE_LIMIT_COUNTERS][$objectHash];
  155.         } else {
  156.             $context[self::CIRCULAR_REFERENCE_LIMIT_COUNTERS][$objectHash] = 1;
  157.         }
  158.         return false;
  159.     }
  160.     /**
  161.      * Handles a circular reference.
  162.      *
  163.      * If a circular reference handler is set, it will be called. Otherwise, a
  164.      * {@class CircularReferenceException} will be thrown.
  165.      *
  166.      * @final
  167.      *
  168.      * @return mixed
  169.      *
  170.      * @throws CircularReferenceException
  171.      */
  172.     protected function handleCircularReference(object $objectstring $format null, array $context = [])
  173.     {
  174.         $circularReferenceHandler $context[self::CIRCULAR_REFERENCE_HANDLER] ?? $this->defaultContext[self::CIRCULAR_REFERENCE_HANDLER];
  175.         if ($circularReferenceHandler) {
  176.             return $circularReferenceHandler($object$format$context);
  177.         }
  178.         throw new CircularReferenceException(sprintf('A circular reference has been detected when serializing the object of class "%s" (configured limit: %d).'get_debug_type($object), $context[self::CIRCULAR_REFERENCE_LIMIT] ?? $this->defaultContext[self::CIRCULAR_REFERENCE_LIMIT]));
  179.     }
  180.     /**
  181.      * Gets attributes to normalize using groups.
  182.      *
  183.      * @param string|object $classOrObject
  184.      * @param bool          $attributesAsString If false, return an array of {@link AttributeMetadataInterface}
  185.      *
  186.      * @return string[]|AttributeMetadataInterface[]|bool
  187.      *
  188.      * @throws LogicException if the 'allow_extra_attributes' context variable is false and no class metadata factory is provided
  189.      */
  190.     protected function getAllowedAttributes($classOrObject, array $contextbool $attributesAsString false)
  191.     {
  192.         $allowExtraAttributes $context[self::ALLOW_EXTRA_ATTRIBUTES] ?? $this->defaultContext[self::ALLOW_EXTRA_ATTRIBUTES];
  193.         if (!$this->classMetadataFactory) {
  194.             if (!$allowExtraAttributes) {
  195.                 throw new LogicException(sprintf('A class metadata factory must be provided in the constructor when setting "%s" to false.'self::ALLOW_EXTRA_ATTRIBUTES));
  196.             }
  197.             return false;
  198.         }
  199.         $groups $this->getGroups($context);
  200.         $allowedAttributes = [];
  201.         $ignoreUsed false;
  202.         foreach ($this->classMetadataFactory->getMetadataFor($classOrObject)->getAttributesMetadata() as $attributeMetadata) {
  203.             if ($ignore $attributeMetadata->isIgnored()) {
  204.                 $ignoreUsed true;
  205.             }
  206.             // If you update this check, update accordingly the one in Symfony\Component\PropertyInfo\Extractor\SerializerExtractor::getProperties()
  207.             if (
  208.                 !$ignore &&
  209.                 ([] === $groups || array_intersect(array_merge($attributeMetadata->getGroups(), ['*']), $groups)) &&
  210.                 $this->isAllowedAttribute($classOrObject$name $attributeMetadata->getName(), null$context)
  211.             ) {
  212.                 $allowedAttributes[] = $attributesAsString $name $attributeMetadata;
  213.             }
  214.         }
  215.         if (!$ignoreUsed && [] === $groups && $allowExtraAttributes) {
  216.             // Backward Compatibility with the code using this method written before the introduction of @Ignore
  217.             return false;
  218.         }
  219.         return $allowedAttributes;
  220.     }
  221.     protected function getGroups(array $context): array
  222.     {
  223.         $groups $context[self::GROUPS] ?? $this->defaultContext[self::GROUPS] ?? [];
  224.         return \is_scalar($groups) ? (array) $groups $groups;
  225.     }
  226.     /**
  227.      * Is this attribute allowed?
  228.      *
  229.      * @param object|string $classOrObject
  230.      *
  231.      * @return bool
  232.      */
  233.     protected function isAllowedAttribute($classOrObjectstring $attributestring $format null, array $context = [])
  234.     {
  235.         $ignoredAttributes $context[self::IGNORED_ATTRIBUTES] ?? $this->defaultContext[self::IGNORED_ATTRIBUTES];
  236.         if (\in_array($attribute$ignoredAttributes)) {
  237.             return false;
  238.         }
  239.         $attributes $context[self::ATTRIBUTES] ?? $this->defaultContext[self::ATTRIBUTES] ?? null;
  240.         if (isset($attributes[$attribute])) {
  241.             // Nested attributes
  242.             return true;
  243.         }
  244.         if (\is_array($attributes)) {
  245.             return \in_array($attribute$attributestrue);
  246.         }
  247.         return true;
  248.     }
  249.     /**
  250.      * Normalizes the given data to an array. It's particularly useful during
  251.      * the denormalization process.
  252.      *
  253.      * @param object|array $data
  254.      *
  255.      * @return array
  256.      */
  257.     protected function prepareForDenormalization($data)
  258.     {
  259.         return (array) $data;
  260.     }
  261.     /**
  262.      * Returns the method to use to construct an object. This method must be either
  263.      * the object constructor or static.
  264.      *
  265.      * @param array|bool $allowedAttributes
  266.      *
  267.      * @return \ReflectionMethod|null
  268.      */
  269.     protected function getConstructor(array &$datastring $class, array &$context\ReflectionClass $reflectionClass$allowedAttributes)
  270.     {
  271.         return $reflectionClass->getConstructor();
  272.     }
  273.     /**
  274.      * Instantiates an object using constructor parameters when needed.
  275.      *
  276.      * This method also allows to denormalize data into an existing object if
  277.      * it is present in the context with the object_to_populate. This object
  278.      * is removed from the context before being returned to avoid side effects
  279.      * when recursively normalizing an object graph.
  280.      *
  281.      * @param array|bool $allowedAttributes
  282.      *
  283.      * @return object
  284.      *
  285.      * @throws RuntimeException
  286.      * @throws MissingConstructorArgumentsException
  287.      */
  288.     protected function instantiateObject(array &$datastring $class, array &$context\ReflectionClass $reflectionClass$allowedAttributesstring $format null)
  289.     {
  290.         if (null !== $object $this->extractObjectToPopulate($class$contextself::OBJECT_TO_POPULATE)) {
  291.             unset($context[self::OBJECT_TO_POPULATE]);
  292.             return $object;
  293.         }
  294.         // clean up even if no match
  295.         unset($context[static::OBJECT_TO_POPULATE]);
  296.         $constructor $this->getConstructor($data$class$context$reflectionClass$allowedAttributes);
  297.         if ($constructor) {
  298.             $context['has_constructor'] = true;
  299.             if (true !== $constructor->isPublic()) {
  300.                 return $reflectionClass->newInstanceWithoutConstructor();
  301.             }
  302.             $constructorParameters $constructor->getParameters();
  303.             $missingConstructorArguments = [];
  304.             $params = [];
  305.             foreach ($constructorParameters as $constructorParameter) {
  306.                 $paramName $constructorParameter->name;
  307.                 $key $this->nameConverter $this->nameConverter->normalize($paramName$class$format$context) : $paramName;
  308.                 $allowed false === $allowedAttributes || \in_array($paramName$allowedAttributes);
  309.                 $ignored = !$this->isAllowedAttribute($class$paramName$format$context);
  310.                 if ($constructorParameter->isVariadic()) {
  311.                     if ($allowed && !$ignored && (isset($data[$key]) || \array_key_exists($key$data))) {
  312.                         if (!\is_array($data[$key])) {
  313.                             throw new RuntimeException(sprintf('Cannot create an instance of "%s" from serialized data because the variadic parameter "%s" can only accept an array.'$class$constructorParameter->name));
  314.                         }
  315.                         $variadicParameters = [];
  316.                         foreach ($data[$key] as $parameterKey => $parameterData) {
  317.                             $variadicParameters[$parameterKey] = $this->denormalizeParameter($reflectionClass$constructorParameter$paramName$parameterData$context$format);
  318.                         }
  319.                         $params array_merge($params$variadicParameters);
  320.                         unset($data[$key]);
  321.                     }
  322.                 } elseif ($allowed && !$ignored && (isset($data[$key]) || \array_key_exists($key$data))) {
  323.                     $parameterData $data[$key];
  324.                     if (null === $parameterData && $constructorParameter->allowsNull()) {
  325.                         $params[] = null;
  326.                         // Don't run set for a parameter passed to the constructor
  327.                         unset($data[$key]);
  328.                         continue;
  329.                     }
  330.                     // Don't run set for a parameter passed to the constructor
  331.                     try {
  332.                         $params[] = $this->denormalizeParameter($reflectionClass$constructorParameter$paramName$parameterData$context$format);
  333.                     } catch (NotNormalizableValueException $exception) {
  334.                         if (!isset($context['not_normalizable_value_exceptions'])) {
  335.                             throw $exception;
  336.                         }
  337.                         $context['not_normalizable_value_exceptions'][] = $exception;
  338.                         $params[] = $parameterData;
  339.                     }
  340.                     unset($data[$key]);
  341.                 } elseif (\array_key_exists($key$context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class] ?? [])) {
  342.                     $params[] = $context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class][$key];
  343.                 } elseif (\array_key_exists($key$this->defaultContext[self::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class] ?? [])) {
  344.                     $params[] = $this->defaultContext[self::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class][$key];
  345.                 } elseif ($constructorParameter->isDefaultValueAvailable()) {
  346.                     $params[] = $constructorParameter->getDefaultValue();
  347.                 } elseif ($constructorParameter->hasType() && $constructorParameter->getType()->allowsNull()) {
  348.                     $params[] = null;
  349.                 } else {
  350.                     if (!isset($context['not_normalizable_value_exceptions'])) {
  351.                         $missingConstructorArguments[] = $constructorParameter->name;
  352.                         continue;
  353.                     }
  354.                     $exception NotNormalizableValueException::createForUnexpectedDataType(
  355.                         sprintf('Failed to create object because the class misses the "%s" property.'$constructorParameter->name),
  356.                         $data,
  357.                         ['unknown'],
  358.                         $context['deserialization_path'] ?? null,
  359.                         true
  360.                     );
  361.                     $context['not_normalizable_value_exceptions'][] = $exception;
  362.                 }
  363.             }
  364.             if ($missingConstructorArguments) {
  365.                 throw new MissingConstructorArgumentsException(sprintf('Cannot create an instance of "%s" from serialized data because its constructor requires the following parameters to be present : "$%s".'$classimplode('", "$'$missingConstructorArguments)), 0null$missingConstructorArguments);
  366.             }
  367.             if (!$constructor->isConstructor()) {
  368.                 return $constructor->invokeArgs(null$params);
  369.             }
  370.             try {
  371.                 return $reflectionClass->newInstanceArgs($params);
  372.             } catch (\TypeError $e) {
  373.                 if (!isset($context['not_normalizable_value_exceptions'])) {
  374.                     throw $e;
  375.                 }
  376.                 return $reflectionClass->newInstanceWithoutConstructor();
  377.             }
  378.         }
  379.         unset($context['has_constructor']);
  380.         return new $class();
  381.     }
  382.     /**
  383.      * @internal
  384.      */
  385.     protected function denormalizeParameter(\ReflectionClass $class\ReflectionParameter $parameterstring $parameterName$parameterData, array $contextstring $format null)
  386.     {
  387.         try {
  388.             if (($parameterType $parameter->getType()) instanceof \ReflectionNamedType && !$parameterType->isBuiltin()) {
  389.                 $parameterClass $parameterType->getName();
  390.                 new \ReflectionClass($parameterClass); // throws a \ReflectionException if the class doesn't exist
  391.                 if (!$this->serializer instanceof DenormalizerInterface) {
  392.                     throw new LogicException(sprintf('Cannot create an instance of "%s" from serialized data because the serializer inject in "%s" is not a denormalizer.'$parameterClass, static::class));
  393.                 }
  394.                 $parameterData $this->serializer->denormalize($parameterData$parameterClass$format$this->createChildContext($context$parameterName$format));
  395.             }
  396.         } catch (\ReflectionException $e) {
  397.             throw new RuntimeException(sprintf('Could not determine the class of the parameter "%s".'$parameterName), 0$e);
  398.         } catch (MissingConstructorArgumentsException $e) {
  399.             if (!$parameter->getType()->allowsNull()) {
  400.                 throw $e;
  401.             }
  402.             return null;
  403.         }
  404.         return $this->applyCallbacks($parameterData$class->getName(), $parameterName$format$context);
  405.     }
  406.     /**
  407.      * @internal
  408.      */
  409.     protected function createChildContext(array $parentContextstring $attribute, ?string $format): array
  410.     {
  411.         if (isset($parentContext[self::ATTRIBUTES][$attribute])) {
  412.             $parentContext[self::ATTRIBUTES] = $parentContext[self::ATTRIBUTES][$attribute];
  413.         } else {
  414.             unset($parentContext[self::ATTRIBUTES]);
  415.         }
  416.         return $parentContext;
  417.     }
  418.     /**
  419.      * Validate callbacks set in context.
  420.      *
  421.      * @param string $contextType Used to specify which context is invalid in exceptions
  422.      *
  423.      * @throws InvalidArgumentException
  424.      */
  425.     final protected function validateCallbackContext(array $contextstring $contextType ''): void
  426.     {
  427.         if (!isset($context[self::CALLBACKS])) {
  428.             return;
  429.         }
  430.         if (!\is_array($context[self::CALLBACKS])) {
  431.             throw new InvalidArgumentException(sprintf('The "%s"%s context option must be an array of callables.'self::CALLBACKS'' !== $contextType $contextType''));
  432.         }
  433.         foreach ($context[self::CALLBACKS] as $attribute => $callback) {
  434.             if (!\is_callable($callback)) {
  435.                 throw new InvalidArgumentException(sprintf('Invalid callback found for attribute "%s" in the "%s"%s context option.'$attributeself::CALLBACKS'' !== $contextType $contextType''));
  436.             }
  437.         }
  438.     }
  439.     /**
  440.      * Apply callbacks set in context.
  441.      *
  442.      * @param mixed         $value
  443.      * @param object|string $object Can be either the object being normalizing or the object's class being denormalized
  444.      *
  445.      * @return mixed
  446.      */
  447.     final protected function applyCallbacks($value$objectstring $attribute, ?string $format, array $context)
  448.     {
  449.         /**
  450.          * @var callable|null
  451.          */
  452.         $callback $context[self::CALLBACKS][$attribute] ?? $this->defaultContext[self::CALLBACKS][$attribute] ?? null;
  453.         return $callback $callback($value$object$attribute$format$context) : $value;
  454.     }
  455. }