init
This commit is contained in:
594
backend/vendor/symfony/serializer/Normalizer/AbstractNormalizer.php
vendored
Normal file
594
backend/vendor/symfony/serializer/Normalizer/AbstractNormalizer.php
vendored
Normal file
@@ -0,0 +1,594 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Exception\CircularReferenceException;
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\LogicException;
|
||||
use Symfony\Component\Serializer\Exception\MissingConstructorArgumentsException;
|
||||
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
|
||||
use Symfony\Component\Serializer\Exception\RuntimeException;
|
||||
use Symfony\Component\Serializer\Mapping\AttributeMetadataInterface;
|
||||
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
|
||||
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
|
||||
use Symfony\Component\Serializer\SerializerAwareInterface;
|
||||
use Symfony\Component\Serializer\SerializerAwareTrait;
|
||||
|
||||
/**
|
||||
* Normalizer implementation.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface
|
||||
{
|
||||
use ObjectToPopulateTrait;
|
||||
use SerializerAwareTrait;
|
||||
|
||||
/* constants to configure the context */
|
||||
|
||||
/**
|
||||
* How many loops of circular reference to allow while normalizing.
|
||||
*
|
||||
* The default value of 1 means that when we encounter the same object a
|
||||
* second time, we consider that a circular reference.
|
||||
*
|
||||
* You can raise this value for special cases, e.g. in combination with the
|
||||
* max depth setting of the object normalizer.
|
||||
*/
|
||||
public const CIRCULAR_REFERENCE_LIMIT = 'circular_reference_limit';
|
||||
|
||||
/**
|
||||
* Instead of creating a new instance of an object, update the specified object.
|
||||
*
|
||||
* If you have a nested structure, child objects will be overwritten with
|
||||
* new instances unless you set DEEP_OBJECT_TO_POPULATE to true.
|
||||
*/
|
||||
public const OBJECT_TO_POPULATE = 'object_to_populate';
|
||||
|
||||
/**
|
||||
* Only (de)normalize attributes that are in the specified groups.
|
||||
*/
|
||||
public const GROUPS = 'groups';
|
||||
|
||||
/**
|
||||
* Limit (de)normalize to the specified names.
|
||||
*
|
||||
* For nested structures, this list needs to reflect the object tree.
|
||||
*/
|
||||
public const ATTRIBUTES = 'attributes';
|
||||
|
||||
/**
|
||||
* If ATTRIBUTES are specified, and the source has fields that are not part of that list,
|
||||
* either ignore those attributes (true) or throw an ExtraAttributesException (false).
|
||||
*/
|
||||
public const ALLOW_EXTRA_ATTRIBUTES = 'allow_extra_attributes';
|
||||
|
||||
/**
|
||||
* Hashmap of default values for constructor arguments.
|
||||
*
|
||||
* The names need to match the parameter names in the constructor arguments.
|
||||
*/
|
||||
public const DEFAULT_CONSTRUCTOR_ARGUMENTS = 'default_constructor_arguments';
|
||||
|
||||
/**
|
||||
* Hashmap of field name => callable to (de)normalize this field.
|
||||
*
|
||||
* The callable is called if the field is encountered with the arguments:
|
||||
*
|
||||
* - mixed $attributeValue value of this field
|
||||
* - object|string $object the whole object being normalized or the object's class being denormalized
|
||||
* - string $attributeName name of the attribute being (de)normalized
|
||||
* - string $format the requested format
|
||||
* - array $context the serialization context
|
||||
*/
|
||||
public const CALLBACKS = 'callbacks';
|
||||
|
||||
/**
|
||||
* Handler to call when a circular reference has been detected.
|
||||
*
|
||||
* If you specify no handler, a CircularReferenceException is thrown.
|
||||
*
|
||||
* The method will be called with ($object, $format, $context) and its
|
||||
* return value is returned as the result of the normalize call.
|
||||
*/
|
||||
public const CIRCULAR_REFERENCE_HANDLER = 'circular_reference_handler';
|
||||
|
||||
/**
|
||||
* Skip the specified attributes when normalizing an object tree.
|
||||
*
|
||||
* This list is applied to each element of nested structures.
|
||||
*
|
||||
* Note: The behaviour for nested structures is different from ATTRIBUTES
|
||||
* for historical reason. Aligning the behaviour would be a BC break.
|
||||
*/
|
||||
public const IGNORED_ATTRIBUTES = 'ignored_attributes';
|
||||
|
||||
/**
|
||||
* Require all properties to be listed in the input instead of falling
|
||||
* back to null for nullable ones.
|
||||
*/
|
||||
public const REQUIRE_ALL_PROPERTIES = 'require_all_properties';
|
||||
|
||||
/**
|
||||
* Flag to control whether a non-boolean value should be filtered using the
|
||||
* filter_var function with the {@see https://www.php.net/manual/fr/filter.filters.validate.php}
|
||||
* \FILTER_VALIDATE_BOOL filter before casting it to a boolean.
|
||||
*
|
||||
* "0", "false", "off", "no" and "" will be cast to false.
|
||||
* "1", "true", "on" and "yes" will be cast to true.
|
||||
*/
|
||||
public const FILTER_BOOL = 'filter_bool';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
protected const CIRCULAR_REFERENCE_LIMIT_COUNTERS = 'circular_reference_limit_counters';
|
||||
|
||||
protected array $defaultContext = [
|
||||
self::ALLOW_EXTRA_ATTRIBUTES => true,
|
||||
self::CIRCULAR_REFERENCE_HANDLER => null,
|
||||
self::CIRCULAR_REFERENCE_LIMIT => 1,
|
||||
self::IGNORED_ATTRIBUTES => [],
|
||||
];
|
||||
|
||||
/**
|
||||
* Sets the {@link ClassMetadataFactoryInterface} to use.
|
||||
*/
|
||||
public function __construct(
|
||||
protected ?ClassMetadataFactoryInterface $classMetadataFactory = null,
|
||||
protected ?NameConverterInterface $nameConverter = null,
|
||||
array $defaultContext = [],
|
||||
) {
|
||||
$this->defaultContext = array_merge($this->defaultContext, $defaultContext);
|
||||
|
||||
$this->validateCallbackContext($this->defaultContext, 'default');
|
||||
|
||||
if (isset($this->defaultContext[self::CIRCULAR_REFERENCE_HANDLER]) && !\is_callable($this->defaultContext[self::CIRCULAR_REFERENCE_HANDLER])) {
|
||||
throw new InvalidArgumentException(\sprintf('Invalid callback found in the "%s" default context option.', self::CIRCULAR_REFERENCE_HANDLER));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects if the configured circular reference limit is reached.
|
||||
*
|
||||
* @throws CircularReferenceException
|
||||
*/
|
||||
protected function isCircularReference(object $object, array &$context): bool
|
||||
{
|
||||
$objectId = spl_object_id($object);
|
||||
|
||||
$circularReferenceLimit = $context[self::CIRCULAR_REFERENCE_LIMIT] ?? $this->defaultContext[self::CIRCULAR_REFERENCE_LIMIT];
|
||||
if (isset($context[self::CIRCULAR_REFERENCE_LIMIT_COUNTERS][$objectId])) {
|
||||
if ($context[self::CIRCULAR_REFERENCE_LIMIT_COUNTERS][$objectId] >= $circularReferenceLimit) {
|
||||
unset($context[self::CIRCULAR_REFERENCE_LIMIT_COUNTERS][$objectId]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
++$context[self::CIRCULAR_REFERENCE_LIMIT_COUNTERS][$objectId];
|
||||
} else {
|
||||
$context[self::CIRCULAR_REFERENCE_LIMIT_COUNTERS][$objectId] = 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a circular reference.
|
||||
*
|
||||
* If a circular reference handler is set, it will be called. Otherwise, a
|
||||
* {@class CircularReferenceException} will be thrown.
|
||||
*
|
||||
* @final
|
||||
*
|
||||
* @throws CircularReferenceException
|
||||
*/
|
||||
protected function handleCircularReference(object $object, ?string $format = null, array $context = []): mixed
|
||||
{
|
||||
$circularReferenceHandler = $context[self::CIRCULAR_REFERENCE_HANDLER] ?? $this->defaultContext[self::CIRCULAR_REFERENCE_HANDLER];
|
||||
if ($circularReferenceHandler) {
|
||||
return $circularReferenceHandler($object, $format, $context);
|
||||
}
|
||||
|
||||
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]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets attributes to normalize using groups.
|
||||
*
|
||||
* @param bool $attributesAsString If false, return an array of {@link AttributeMetadataInterface}
|
||||
*
|
||||
* @return string[]|AttributeMetadataInterface[]|bool
|
||||
*
|
||||
* @throws LogicException if the 'allow_extra_attributes' context variable is false and no class metadata factory is provided
|
||||
*/
|
||||
protected function getAllowedAttributes(string|object $classOrObject, array $context, bool $attributesAsString = false): array|bool
|
||||
{
|
||||
$allowExtraAttributes = $context[self::ALLOW_EXTRA_ATTRIBUTES] ?? $this->defaultContext[self::ALLOW_EXTRA_ATTRIBUTES];
|
||||
if (!$this->classMetadataFactory) {
|
||||
if (!$allowExtraAttributes) {
|
||||
throw new LogicException(\sprintf('A class metadata factory must be provided in the constructor when setting "%s" to false.', self::ALLOW_EXTRA_ATTRIBUTES));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$groups = $this->getGroups($context);
|
||||
|
||||
$allowedAttributes = [];
|
||||
$ignoreUsed = false;
|
||||
|
||||
foreach ($this->classMetadataFactory->getMetadataFor($classOrObject)->getAttributesMetadata() as $attributeMetadata) {
|
||||
if ($ignore = $attributeMetadata->isIgnored()) {
|
||||
$ignoreUsed = true;
|
||||
}
|
||||
|
||||
// If you update this check, update accordingly the one in Symfony\Component\PropertyInfo\Extractor\SerializerExtractor::getProperties()
|
||||
if (
|
||||
!$ignore
|
||||
&& ([] === $groups || \in_array('*', $groups, true) || array_intersect($attributeMetadata->getGroups(), $groups))
|
||||
&& $this->isAllowedAttribute($classOrObject, $name = $attributeMetadata->getName(), null, $context)
|
||||
) {
|
||||
$allowedAttributes[] = $attributesAsString ? $name : $attributeMetadata;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$ignoreUsed && [] === $groups && $allowExtraAttributes) {
|
||||
// Backward Compatibility with the code using this method written before the introduction of @Ignore
|
||||
return false;
|
||||
}
|
||||
|
||||
return $allowedAttributes;
|
||||
}
|
||||
|
||||
protected function getGroups(array $context): array
|
||||
{
|
||||
$groups = $context[self::GROUPS] ?? $this->defaultContext[self::GROUPS] ?? [];
|
||||
|
||||
return \is_scalar($groups) ? (array) $groups : $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this attribute allowed?
|
||||
*/
|
||||
protected function isAllowedAttribute(object|string $classOrObject, string $attribute, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
$ignoredAttributes = $context[self::IGNORED_ATTRIBUTES] ?? $this->defaultContext[self::IGNORED_ATTRIBUTES];
|
||||
if (\in_array($attribute, $ignoredAttributes, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$attributes = $context[self::ATTRIBUTES] ?? $this->defaultContext[self::ATTRIBUTES] ?? null;
|
||||
if (isset($attributes[$attribute])) {
|
||||
// Nested attributes
|
||||
return true;
|
||||
}
|
||||
|
||||
if (\is_array($attributes)) {
|
||||
return \in_array($attribute, $attributes, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the given data to an array. It's particularly useful during
|
||||
* the denormalization process.
|
||||
*/
|
||||
protected function prepareForDenormalization(mixed $data): array
|
||||
{
|
||||
return (array) $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method to use to construct an object. This method must be either
|
||||
* the object constructor or static.
|
||||
*/
|
||||
protected function getConstructor(array &$data, string $class, array &$context, \ReflectionClass $reflectionClass, array|bool $allowedAttributes): ?\ReflectionMethod
|
||||
{
|
||||
return $reflectionClass->getConstructor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates an object using constructor parameters when needed.
|
||||
*
|
||||
* This method also allows to denormalize data into an existing object if
|
||||
* it is present in the context with the object_to_populate. This object
|
||||
* is removed from the context before being returned to avoid side effects
|
||||
* when recursively normalizing an object graph.
|
||||
*
|
||||
* @throws RuntimeException
|
||||
* @throws MissingConstructorArgumentsException
|
||||
*/
|
||||
protected function instantiateObject(array &$data, string $class, array &$context, \ReflectionClass $reflectionClass, array|bool $allowedAttributes, ?string $format = null): object
|
||||
{
|
||||
if (null !== $object = $this->extractObjectToPopulate($class, $context, self::OBJECT_TO_POPULATE)) {
|
||||
unset($context[self::OBJECT_TO_POPULATE]);
|
||||
|
||||
return $object;
|
||||
}
|
||||
// clean up even if no match
|
||||
unset($context[static::OBJECT_TO_POPULATE]);
|
||||
|
||||
$constructor = $this->getConstructor($data, $class, $context, $reflectionClass, $allowedAttributes);
|
||||
if ($constructor) {
|
||||
if (true !== $constructor->isPublic()) {
|
||||
return $reflectionClass->newInstanceWithoutConstructor();
|
||||
}
|
||||
|
||||
$constructorParameters = $constructor->getParameters();
|
||||
$missingConstructorArguments = [];
|
||||
$params = [];
|
||||
$unsetKeys = [];
|
||||
|
||||
foreach ($constructorParameters as $constructorParameter) {
|
||||
$paramName = $constructorParameter->name;
|
||||
$attributeContext = $this->getAttributeDenormalizationContext($class, $paramName, $context);
|
||||
$key = $this->nameConverter ? $this->nameConverter->normalize($paramName, $class, $format, $context) : $paramName;
|
||||
|
||||
$allowed = false === $allowedAttributes || \in_array($paramName, $allowedAttributes, true);
|
||||
$ignored = !$this->isAllowedAttribute($class, $paramName, $format, $context);
|
||||
if ($constructorParameter->isVariadic()) {
|
||||
if ($allowed && !$ignored && (isset($data[$key]) || \array_key_exists($key, $data))) {
|
||||
if (!\is_array($data[$key])) {
|
||||
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));
|
||||
}
|
||||
|
||||
$variadicParameters = [];
|
||||
foreach ($data[$key] as $parameterKey => $parameterData) {
|
||||
try {
|
||||
$variadicParameters[$parameterKey] = $this->denormalizeParameter($reflectionClass, $constructorParameter, $paramName, $parameterData, $attributeContext, $format);
|
||||
} catch (NotNormalizableValueException $exception) {
|
||||
if (!isset($context['not_normalizable_value_exceptions'])) {
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
$context['not_normalizable_value_exceptions'][] = $exception;
|
||||
$params[$paramName] = $parameterData;
|
||||
}
|
||||
}
|
||||
|
||||
$params = array_merge(array_values($params), $variadicParameters);
|
||||
$unsetKeys[] = $key;
|
||||
}
|
||||
} elseif ($allowed && !$ignored && (isset($data[$key]) || \array_key_exists($key, $data))) {
|
||||
$parameterData = $data[$key];
|
||||
if (null === $parameterData && $constructorParameter->allowsNull()) {
|
||||
$params[$paramName] = null;
|
||||
$unsetKeys[] = $key;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$params[$paramName] = $this->denormalizeParameter($reflectionClass, $constructorParameter, $paramName, $parameterData, $attributeContext, $format);
|
||||
} catch (NotNormalizableValueException $exception) {
|
||||
if (!isset($context['not_normalizable_value_exceptions'])) {
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
$context['not_normalizable_value_exceptions'][] = $exception;
|
||||
$params[$paramName] = $parameterData;
|
||||
}
|
||||
|
||||
$unsetKeys[] = $key;
|
||||
} elseif (\array_key_exists($key, $context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class] ?? [])) {
|
||||
$params[$paramName] = $context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class][$key];
|
||||
} elseif (\array_key_exists($key, $this->defaultContext[self::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class] ?? [])) {
|
||||
$params[$paramName] = $this->defaultContext[self::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class][$key];
|
||||
} elseif ($constructorParameter->isDefaultValueAvailable()) {
|
||||
$params[$paramName] = $constructorParameter->getDefaultValue();
|
||||
} elseif (!($context[self::REQUIRE_ALL_PROPERTIES] ?? $this->defaultContext[self::REQUIRE_ALL_PROPERTIES] ?? false) && $constructorParameter->hasType() && $constructorParameter->getType()->allowsNull()) {
|
||||
$params[$paramName] = null;
|
||||
} else {
|
||||
if (!isset($context['not_normalizable_value_exceptions'])) {
|
||||
$missingConstructorArguments[] = $constructorParameter->name;
|
||||
continue;
|
||||
}
|
||||
|
||||
$constructorParameterTypes = [];
|
||||
$reflectionType = $constructorParameter->getType();
|
||||
if ($reflectionType instanceof \ReflectionUnionType) {
|
||||
foreach ($reflectionType->getTypes() as $reflectionType) {
|
||||
$constructorParameterTypes[] = (string) $reflectionType;
|
||||
}
|
||||
} elseif ($reflectionType instanceof \ReflectionType) {
|
||||
$constructorParameterTypes[] = (string) $reflectionType;
|
||||
} else {
|
||||
$constructorParameterTypes[] = 'unknown';
|
||||
}
|
||||
|
||||
$exception = NotNormalizableValueException::createForUnexpectedDataType(
|
||||
\sprintf('Failed to create object because the class misses the "%s" property.', $constructorParameter->name),
|
||||
null,
|
||||
$constructorParameterTypes,
|
||||
$attributeContext['deserialization_path'] ?? null,
|
||||
true
|
||||
);
|
||||
$context['not_normalizable_value_exceptions'][] = $exception;
|
||||
}
|
||||
}
|
||||
|
||||
if ($missingConstructorArguments) {
|
||||
throw new MissingConstructorArgumentsException(\sprintf('Cannot create an instance of "%s" from serialized data because its constructor requires the following parameters to be present : "$%s".', $class, implode('", "$', $missingConstructorArguments)), 0, null, $missingConstructorArguments, $class);
|
||||
}
|
||||
|
||||
if (!$constructor->isConstructor()) {
|
||||
$instance = $constructor->invokeArgs(null, $params);
|
||||
|
||||
// do not set a parameter that has been set in the constructor
|
||||
foreach ($unsetKeys as $key) {
|
||||
unset($data[$key]);
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
try {
|
||||
$instance = $reflectionClass->newInstanceArgs($params);
|
||||
|
||||
// do not set a parameter that has been set in the constructor
|
||||
foreach ($unsetKeys as $key) {
|
||||
unset($data[$key]);
|
||||
}
|
||||
|
||||
return $instance;
|
||||
} catch (\TypeError $e) {
|
||||
if (!isset($context['not_normalizable_value_exceptions'])) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $reflectionClass->newInstanceWithoutConstructor();
|
||||
}
|
||||
}
|
||||
|
||||
if (!$reflectionClass->isInstantiable()) {
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('Failed to create object because the class "%s" is not instantiable.', $class), $data, ['unknown'], $context['deserialization_path'] ?? null);
|
||||
}
|
||||
|
||||
return new $class();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
protected function denormalizeParameter(\ReflectionClass $class, \ReflectionParameter $parameter, string $parameterName, mixed $parameterData, array $context, ?string $format = null): mixed
|
||||
{
|
||||
try {
|
||||
if (($parameterType = $parameter->getType()) instanceof \ReflectionNamedType && !$parameterType->isBuiltin()) {
|
||||
$parameterClass = $parameterType->getName();
|
||||
new \ReflectionClass($parameterClass); // throws a \ReflectionException if the class doesn't exist
|
||||
|
||||
if (!$this->serializer instanceof DenormalizerInterface) {
|
||||
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));
|
||||
}
|
||||
|
||||
$parameterData = $this->serializer->denormalize($parameterData, $parameterClass, $format, $this->createChildContext($context, $parameterName, $format));
|
||||
}
|
||||
} catch (\ReflectionException $e) {
|
||||
throw new RuntimeException(\sprintf('Could not determine the class of the parameter "%s".', $parameterName), 0, $e);
|
||||
} catch (MissingConstructorArgumentsException $e) {
|
||||
if (!$parameter->getType()->allowsNull()) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$parameterData = $this->applyCallbacks($parameterData, $class->getName(), $parameterName, $format, $context);
|
||||
|
||||
return $this->applyFilterBool($parameter, $parameterData, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
protected function createChildContext(array $parentContext, string $attribute, ?string $format): array
|
||||
{
|
||||
if (isset($parentContext[self::ATTRIBUTES][$attribute])) {
|
||||
$parentContext[self::ATTRIBUTES] = $parentContext[self::ATTRIBUTES][$attribute];
|
||||
} else {
|
||||
unset($parentContext[self::ATTRIBUTES]);
|
||||
}
|
||||
|
||||
return $parentContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate callbacks set in context.
|
||||
*
|
||||
* @param string $contextType Used to specify which context is invalid in exceptions
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
final protected function validateCallbackContext(array $context, string $contextType = ''): void
|
||||
{
|
||||
if (!isset($context[self::CALLBACKS])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!\is_array($context[self::CALLBACKS])) {
|
||||
throw new InvalidArgumentException(\sprintf('The "%s"%s context option must be an array of callables.', self::CALLBACKS, '' !== $contextType ? " $contextType" : ''));
|
||||
}
|
||||
|
||||
foreach ($context[self::CALLBACKS] as $attribute => $callback) {
|
||||
if (!\is_callable($callback)) {
|
||||
throw new InvalidArgumentException(\sprintf('Invalid callback found for attribute "%s" in the "%s"%s context option.', $attribute, self::CALLBACKS, '' !== $contextType ? " $contextType" : ''));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final protected function applyCallbacks(mixed $value, object|string $object, string $attribute, ?string $format, array $context): mixed
|
||||
{
|
||||
/**
|
||||
* @var callable|null
|
||||
*/
|
||||
$callback = $context[self::CALLBACKS][$attribute] ?? $this->defaultContext[self::CALLBACKS][$attribute] ?? null;
|
||||
|
||||
return $callback ? $callback($value, $object, $attribute, $format, $context) : $value;
|
||||
}
|
||||
|
||||
final protected function applyFilterBool(\ReflectionParameter $parameter, mixed $value, array $context): mixed
|
||||
{
|
||||
if (!($context[self::FILTER_BOOL] ?? false)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (!($parameterType = $parameter->getType()) instanceof \ReflectionNamedType || 'bool' !== $parameterType->getName()) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return filter_var($value, \FILTER_VALIDATE_BOOL, \FILTER_NULL_ON_FAILURE) ?? $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the normalization context merged with current one. Metadata always wins over global context, as more specific.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function getAttributeNormalizationContext(object $object, string $attribute, array $context): array
|
||||
{
|
||||
if (null === $metadata = $this->getAttributeMetadata($object, $attribute)) {
|
||||
return $context;
|
||||
}
|
||||
|
||||
return array_merge($context, $metadata->getNormalizationContextForGroups($this->getGroups($context)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the denormalization context merged with current one. Metadata always wins over global context, as more specific.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function getAttributeDenormalizationContext(string $class, string $attribute, array $context): array
|
||||
{
|
||||
$context['deserialization_path'] = ($context['deserialization_path'] ?? false) ? $context['deserialization_path'].'.'.$attribute : $attribute;
|
||||
|
||||
if (null === $metadata = $this->getAttributeMetadata($class, $attribute)) {
|
||||
return $context;
|
||||
}
|
||||
|
||||
return array_merge($context, $metadata->getDenormalizationContextForGroups($this->getGroups($context)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
protected function getAttributeMetadata(object|string $objectOrClass, string $attribute): ?AttributeMetadataInterface
|
||||
{
|
||||
if (!$this->classMetadataFactory) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->classMetadataFactory->getMetadataFor($objectOrClass)->getAttributesMetadata()[$attribute] ?? null;
|
||||
}
|
||||
}
|
||||
1294
backend/vendor/symfony/serializer/Normalizer/AbstractObjectNormalizer.php
vendored
Normal file
1294
backend/vendor/symfony/serializer/Normalizer/AbstractObjectNormalizer.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
112
backend/vendor/symfony/serializer/Normalizer/ArrayDenormalizer.php
vendored
Normal file
112
backend/vendor/symfony/serializer/Normalizer/ArrayDenormalizer.php
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\PropertyInfo\Type as LegacyType;
|
||||
use Symfony\Component\Serializer\Exception\BadMethodCallException;
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
|
||||
use Symfony\Component\TypeInfo\Type;
|
||||
use Symfony\Component\TypeInfo\Type\BuiltinType;
|
||||
use Symfony\Component\TypeInfo\Type\UnionType;
|
||||
use Symfony\Component\TypeInfo\TypeIdentifier;
|
||||
|
||||
/**
|
||||
* Denormalizes arrays of objects.
|
||||
*
|
||||
* @author Alexander M. Turek <me@derrabus.de>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class ArrayDenormalizer implements DenormalizerInterface, DenormalizerAwareInterface
|
||||
{
|
||||
use DenormalizerAwareTrait;
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return ['object' => null, '*' => false];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NotNormalizableValueException
|
||||
*/
|
||||
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): array
|
||||
{
|
||||
if (!isset($this->denormalizer)) {
|
||||
throw new BadMethodCallException('Please set a denormalizer before calling denormalize()!');
|
||||
}
|
||||
if (!\is_array($data)) {
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('Data expected to be "%s", "%s" given.', $type, get_debug_type($data)), $data, ['array'], $context['deserialization_path'] ?? null);
|
||||
}
|
||||
if (!str_ends_with($type, '[]')) {
|
||||
throw new InvalidArgumentException('Unsupported class: '.$type);
|
||||
}
|
||||
|
||||
$type = substr($type, 0, -2);
|
||||
|
||||
$typeIdentifiers = [];
|
||||
if (null !== $keyType = ($context['key_type'] ?? null)) {
|
||||
if ($keyType instanceof Type) {
|
||||
// BC layer for type-info < 7.2
|
||||
if (method_exists(Type::class, 'getBaseType')) {
|
||||
$typeIdentifiers = array_map(fn (Type $t): string => $t->getBaseType()->getTypeIdentifier()->value, $keyType instanceof UnionType ? $keyType->getTypes() : [$keyType]);
|
||||
} else {
|
||||
/** @var list<BuiltinType<TypeIdentifier::INT>|BuiltinType<TypeIdentifier::STRING>> */
|
||||
$keyTypes = $keyType instanceof UnionType ? $keyType->getTypes() : [$keyType];
|
||||
|
||||
$typeIdentifiers = array_map(fn (BuiltinType $t): string => $t->getTypeIdentifier()->value, $keyTypes);
|
||||
}
|
||||
} else {
|
||||
$typeIdentifiers = array_map(fn (LegacyType $t): string => $t->getBuiltinType(), \is_array($keyType) ? $keyType : [$keyType]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
$subContext = $context;
|
||||
$subContext['deserialization_path'] = ($context['deserialization_path'] ?? false) ? \sprintf('%s[%s]', $context['deserialization_path'], $key) : "[$key]";
|
||||
|
||||
$this->validateKeyType($typeIdentifiers, $key, $subContext['deserialization_path']);
|
||||
|
||||
$data[$key] = $this->denormalizer->denormalize($value, $type, $format, $subContext);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
if (!isset($this->denormalizer)) {
|
||||
throw new BadMethodCallException(\sprintf('The nested denormalizer needs to be set to allow "%s()" to be used.', __METHOD__));
|
||||
}
|
||||
|
||||
return str_ends_with($type, '[]')
|
||||
&& $this->denormalizer->supportsDenormalization($data, substr($type, 0, -2), $format, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<string> $typeIdentifiers
|
||||
*/
|
||||
private function validateKeyType(array $typeIdentifiers, mixed $key, string $path): void
|
||||
{
|
||||
if (!$typeIdentifiers) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($typeIdentifiers as $typeIdentifier) {
|
||||
if (('is_'.$typeIdentifier)($key)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The type of the key "%s" must be "%s" ("%s" given).', $key, implode('", "', $typeIdentifiers), get_debug_type($key)), $key, $typeIdentifiers, $path, true);
|
||||
}
|
||||
}
|
||||
84
backend/vendor/symfony/serializer/Normalizer/BackedEnumNormalizer.php
vendored
Normal file
84
backend/vendor/symfony/serializer/Normalizer/BackedEnumNormalizer.php
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
|
||||
|
||||
/**
|
||||
* Normalizes a {@see \BackedEnum} enumeration to a string or an integer.
|
||||
*
|
||||
* @author Alexandre Daubois <alex.daubois@gmail.com>
|
||||
*/
|
||||
final class BackedEnumNormalizer implements NormalizerInterface, DenormalizerInterface
|
||||
{
|
||||
/**
|
||||
* If true, will denormalize any invalid value into null.
|
||||
*/
|
||||
public const ALLOW_INVALID_VALUES = 'allow_invalid_values';
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return [
|
||||
\BackedEnum::class => true,
|
||||
];
|
||||
}
|
||||
|
||||
public function normalize(mixed $data, ?string $format = null, array $context = []): int|string
|
||||
{
|
||||
if (!$data instanceof \BackedEnum) {
|
||||
throw new InvalidArgumentException('The data must belong to a backed enumeration.');
|
||||
}
|
||||
|
||||
return $data->value;
|
||||
}
|
||||
|
||||
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return $data instanceof \BackedEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NotNormalizableValueException
|
||||
*/
|
||||
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed
|
||||
{
|
||||
if (!is_subclass_of($type, \BackedEnum::class)) {
|
||||
throw new InvalidArgumentException('The data must belong to a backed enumeration.');
|
||||
}
|
||||
|
||||
$allowInvalidValues = $context[self::ALLOW_INVALID_VALUES] ?? false;
|
||||
|
||||
if (null === $data || (!\is_int($data) && !\is_string($data))) {
|
||||
if ($allowInvalidValues && !isset($context['not_normalizable_value_exceptions'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType('The data is neither an integer nor a string, you should pass an integer or a string that can be parsed as an enumeration case of type '.$type.'.', $data, ['int', 'string'], $context['deserialization_path'] ?? null, true);
|
||||
}
|
||||
|
||||
try {
|
||||
return $type::from($data);
|
||||
} catch (\ValueError|\TypeError $e) {
|
||||
if ($allowInvalidValues && !isset($context['not_normalizable_value_exceptions'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType('The data must belong to a backed enumeration of type '.$type, $data, ['int', 'string'], $context['deserialization_path'] ?? null, true, 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return is_subclass_of($type, \BackedEnum::class);
|
||||
}
|
||||
}
|
||||
159
backend/vendor/symfony/serializer/Normalizer/ConstraintViolationListNormalizer.php
vendored
Normal file
159
backend/vendor/symfony/serializer/Normalizer/ConstraintViolationListNormalizer.php
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
|
||||
use Symfony\Component\Validator\ConstraintViolationListInterface;
|
||||
|
||||
/**
|
||||
* A normalizer that normalizes a ConstraintViolationListInterface instance.
|
||||
*
|
||||
* This Normalizer implements RFC7807 {@link https://tools.ietf.org/html/rfc7807}.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
final class ConstraintViolationListNormalizer implements NormalizerInterface
|
||||
{
|
||||
public const INSTANCE = 'instance';
|
||||
public const STATUS = 'status';
|
||||
public const TITLE = 'title';
|
||||
public const TYPE = 'type';
|
||||
public const PAYLOAD_FIELDS = 'payload_fields';
|
||||
|
||||
public function __construct(
|
||||
private readonly array $defaultContext = [],
|
||||
private readonly ?NameConverterInterface $nameConverter = null,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return [
|
||||
ConstraintViolationListInterface::class => true,
|
||||
];
|
||||
}
|
||||
|
||||
public function normalize(mixed $data, ?string $format = null, array $context = []): array
|
||||
{
|
||||
if (\array_key_exists(self::PAYLOAD_FIELDS, $context)) {
|
||||
$payloadFieldsToSerialize = $context[self::PAYLOAD_FIELDS];
|
||||
} elseif (\array_key_exists(self::PAYLOAD_FIELDS, $this->defaultContext)) {
|
||||
$payloadFieldsToSerialize = $this->defaultContext[self::PAYLOAD_FIELDS];
|
||||
} else {
|
||||
$payloadFieldsToSerialize = [];
|
||||
}
|
||||
|
||||
if (\is_array($payloadFieldsToSerialize) && [] !== $payloadFieldsToSerialize) {
|
||||
$payloadFieldsToSerialize = array_flip($payloadFieldsToSerialize);
|
||||
}
|
||||
|
||||
$violations = [];
|
||||
$messages = [];
|
||||
foreach ($data as $violation) {
|
||||
$propertyPath = $violation->getPropertyPath();
|
||||
|
||||
if (null !== $this->nameConverter) {
|
||||
$propertyPath = $this->normalizePropertyPath($propertyPath, \is_object($violation->getRoot()) ? \get_class($violation->getRoot()) : null, $format, $context);
|
||||
}
|
||||
|
||||
$violationEntry = [
|
||||
'propertyPath' => $propertyPath,
|
||||
'title' => $violation->getMessage(),
|
||||
'template' => $violation->getMessageTemplate(),
|
||||
'parameters' => $violation->getParameters(),
|
||||
];
|
||||
if (null !== $code = $violation->getCode()) {
|
||||
$violationEntry['type'] = \sprintf('urn:uuid:%s', $code);
|
||||
}
|
||||
|
||||
$constraint = $violation->getConstraint();
|
||||
if (
|
||||
[] !== $payloadFieldsToSerialize
|
||||
&& $constraint
|
||||
&& $constraint->payload
|
||||
// If some or all payload fields are whitelisted, add them
|
||||
&& $payloadFields = null === $payloadFieldsToSerialize || true === $payloadFieldsToSerialize ? $constraint->payload : array_intersect_key($constraint->payload, $payloadFieldsToSerialize)
|
||||
) {
|
||||
$violationEntry['payload'] = $payloadFields;
|
||||
}
|
||||
|
||||
$violations[] = $violationEntry;
|
||||
|
||||
$prefix = $propertyPath ? \sprintf('%s: ', $propertyPath) : '';
|
||||
$messages[] = $prefix.$violation->getMessage();
|
||||
}
|
||||
|
||||
$result = [
|
||||
'type' => $context[self::TYPE] ?? $this->defaultContext[self::TYPE] ?? 'https://symfony.com/errors/validation',
|
||||
'title' => $context[self::TITLE] ?? $this->defaultContext[self::TITLE] ?? 'Validation Failed',
|
||||
];
|
||||
if (null !== $status = ($context[self::STATUS] ?? $this->defaultContext[self::STATUS] ?? null)) {
|
||||
$result['status'] = $status;
|
||||
}
|
||||
if ($messages) {
|
||||
$result['detail'] = implode("\n", $messages);
|
||||
}
|
||||
if (null !== $instance = ($context[self::INSTANCE] ?? $this->defaultContext[self::INSTANCE] ?? null)) {
|
||||
$result['instance'] = $instance;
|
||||
}
|
||||
|
||||
return $result + ['violations' => $violations];
|
||||
}
|
||||
|
||||
private function normalizePropertyPath(string $propertyPath, ?string $class, ?string $format, array $context): string
|
||||
{
|
||||
if (!str_contains($propertyPath, '.')) {
|
||||
return $this->nameConverter->normalize($propertyPath, $class, $format, $context);
|
||||
}
|
||||
|
||||
$result = [];
|
||||
$currentClass = $class;
|
||||
|
||||
foreach (explode('.', $propertyPath) as $segment) {
|
||||
$subscript = '';
|
||||
$propertyName = $segment;
|
||||
if (false !== $bracketPos = strpos($segment, '[')) {
|
||||
$propertyName = substr($segment, 0, $bracketPos);
|
||||
$subscript = substr($segment, $bracketPos);
|
||||
}
|
||||
|
||||
$result[] = $this->nameConverter->normalize($propertyName, $currentClass, $format, $context).$subscript;
|
||||
|
||||
$currentClass = $this->getPropertyClassFromReflection($currentClass, $propertyName);
|
||||
}
|
||||
|
||||
return implode('.', $result);
|
||||
}
|
||||
|
||||
private function getPropertyClassFromReflection(?string $class, string $property): ?string
|
||||
{
|
||||
if (null === $class) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$type = (new \ReflectionProperty($class, $property))->getType();
|
||||
if ($type instanceof \ReflectionNamedType && !$type->isBuiltin()) {
|
||||
return $type->getName();
|
||||
}
|
||||
} catch (\ReflectionException) {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return $data instanceof ConstraintViolationListInterface;
|
||||
}
|
||||
}
|
||||
68
backend/vendor/symfony/serializer/Normalizer/CustomNormalizer.php
vendored
Normal file
68
backend/vendor/symfony/serializer/Normalizer/CustomNormalizer.php
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\SerializerAwareInterface;
|
||||
use Symfony\Component\Serializer\SerializerAwareTrait;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
final class CustomNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface
|
||||
{
|
||||
use ObjectToPopulateTrait;
|
||||
use SerializerAwareTrait;
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return [
|
||||
NormalizableInterface::class => true,
|
||||
DenormalizableInterface::class => true,
|
||||
];
|
||||
}
|
||||
|
||||
public function normalize(mixed $data, ?string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null
|
||||
{
|
||||
return $data->normalize($this->serializer, $format, $context);
|
||||
}
|
||||
|
||||
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed
|
||||
{
|
||||
$object = $this->extractObjectToPopulate($type, $context) ?? new $type();
|
||||
$object->denormalize($this->serializer, $data, $format, $context);
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given class implements the NormalizableInterface.
|
||||
*
|
||||
* @param mixed $data Data to normalize
|
||||
* @param string|null $format The format being (de-)serialized from or into
|
||||
*/
|
||||
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return $data instanceof NormalizableInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given class implements the DenormalizableInterface.
|
||||
*
|
||||
* @param mixed $data Data to denormalize from
|
||||
* @param string $type The class to which the data should be denormalized
|
||||
* @param string|null $format The format being deserialized from
|
||||
*/
|
||||
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return is_subclass_of($type, DenormalizableInterface::class);
|
||||
}
|
||||
}
|
||||
140
backend/vendor/symfony/serializer/Normalizer/DataUriNormalizer.php
vendored
Normal file
140
backend/vendor/symfony/serializer/Normalizer/DataUriNormalizer.php
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
use Symfony\Component\Mime\MimeTypeGuesserInterface;
|
||||
use Symfony\Component\Mime\MimeTypes;
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
|
||||
|
||||
/**
|
||||
* Normalizes an {@see \SplFileInfo} object to a data URI.
|
||||
* Denormalizes a data URI to a {@see \SplFileObject} object.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
final class DataUriNormalizer implements NormalizerInterface, DenormalizerInterface
|
||||
{
|
||||
private const SUPPORTED_TYPES = [
|
||||
\SplFileInfo::class => true,
|
||||
\SplFileObject::class => true,
|
||||
File::class => true,
|
||||
];
|
||||
|
||||
private readonly ?MimeTypeGuesserInterface $mimeTypeGuesser;
|
||||
|
||||
public function __construct(?MimeTypeGuesserInterface $mimeTypeGuesser = null)
|
||||
{
|
||||
if (!$mimeTypeGuesser && class_exists(MimeTypes::class)) {
|
||||
$mimeTypeGuesser = MimeTypes::getDefault();
|
||||
}
|
||||
|
||||
$this->mimeTypeGuesser = $mimeTypeGuesser;
|
||||
}
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return self::SUPPORTED_TYPES;
|
||||
}
|
||||
|
||||
public function normalize(mixed $data, ?string $format = null, array $context = []): string
|
||||
{
|
||||
if (!$data instanceof \SplFileInfo) {
|
||||
throw new InvalidArgumentException('The object must be an instance of "\SplFileInfo".');
|
||||
}
|
||||
|
||||
$mimeType = $this->getMimeType($data);
|
||||
$splFileObject = $this->extractSplFileObject($data);
|
||||
|
||||
$splFileData = '';
|
||||
|
||||
$splFileObject->rewind();
|
||||
while (!$splFileObject->eof()) {
|
||||
$splFileData .= $splFileObject->fgets();
|
||||
}
|
||||
|
||||
if ('text' === explode('/', $mimeType, 2)[0]) {
|
||||
return \sprintf('data:%s,%s', $mimeType, rawurlencode($splFileData));
|
||||
}
|
||||
|
||||
return \sprintf('data:%s;base64,%s', $mimeType, base64_encode($splFileData));
|
||||
}
|
||||
|
||||
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return $data instanceof \SplFileInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regex adapted from Brian Grinstead code.
|
||||
*
|
||||
* @see https://gist.github.com/bgrins/6194623
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws NotNormalizableValueException
|
||||
*/
|
||||
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): \SplFileInfo
|
||||
{
|
||||
if (null === $data || !preg_match('/^data:([a-z0-9][a-z0-9\!\#\$\&\-\^\_\+\.]{0,126}\/[a-z0-9][a-z0-9\!\#\$\&\-\^\_\+\.]{0,126}(;[a-z0-9\-]+\=[a-z0-9\-]+)?)?(;base64)?,[a-z0-9\!\$\&\\\'\,\(\)\*\+\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i', $data)) {
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType('The provided "data:" URI is not valid.', $data, ['string'], $context['deserialization_path'] ?? null, true);
|
||||
}
|
||||
|
||||
try {
|
||||
switch ($type) {
|
||||
case File::class:
|
||||
if (!class_exists(File::class)) {
|
||||
throw new InvalidArgumentException(\sprintf('Cannot denormalize to a "%s" without the HttpFoundation component installed. Try running "composer require symfony/http-foundation".', File::class));
|
||||
}
|
||||
|
||||
return new File($data, false);
|
||||
|
||||
case 'SplFileObject':
|
||||
case 'SplFileInfo':
|
||||
return new \SplFileObject($data);
|
||||
}
|
||||
} catch (\RuntimeException $exception) {
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType($exception->getMessage(), $data, ['string'], $context['deserialization_path'] ?? null, false, $exception->getCode(), $exception);
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(\sprintf('The class parameter "%s" is not supported. It must be one of "SplFileInfo", "SplFileObject" or "Symfony\Component\HttpFoundation\File\File".', $type));
|
||||
}
|
||||
|
||||
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return isset(self::SUPPORTED_TYPES[$type]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mime type of the object. Defaults to application/octet-stream.
|
||||
*/
|
||||
private function getMimeType(\SplFileInfo $object): string
|
||||
{
|
||||
if ($object instanceof File) {
|
||||
return $object->getMimeType();
|
||||
}
|
||||
|
||||
return $this->mimeTypeGuesser?->guessMimeType($object->getPathname()) ?: 'application/octet-stream';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the \SplFileObject instance associated with the given \SplFileInfo instance.
|
||||
*/
|
||||
private function extractSplFileObject(\SplFileInfo $object): \SplFileObject
|
||||
{
|
||||
if ($object instanceof \SplFileObject) {
|
||||
return $object;
|
||||
}
|
||||
|
||||
return $object->openFile();
|
||||
}
|
||||
}
|
||||
118
backend/vendor/symfony/serializer/Normalizer/DateIntervalNormalizer.php
vendored
Normal file
118
backend/vendor/symfony/serializer/Normalizer/DateIntervalNormalizer.php
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
|
||||
|
||||
/**
|
||||
* Normalizes an instance of {@see \DateInterval} to an interval string.
|
||||
* Denormalizes an interval string to an instance of {@see \DateInterval}.
|
||||
*
|
||||
* @author Jérôme Parmentier <jerome@prmntr.me>
|
||||
*/
|
||||
final class DateIntervalNormalizer implements NormalizerInterface, DenormalizerInterface
|
||||
{
|
||||
public const FORMAT_KEY = 'dateinterval_format';
|
||||
|
||||
private array $defaultContext = [
|
||||
self::FORMAT_KEY => '%rP%yY%mM%dDT%hH%iM%sS',
|
||||
];
|
||||
|
||||
public function __construct(array $defaultContext = [])
|
||||
{
|
||||
$this->defaultContext = array_merge($this->defaultContext, $defaultContext);
|
||||
}
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return [
|
||||
\DateInterval::class => true,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function normalize(mixed $data, ?string $format = null, array $context = []): string
|
||||
{
|
||||
if (!$data instanceof \DateInterval) {
|
||||
throw new InvalidArgumentException('The object must be an instance of "\DateInterval".');
|
||||
}
|
||||
|
||||
return $data->format($context[self::FORMAT_KEY] ?? $this->defaultContext[self::FORMAT_KEY]);
|
||||
}
|
||||
|
||||
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return $data instanceof \DateInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NotNormalizableValueException
|
||||
*/
|
||||
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): \DateInterval
|
||||
{
|
||||
if (!\is_string($data)) {
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType('Data expected to be a string.', $data, ['string'], $context['deserialization_path'] ?? null, true);
|
||||
}
|
||||
|
||||
if (!$this->isISO8601($data)) {
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType('Expected a valid ISO 8601 interval string.', $data, ['string'], $context['deserialization_path'] ?? null, true);
|
||||
}
|
||||
|
||||
$dateIntervalFormat = $context[self::FORMAT_KEY] ?? $this->defaultContext[self::FORMAT_KEY];
|
||||
|
||||
$signPattern = '';
|
||||
switch (substr($dateIntervalFormat, 0, 2)) {
|
||||
case '%R':
|
||||
$signPattern = '[-+]';
|
||||
$dateIntervalFormat = substr($dateIntervalFormat, 2);
|
||||
break;
|
||||
case '%r':
|
||||
$signPattern = '-?';
|
||||
$dateIntervalFormat = substr($dateIntervalFormat, 2);
|
||||
break;
|
||||
}
|
||||
$valuePattern = '/^'.$signPattern.preg_replace('/%([yYmMdDhHiIsSwW])(\w)/', '(?:(?P<$1>\d+)$2)?', preg_replace('/(T.*)$/', '($1)?', $dateIntervalFormat)).'$/';
|
||||
if (!preg_match($valuePattern, $data)) {
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('Value "%s" contains intervals not accepted by format "%s".', $data, $dateIntervalFormat), $data, ['string'], $context['deserialization_path'] ?? null, false);
|
||||
}
|
||||
|
||||
try {
|
||||
if ('-' === $data[0]) {
|
||||
$interval = new \DateInterval(substr($data, 1));
|
||||
$interval->invert = 1;
|
||||
|
||||
return $interval;
|
||||
}
|
||||
|
||||
if ('+' === $data[0]) {
|
||||
return new \DateInterval(substr($data, 1));
|
||||
}
|
||||
|
||||
return new \DateInterval($data);
|
||||
} catch (\Exception $e) {
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType($e->getMessage(), $data, ['string'], $context['deserialization_path'] ?? null, false, $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return \DateInterval::class === $type;
|
||||
}
|
||||
|
||||
private function isISO8601(string $string): bool
|
||||
{
|
||||
return preg_match('/^[\-+]?P(?=\w*(?:\d|%\w))(?:\d+Y|%[yY]Y)?(?:\d+M|%[mM]M)?(?:\d+W|%[wW]W)?(?:\d+D|%[dD]D)?(?:T(?:\d+H|[hH]H)?(?:\d+M|[iI]M)?(?:\d+S|[sS]S)?)?$/', $string);
|
||||
}
|
||||
}
|
||||
184
backend/vendor/symfony/serializer/Normalizer/DateTimeNormalizer.php
vendored
Normal file
184
backend/vendor/symfony/serializer/Normalizer/DateTimeNormalizer.php
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
|
||||
|
||||
/**
|
||||
* Normalizes an object implementing the {@see \DateTimeInterface} to a date string.
|
||||
* Denormalizes a date string to an instance of {@see \DateTime} or {@see \DateTimeImmutable}.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
final class DateTimeNormalizer implements NormalizerInterface, DenormalizerInterface
|
||||
{
|
||||
public const FORMAT_KEY = 'datetime_format';
|
||||
public const TIMEZONE_KEY = 'datetime_timezone';
|
||||
public const CAST_KEY = 'datetime_cast';
|
||||
public const FORCE_TIMEZONE_KEY = 'datetime_force_timezone';
|
||||
|
||||
private array $defaultContext = [
|
||||
self::FORMAT_KEY => \DateTimeInterface::RFC3339,
|
||||
self::TIMEZONE_KEY => null,
|
||||
self::CAST_KEY => null,
|
||||
self::FORCE_TIMEZONE_KEY => false,
|
||||
];
|
||||
|
||||
private const SUPPORTED_TYPES = [
|
||||
\DateTimeInterface::class => true,
|
||||
\DateTimeImmutable::class => true,
|
||||
\DateTime::class => true,
|
||||
];
|
||||
|
||||
public function __construct(array $defaultContext = [])
|
||||
{
|
||||
$this->setDefaultContext($defaultContext);
|
||||
}
|
||||
|
||||
public function setDefaultContext(array $defaultContext): void
|
||||
{
|
||||
$this->defaultContext = array_merge($this->defaultContext, $defaultContext);
|
||||
}
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return self::SUPPORTED_TYPES;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function normalize(mixed $data, ?string $format = null, array $context = []): int|float|string
|
||||
{
|
||||
if (!$data instanceof \DateTimeInterface) {
|
||||
throw new InvalidArgumentException('The object must implement the "\DateTimeInterface".');
|
||||
}
|
||||
|
||||
$dateTimeFormat = $context[self::FORMAT_KEY] ?? $this->defaultContext[self::FORMAT_KEY];
|
||||
$timezone = $this->getTimezone($context);
|
||||
|
||||
if (null !== $timezone) {
|
||||
$data = clone $data;
|
||||
$data = $data->setTimezone($timezone);
|
||||
}
|
||||
|
||||
return match ($context[self::CAST_KEY] ?? $this->defaultContext[self::CAST_KEY] ?? false) {
|
||||
'int' => (int) $data->format($dateTimeFormat),
|
||||
'float' => (float) $data->format($dateTimeFormat),
|
||||
default => $data->format($dateTimeFormat),
|
||||
};
|
||||
}
|
||||
|
||||
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return $data instanceof \DateTimeInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NotNormalizableValueException
|
||||
*/
|
||||
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): \DateTimeInterface
|
||||
{
|
||||
if (\is_int($data) || \is_float($data)) {
|
||||
switch ($context[self::FORMAT_KEY] ?? $this->defaultContext[self::FORMAT_KEY] ?? null) {
|
||||
case 'U':
|
||||
$data = \sprintf('%d', $data);
|
||||
break;
|
||||
case 'U.u':
|
||||
$data = \sprintf('%.6F', $data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!\is_string($data) || '' === trim($data)) {
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType('The data is either not an string, an empty string, or null; you should pass a string that can be parsed with the passed format or a valid DateTime string.', $data, ['string'], $context['deserialization_path'] ?? null, true);
|
||||
}
|
||||
|
||||
try {
|
||||
if (\DateTimeInterface::class === $type) {
|
||||
$type = \DateTimeImmutable::class;
|
||||
}
|
||||
|
||||
$timezone = $this->getTimezone($context);
|
||||
$dateTimeFormat = $context[self::FORMAT_KEY] ?? null;
|
||||
|
||||
if (null !== $dateTimeFormat) {
|
||||
if (false !== $object = $type::createFromFormat($dateTimeFormat, $data, $timezone)) {
|
||||
return $this->enforceTimezone($object, $context);
|
||||
}
|
||||
|
||||
$dateTimeErrors = $type::getLastErrors();
|
||||
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('Parsing datetime string "%s" using format "%s" resulted in %d errors: ', $data, $dateTimeFormat, $dateTimeErrors['error_count'])."\n".implode("\n", $this->formatDateTimeErrors($dateTimeErrors['errors'])), $data, ['string'], $context['deserialization_path'] ?? null, true);
|
||||
}
|
||||
|
||||
$defaultDateTimeFormat = $this->defaultContext[self::FORMAT_KEY] ?? null;
|
||||
|
||||
if (null !== $defaultDateTimeFormat) {
|
||||
if (false !== $object = $type::createFromFormat($defaultDateTimeFormat, $data, $timezone)) {
|
||||
return $this->enforceTimezone($object, $context);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->enforceTimezone(new $type($data, $timezone), $context);
|
||||
} catch (NotNormalizableValueException $e) {
|
||||
throw $e;
|
||||
} catch (\Exception $e) {
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType($e->getMessage(), $data, ['string'], $context['deserialization_path'] ?? null, false, $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return is_a($type, \DateTimeInterface::class, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats datetime errors.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private function formatDateTimeErrors(array $errors): array
|
||||
{
|
||||
$formattedErrors = [];
|
||||
|
||||
foreach ($errors as $pos => $message) {
|
||||
$formattedErrors[] = \sprintf('at position %d: %s', $pos, $message);
|
||||
}
|
||||
|
||||
return $formattedErrors;
|
||||
}
|
||||
|
||||
private function getTimezone(array $context): ?\DateTimeZone
|
||||
{
|
||||
$dateTimeZone = $context[self::TIMEZONE_KEY] ?? $this->defaultContext[self::TIMEZONE_KEY];
|
||||
|
||||
if (null === $dateTimeZone) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $dateTimeZone instanceof \DateTimeZone ? $dateTimeZone : new \DateTimeZone($dateTimeZone);
|
||||
}
|
||||
|
||||
private function enforceTimezone(\DateTime|\DateTimeImmutable $object, array $context): \DateTimeInterface
|
||||
{
|
||||
$timezone = $this->getTimezone($context);
|
||||
$forceTimezone = $context[self::FORCE_TIMEZONE_KEY] ?? $this->defaultContext[self::FORCE_TIMEZONE_KEY];
|
||||
|
||||
if (null === $timezone || !$forceTimezone) {
|
||||
return $object;
|
||||
}
|
||||
|
||||
return $object->setTimezone($timezone);
|
||||
}
|
||||
}
|
||||
68
backend/vendor/symfony/serializer/Normalizer/DateTimeZoneNormalizer.php
vendored
Normal file
68
backend/vendor/symfony/serializer/Normalizer/DateTimeZoneNormalizer.php
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
|
||||
|
||||
/**
|
||||
* Normalizes a {@see \DateTimeZone} object to a timezone string.
|
||||
*
|
||||
* @author Jérôme Desjardins <jewome62@gmail.com>
|
||||
*/
|
||||
final class DateTimeZoneNormalizer implements NormalizerInterface, DenormalizerInterface
|
||||
{
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return [
|
||||
\DateTimeZone::class => true,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function normalize(mixed $data, ?string $format = null, array $context = []): string
|
||||
{
|
||||
if (!$data instanceof \DateTimeZone) {
|
||||
throw new InvalidArgumentException('The object must be an instance of "\DateTimeZone".');
|
||||
}
|
||||
|
||||
return $data->getName();
|
||||
}
|
||||
|
||||
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return $data instanceof \DateTimeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NotNormalizableValueException
|
||||
*/
|
||||
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): \DateTimeZone
|
||||
{
|
||||
if ('' === $data || null === $data) {
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType('The data is either an empty string or null, you should pass a string that can be parsed as a DateTimeZone.', $data, ['string'], $context['deserialization_path'] ?? null, true);
|
||||
}
|
||||
|
||||
try {
|
||||
return new \DateTimeZone($data);
|
||||
} catch (\Exception $e) {
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType($e->getMessage(), $data, ['string'], $context['deserialization_path'] ?? null, true, $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return \DateTimeZone::class === $type;
|
||||
}
|
||||
}
|
||||
38
backend/vendor/symfony/serializer/Normalizer/DenormalizableInterface.php
vendored
Normal file
38
backend/vendor/symfony/serializer/Normalizer/DenormalizableInterface.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
/**
|
||||
* Defines the most basic interface a class must implement to be denormalizable.
|
||||
*
|
||||
* If a denormalizer is registered for the class and it doesn't implement
|
||||
* the Denormalizable interfaces, the normalizer will be used instead
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
interface DenormalizableInterface
|
||||
{
|
||||
/**
|
||||
* Denormalizes the object back from an array of scalars|arrays.
|
||||
*
|
||||
* It is important to understand that the denormalize() call should denormalize
|
||||
* recursively all child objects of the implementer.
|
||||
*
|
||||
* @param DenormalizerInterface $denormalizer The denormalizer is given so that you
|
||||
* can use it to denormalize objects contained within this object
|
||||
* @param array|string|int|float|bool $data The data from which to re-create the object
|
||||
* @param string|null $format The format is optionally given to be able to denormalize
|
||||
* differently based on different input formats
|
||||
* @param array $context Options for denormalizing
|
||||
*/
|
||||
public function denormalize(DenormalizerInterface $denormalizer, array|string|int|float|bool $data, ?string $format = null, array $context = []): void;
|
||||
}
|
||||
23
backend/vendor/symfony/serializer/Normalizer/DenormalizerAwareInterface.php
vendored
Normal file
23
backend/vendor/symfony/serializer/Normalizer/DenormalizerAwareInterface.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
/**
|
||||
* @author Joel Wurtz <joel.wurtz@gmail.com>
|
||||
*/
|
||||
interface DenormalizerAwareInterface
|
||||
{
|
||||
/**
|
||||
* Sets the owning Denormalizer object.
|
||||
*/
|
||||
public function setDenormalizer(DenormalizerInterface $denormalizer): void;
|
||||
}
|
||||
25
backend/vendor/symfony/serializer/Normalizer/DenormalizerAwareTrait.php
vendored
Normal file
25
backend/vendor/symfony/serializer/Normalizer/DenormalizerAwareTrait.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
/**
|
||||
* @author Joel Wurtz <joel.wurtz@gmail.com>
|
||||
*/
|
||||
trait DenormalizerAwareTrait
|
||||
{
|
||||
protected DenormalizerInterface $denormalizer;
|
||||
|
||||
public function setDenormalizer(DenormalizerInterface $denormalizer): void
|
||||
{
|
||||
$this->denormalizer = $denormalizer;
|
||||
}
|
||||
}
|
||||
77
backend/vendor/symfony/serializer/Normalizer/DenormalizerInterface.php
vendored
Normal file
77
backend/vendor/symfony/serializer/Normalizer/DenormalizerInterface.php
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Exception\BadMethodCallException;
|
||||
use Symfony\Component\Serializer\Exception\ExceptionInterface;
|
||||
use Symfony\Component\Serializer\Exception\ExtraAttributesException;
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\LogicException;
|
||||
use Symfony\Component\Serializer\Exception\RuntimeException;
|
||||
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
interface DenormalizerInterface
|
||||
{
|
||||
public const COLLECT_DENORMALIZATION_ERRORS = 'collect_denormalization_errors';
|
||||
|
||||
/**
|
||||
* Denormalizes data back into an object of the given class.
|
||||
*
|
||||
* @template TObject of object
|
||||
*
|
||||
* @param mixed $data Data to restore
|
||||
* @param class-string<TObject>|string $type The expected class to instantiate
|
||||
* @param string|null $format Format the given data was extracted from
|
||||
* @param array<string, mixed> $context Options available to the denormalizer
|
||||
*
|
||||
* @return ($type is class-string<TObject> ? TObject : mixed)
|
||||
*
|
||||
* @throws BadMethodCallException Occurs when the normalizer is not called in an expected context
|
||||
* @throws InvalidArgumentException Occurs when the arguments are not coherent or not supported
|
||||
* @throws UnexpectedValueException Occurs when the item cannot be hydrated with the given data
|
||||
* @throws ExtraAttributesException Occurs when the item doesn't have attribute to receive given data
|
||||
* @throws LogicException Occurs when the normalizer is not supposed to denormalize
|
||||
* @throws RuntimeException Occurs if the class cannot be instantiated
|
||||
* @throws ExceptionInterface Occurs for all the other cases of errors
|
||||
*/
|
||||
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed;
|
||||
|
||||
/**
|
||||
* Checks whether the given class is supported for denormalization by this normalizer.
|
||||
*
|
||||
* @param mixed $data Data to denormalize from
|
||||
* @param string $type The class to which the data should be denormalized
|
||||
* @param string|null $format The format being deserialized from
|
||||
* @param array<string, mixed> $context Options available to the denormalizer
|
||||
*/
|
||||
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool;
|
||||
|
||||
/**
|
||||
* Returns the types potentially supported by this denormalizer.
|
||||
*
|
||||
* For each supported formats (if applicable), the supported types should be
|
||||
* returned as keys, and each type should be mapped to a boolean indicating
|
||||
* if the result of supportsDenormalization() can be cached or not
|
||||
* (a result cannot be cached when it depends on the context or on the data.)
|
||||
* A null value means that the denormalizer does not support the corresponding
|
||||
* type.
|
||||
*
|
||||
* Use type "object" to match any classes or interfaces,
|
||||
* and type "*" to match any types.
|
||||
*
|
||||
* @return array<class-string|'*'|'object'|string, bool|null>
|
||||
*/
|
||||
public function getSupportedTypes(?string $format): array;
|
||||
}
|
||||
85
backend/vendor/symfony/serializer/Normalizer/FormErrorNormalizer.php
vendored
Normal file
85
backend/vendor/symfony/serializer/Normalizer/FormErrorNormalizer.php
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
|
||||
/**
|
||||
* Normalizes invalid Form instances.
|
||||
*/
|
||||
final class FormErrorNormalizer implements NormalizerInterface
|
||||
{
|
||||
public const TITLE = 'title';
|
||||
public const TYPE = 'type';
|
||||
public const CODE = 'status_code';
|
||||
|
||||
public function normalize(mixed $data, ?string $format = null, array $context = []): array
|
||||
{
|
||||
$error = [
|
||||
'title' => $context[self::TITLE] ?? 'Validation Failed',
|
||||
'type' => $context[self::TYPE] ?? 'https://symfony.com/errors/form',
|
||||
'code' => $context[self::CODE] ?? null,
|
||||
'errors' => $this->convertFormErrorsToArray($data),
|
||||
];
|
||||
|
||||
if (0 !== \count($data->all())) {
|
||||
$error['children'] = $this->convertFormChildrenToArray($data);
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return [
|
||||
FormInterface::class => false,
|
||||
];
|
||||
}
|
||||
|
||||
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return $data instanceof FormInterface && $data->isSubmitted() && !$data->isValid();
|
||||
}
|
||||
|
||||
private function convertFormErrorsToArray(FormInterface $data): array
|
||||
{
|
||||
$errors = [];
|
||||
|
||||
foreach ($data->getErrors() as $error) {
|
||||
$errors[] = [
|
||||
'message' => $error->getMessage(),
|
||||
'cause' => $error->getCause(),
|
||||
];
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
private function convertFormChildrenToArray(FormInterface $data): array
|
||||
{
|
||||
$children = [];
|
||||
|
||||
foreach ($data->all() as $child) {
|
||||
$childData = [
|
||||
'errors' => $this->convertFormErrorsToArray($child),
|
||||
];
|
||||
|
||||
if ($child->all()) {
|
||||
$childData['children'] = $this->convertFormChildrenToArray($child);
|
||||
}
|
||||
|
||||
$children[$child->getName()] = $childData;
|
||||
}
|
||||
|
||||
return $children;
|
||||
}
|
||||
}
|
||||
212
backend/vendor/symfony/serializer/Normalizer/GetSetMethodNormalizer.php
vendored
Normal file
212
backend/vendor/symfony/serializer/Normalizer/GetSetMethodNormalizer.php
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Annotation\Ignore as LegacyIgnore;
|
||||
use Symfony\Component\Serializer\Attribute\Ignore;
|
||||
|
||||
/**
|
||||
* Converts between objects with getter and setter methods and arrays.
|
||||
*
|
||||
* The normalization process looks at all public methods and calls the ones
|
||||
* which have a name starting with get and take no parameters. The result is a
|
||||
* map from property names (method name stripped of the get prefix and converted
|
||||
* to lower case) to property values. Property values are normalized through the
|
||||
* serializer.
|
||||
*
|
||||
* The denormalization first looks at the constructor of the given class to see
|
||||
* if any of the parameters have the same name as one of the properties. The
|
||||
* constructor is then called with all parameters or an exception is thrown if
|
||||
* any required parameters were not present as properties. Then the denormalizer
|
||||
* walks through the given map of property names to property values to see if a
|
||||
* setter method exists for any of the properties. If a setter exists it is
|
||||
* called with the property value. No automatic denormalization of the value
|
||||
* takes place.
|
||||
*
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
final class GetSetMethodNormalizer extends AbstractObjectNormalizer
|
||||
{
|
||||
private static $reflectionCache = [];
|
||||
private static array $setterAccessibleCache = [];
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return ['object' => true];
|
||||
}
|
||||
|
||||
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return parent::supportsNormalization($data, $format) && $this->supports($data::class, true);
|
||||
}
|
||||
|
||||
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return parent::supportsDenormalization($data, $type, $format) && $this->supports($type, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given class has any getter or setter method.
|
||||
*/
|
||||
private function supports(string $class, bool $readAttributes): bool
|
||||
{
|
||||
if ($this->classDiscriminatorResolver?->getMappingForClass($class)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isset(self::$reflectionCache[$class])) {
|
||||
self::$reflectionCache[$class] = new \ReflectionClass($class);
|
||||
}
|
||||
|
||||
$reflection = self::$reflectionCache[$class];
|
||||
|
||||
foreach ($reflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
|
||||
if ($readAttributes ? $this->isGetMethod($reflectionMethod) : $this->isSetMethod($reflectionMethod)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a method's name matches /^(get|is|has).+$/ and can be called non-statically without parameters.
|
||||
*/
|
||||
private function isGetMethod(\ReflectionMethod $method): bool
|
||||
{
|
||||
return !$method->isStatic()
|
||||
&& !($method->getAttributes(Ignore::class) || $method->getAttributes(LegacyIgnore::class))
|
||||
&& !$method->getNumberOfRequiredParameters()
|
||||
&& !\in_array((string) $method->getReturnType(), ['void', 'never'], true)
|
||||
&& ((2 < ($methodLength = \strlen($method->name)) && str_starts_with($method->name, 'is') && !ctype_lower($method->name[2]))
|
||||
|| (3 < $methodLength && (str_starts_with($method->name, 'has') || str_starts_with($method->name, 'get') || str_starts_with($method->name, 'can')) && !ctype_lower($method->name[3]))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a method's name matches /^set.+$/ and can be called non-statically with one parameter.
|
||||
*/
|
||||
private function isSetMethod(\ReflectionMethod $method): bool
|
||||
{
|
||||
return !$method->isStatic()
|
||||
&& !$method->getAttributes(Ignore::class)
|
||||
&& 0 < $method->getNumberOfParameters()
|
||||
&& 3 < \strlen($method->name)
|
||||
&& str_starts_with($method->name, 'set')
|
||||
&& !ctype_lower($method->name[3])
|
||||
;
|
||||
}
|
||||
|
||||
protected function extractAttributes(object $object, ?string $format = null, array $context = []): array
|
||||
{
|
||||
$reflectionObject = new \ReflectionObject($object);
|
||||
$reflectionMethods = $reflectionObject->getMethods(\ReflectionMethod::IS_PUBLIC);
|
||||
|
||||
$attributes = [];
|
||||
foreach ($reflectionMethods as $method) {
|
||||
if (!$this->isGetMethod($method)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attributeName = lcfirst(substr($method->name, str_starts_with($method->name, 'is') ? 2 : 3));
|
||||
|
||||
if ($this->isAllowedAttribute($object, $attributeName, $format, $context)) {
|
||||
$attributes[] = $attributeName;
|
||||
}
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
protected function getAttributeValue(object $object, string $attribute, ?string $format = null, array $context = []): mixed
|
||||
{
|
||||
$getter = 'get'.$attribute;
|
||||
if (method_exists($object, $getter) && \is_callable([$object, $getter])) {
|
||||
return $object->$getter();
|
||||
}
|
||||
|
||||
$isser = 'is'.$attribute;
|
||||
if (method_exists($object, $isser) && \is_callable([$object, $isser])) {
|
||||
return $object->$isser();
|
||||
}
|
||||
|
||||
$haser = 'has'.$attribute;
|
||||
if (method_exists($object, $haser) && \is_callable([$object, $haser])) {
|
||||
return $object->$haser();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function setAttributeValue(object $object, string $attribute, mixed $value, ?string $format = null, array $context = []): void
|
||||
{
|
||||
$setter = 'set'.$attribute;
|
||||
$key = $object::class.':'.$setter;
|
||||
|
||||
if (!isset(self::$setterAccessibleCache[$key])) {
|
||||
self::$setterAccessibleCache[$key] = method_exists($object, $setter) && \is_callable([$object, $setter]) && !(new \ReflectionMethod($object, $setter))->isStatic();
|
||||
}
|
||||
|
||||
if (self::$setterAccessibleCache[$key]) {
|
||||
$object->$setter($value);
|
||||
}
|
||||
}
|
||||
|
||||
protected function isAllowedAttribute($classOrObject, string $attribute, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
if (!parent::isAllowedAttribute($classOrObject, $attribute, $format, $context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$class = \is_object($classOrObject) ? $classOrObject::class : $classOrObject;
|
||||
|
||||
if ($this->classDiscriminatorResolver?->getMappingForMappedObject($classOrObject)?->getTypeProperty() === $attribute) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isset(self::$reflectionCache[$class])) {
|
||||
self::$reflectionCache[$class] = new \ReflectionClass($class);
|
||||
}
|
||||
|
||||
$reflection = self::$reflectionCache[$class];
|
||||
|
||||
if ($context['_read_attributes'] ?? true) {
|
||||
foreach (['get', 'is', 'has'] as $getterPrefix) {
|
||||
$getter = $getterPrefix.$attribute;
|
||||
$reflectionMethod = $reflection->hasMethod($getter) ? $reflection->getMethod($getter) : null;
|
||||
if ($reflectionMethod && $this->isGetMethod($reflectionMethod)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$setter = 'set'.$attribute;
|
||||
if ($reflection->hasMethod($setter) && $this->isSetMethod($reflection->getMethod($setter))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$constructor = $reflection->getConstructor();
|
||||
|
||||
if ($constructor && $constructor->isPublic()) {
|
||||
foreach ($constructor->getParameters() as $parameter) {
|
||||
if ($parameter->getName() === $attribute) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
62
backend/vendor/symfony/serializer/Normalizer/JsonSerializableNormalizer.php
vendored
Normal file
62
backend/vendor/symfony/serializer/Normalizer/JsonSerializableNormalizer.php
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\LogicException;
|
||||
|
||||
/**
|
||||
* A normalizer that uses an objects own JsonSerializable implementation.
|
||||
*
|
||||
* @author Fred Cox <mcfedr@gmail.com>
|
||||
*/
|
||||
final class JsonSerializableNormalizer extends AbstractNormalizer
|
||||
{
|
||||
public function normalize(mixed $data, ?string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null
|
||||
{
|
||||
if ($this->isCircularReference($data, $context)) {
|
||||
return $this->handleCircularReference($data, $format, $context);
|
||||
}
|
||||
|
||||
if (!$data instanceof \JsonSerializable) {
|
||||
throw new InvalidArgumentException(\sprintf('The object must implement "%s".', \JsonSerializable::class));
|
||||
}
|
||||
|
||||
if (!$this->serializer instanceof NormalizerInterface) {
|
||||
throw new LogicException('Cannot normalize object because injected serializer is not a normalizer.');
|
||||
}
|
||||
|
||||
return $this->serializer->normalize($data->jsonSerialize(), $format, $context);
|
||||
}
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return [
|
||||
\JsonSerializable::class => true,
|
||||
];
|
||||
}
|
||||
|
||||
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return $data instanceof \JsonSerializable;
|
||||
}
|
||||
|
||||
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed
|
||||
{
|
||||
throw new LogicException(\sprintf('Cannot denormalize with "%s".', \JsonSerializable::class));
|
||||
}
|
||||
}
|
||||
121
backend/vendor/symfony/serializer/Normalizer/MimeMessageNormalizer.php
vendored
Normal file
121
backend/vendor/symfony/serializer/Normalizer/MimeMessageNormalizer.php
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Mime\Address;
|
||||
use Symfony\Component\Mime\Header\HeaderInterface;
|
||||
use Symfony\Component\Mime\Header\Headers;
|
||||
use Symfony\Component\Mime\Header\UnstructuredHeader;
|
||||
use Symfony\Component\Mime\Message;
|
||||
use Symfony\Component\Mime\Part\AbstractPart;
|
||||
use Symfony\Component\Mime\RawMessage;
|
||||
use Symfony\Component\Serializer\Exception\LogicException;
|
||||
use Symfony\Component\Serializer\SerializerAwareInterface;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
|
||||
/**
|
||||
* Normalize Mime message classes.
|
||||
*
|
||||
* It forces the use of a PropertyNormalizer instance for normalization
|
||||
* of all data objects composing a Message.
|
||||
*
|
||||
* Emails using resources for any parts are not serializable.
|
||||
*/
|
||||
final class MimeMessageNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface
|
||||
{
|
||||
private NormalizerInterface&DenormalizerInterface $serializer;
|
||||
private array $headerClassMap;
|
||||
private \ReflectionProperty $headersProperty;
|
||||
|
||||
public function __construct(private readonly PropertyNormalizer $normalizer)
|
||||
{
|
||||
$this->headerClassMap = (new \ReflectionClassConstant(Headers::class, 'HEADER_CLASS_MAP'))->getValue();
|
||||
$this->headersProperty = new \ReflectionProperty(Headers::class, 'headers');
|
||||
}
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return [
|
||||
Message::class => true,
|
||||
Headers::class => true,
|
||||
HeaderInterface::class => true,
|
||||
Address::class => true,
|
||||
AbstractPart::class => true,
|
||||
];
|
||||
}
|
||||
|
||||
public function setSerializer(SerializerInterface $serializer): void
|
||||
{
|
||||
if (!$serializer instanceof NormalizerInterface || !$serializer instanceof DenormalizerInterface) {
|
||||
throw new LogicException(\sprintf('The passed serializer should implement both NormalizerInterface and DenormalizerInterface, "%s" given.', get_debug_type($serializer)));
|
||||
}
|
||||
$this->serializer = $serializer;
|
||||
$this->normalizer->setSerializer($serializer);
|
||||
}
|
||||
|
||||
public function normalize(mixed $data, ?string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null
|
||||
{
|
||||
if ($data instanceof Headers) {
|
||||
$ret = [];
|
||||
foreach ($this->headersProperty->getValue($data) as $name => $header) {
|
||||
$ret[$name] = $this->serializer->normalize($header, $format, $context);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
$ret = $this->normalizer->normalize($data, $format, $context);
|
||||
|
||||
if ($data instanceof AbstractPart) {
|
||||
$ret['class'] = $data::class;
|
||||
unset($ret['seekable'], $ret['cid'], $ret['handle']);
|
||||
}
|
||||
|
||||
if ($data instanceof RawMessage && \array_key_exists('message', $ret) && null === $ret['message']) {
|
||||
unset($ret['message']);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed
|
||||
{
|
||||
if (Headers::class === $type) {
|
||||
$ret = [];
|
||||
foreach ($data as $headers) {
|
||||
foreach ($headers as $header) {
|
||||
$ret[] = $this->serializer->denormalize($header, $this->headerClassMap[strtolower($header['name'])] ?? UnstructuredHeader::class, $format, $context);
|
||||
}
|
||||
}
|
||||
|
||||
return new Headers(...$ret);
|
||||
}
|
||||
|
||||
if (AbstractPart::class === $type) {
|
||||
$type = $data['class'];
|
||||
unset($data['class']);
|
||||
$data['headers'] = $this->serializer->denormalize($data['headers'], Headers::class, $format, $context);
|
||||
}
|
||||
|
||||
return $this->normalizer->denormalize($data, $type, $format, $context);
|
||||
}
|
||||
|
||||
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return $data instanceof Message || $data instanceof Headers || $data instanceof HeaderInterface || $data instanceof Address || $data instanceof AbstractPart;
|
||||
}
|
||||
|
||||
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return is_a($type, Message::class, true) || Headers::class === $type || AbstractPart::class === $type;
|
||||
}
|
||||
}
|
||||
37
backend/vendor/symfony/serializer/Normalizer/NormalizableInterface.php
vendored
Normal file
37
backend/vendor/symfony/serializer/Normalizer/NormalizableInterface.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
/**
|
||||
* Defines the most basic interface a class must implement to be normalizable.
|
||||
*
|
||||
* If a normalizer is registered for the class and it doesn't implement
|
||||
* the Normalizable interfaces, the normalizer will be used instead.
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
interface NormalizableInterface
|
||||
{
|
||||
/**
|
||||
* Normalizes the object into an array of scalars|arrays.
|
||||
*
|
||||
* It is important to understand that the normalize() call should normalize
|
||||
* recursively all child objects of the implementer.
|
||||
*
|
||||
* @param NormalizerInterface $normalizer The normalizer is given so that you
|
||||
* can use it to normalize objects contained within this object
|
||||
* @param string|null $format The format is optionally given to be able to normalize differently
|
||||
* based on different output formats
|
||||
* @param array $context Options for normalizing this object
|
||||
*/
|
||||
public function normalize(NormalizerInterface $normalizer, ?string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null;
|
||||
}
|
||||
23
backend/vendor/symfony/serializer/Normalizer/NormalizerAwareInterface.php
vendored
Normal file
23
backend/vendor/symfony/serializer/Normalizer/NormalizerAwareInterface.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
/**
|
||||
* @author Joel Wurtz <joel.wurtz@gmail.com>
|
||||
*/
|
||||
interface NormalizerAwareInterface
|
||||
{
|
||||
/**
|
||||
* Sets the owning Normalizer object.
|
||||
*/
|
||||
public function setNormalizer(NormalizerInterface $normalizer): void;
|
||||
}
|
||||
25
backend/vendor/symfony/serializer/Normalizer/NormalizerAwareTrait.php
vendored
Normal file
25
backend/vendor/symfony/serializer/Normalizer/NormalizerAwareTrait.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
/**
|
||||
* @author Joel Wurtz <joel.wurtz@gmail.com>
|
||||
*/
|
||||
trait NormalizerAwareTrait
|
||||
{
|
||||
protected NormalizerInterface $normalizer;
|
||||
|
||||
public function setNormalizer(NormalizerInterface $normalizer): void
|
||||
{
|
||||
$this->normalizer = $normalizer;
|
||||
}
|
||||
}
|
||||
66
backend/vendor/symfony/serializer/Normalizer/NormalizerInterface.php
vendored
Normal file
66
backend/vendor/symfony/serializer/Normalizer/NormalizerInterface.php
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Exception\CircularReferenceException;
|
||||
use Symfony\Component\Serializer\Exception\ExceptionInterface;
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\LogicException;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
interface NormalizerInterface
|
||||
{
|
||||
/**
|
||||
* Normalizes data into a set of arrays/scalars.
|
||||
*
|
||||
* @param mixed $data Data to normalize
|
||||
* @param string|null $format Format the normalization result will be encoded as
|
||||
* @param array<string, mixed> $context Context options for the normalizer
|
||||
*
|
||||
* @return array|string|int|float|bool|\ArrayObject|null \ArrayObject is used to make sure an empty object is encoded as an object not an array
|
||||
*
|
||||
* @throws InvalidArgumentException Occurs when the object given is not a supported type for the normalizer
|
||||
* @throws CircularReferenceException Occurs when the normalizer detects a circular reference when no circular
|
||||
* reference handler can fix it
|
||||
* @throws LogicException Occurs when the normalizer is not called in an expected context
|
||||
* @throws ExceptionInterface Occurs for all the other cases of errors
|
||||
*/
|
||||
public function normalize(mixed $data, ?string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null;
|
||||
|
||||
/**
|
||||
* Checks whether the given class is supported for normalization by this normalizer.
|
||||
*
|
||||
* @param mixed $data Data to normalize
|
||||
* @param string|null $format The format being (de-)serialized from or into
|
||||
* @param array<string, mixed> $context Context options for the normalizer
|
||||
*/
|
||||
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool;
|
||||
|
||||
/**
|
||||
* Returns the types potentially supported by this normalizer.
|
||||
*
|
||||
* For each supported formats (if applicable), the supported types should be
|
||||
* returned as keys, and each type should be mapped to a boolean indicating
|
||||
* if the result of supportsNormalization() can be cached or not
|
||||
* (a result cannot be cached when it depends on the context or on the data.)
|
||||
* A null value means that the normalizer does not support the corresponding
|
||||
* type.
|
||||
*
|
||||
* Use type "object" to match any classes or interfaces,
|
||||
* and type "*" to match any types.
|
||||
*
|
||||
* @return array<class-string|'*'|'object'|string, bool|null>
|
||||
*/
|
||||
public function getSupportedTypes(?string $format): array;
|
||||
}
|
||||
79
backend/vendor/symfony/serializer/Normalizer/NumberNormalizer.php
vendored
Normal file
79
backend/vendor/symfony/serializer/Normalizer/NumberNormalizer.php
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use BcMath\Number;
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
|
||||
|
||||
/**
|
||||
* Normalizes {@see Number} and {@see \GMP} to a string.
|
||||
*/
|
||||
final class NumberNormalizer implements NormalizerInterface, DenormalizerInterface
|
||||
{
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return [
|
||||
Number::class => true,
|
||||
\GMP::class => true,
|
||||
];
|
||||
}
|
||||
|
||||
public function normalize(mixed $data, ?string $format = null, array $context = []): string
|
||||
{
|
||||
if (!$data instanceof Number && !$data instanceof \GMP) {
|
||||
throw new InvalidArgumentException(\sprintf('The data must be an instance of "%s" or "%s".', Number::class, \GMP::class));
|
||||
}
|
||||
|
||||
return (string) $data;
|
||||
}
|
||||
|
||||
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return $data instanceof Number || $data instanceof \GMP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NotNormalizableValueException
|
||||
*/
|
||||
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): Number|\GMP
|
||||
{
|
||||
if (!\is_string($data) && !\is_int($data)) {
|
||||
throw $this->createNotNormalizableValueException($type, $data, $context);
|
||||
}
|
||||
|
||||
try {
|
||||
return match ($type) {
|
||||
Number::class => new Number($data),
|
||||
\GMP::class => new \GMP($data),
|
||||
default => throw new InvalidArgumentException(\sprintf('Only "%s" and "%s" types are supported.', Number::class, \GMP::class)),
|
||||
};
|
||||
} catch (\ValueError $e) {
|
||||
throw $this->createNotNormalizableValueException($type, $data, $context, $e);
|
||||
}
|
||||
}
|
||||
|
||||
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return \in_array($type, [Number::class, \GMP::class], true) && null !== $data;
|
||||
}
|
||||
|
||||
private function createNotNormalizableValueException(string $type, mixed $data, array $context, ?\Throwable $previous = null): NotNormalizableValueException
|
||||
{
|
||||
$message = match ($type) {
|
||||
Number::class => 'The data must be a "string" representing a decimal number, or an "int".',
|
||||
\GMP::class => 'The data must be a "string" representing an integer, or an "int".',
|
||||
};
|
||||
|
||||
return NotNormalizableValueException::createForUnexpectedDataType($message, $data, ['string', 'int'], $context['deserialization_path'] ?? null, true, 0, $previous);
|
||||
}
|
||||
}
|
||||
178
backend/vendor/symfony/serializer/Normalizer/ObjectNormalizer.php
vendored
Normal file
178
backend/vendor/symfony/serializer/Normalizer/ObjectNormalizer.php
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
|
||||
use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
|
||||
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
|
||||
use Symfony\Component\PropertyInfo\PropertyWriteInfo;
|
||||
use Symfony\Component\Serializer\Attribute\Ignore;
|
||||
use Symfony\Component\Serializer\Exception\LogicException;
|
||||
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorResolverInterface;
|
||||
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
|
||||
use Symfony\Component\Serializer\Mapping\Loader\AccessorCollisionResolverTrait;
|
||||
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
|
||||
|
||||
/**
|
||||
* Converts between objects and arrays using the PropertyAccess component.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
final class ObjectNormalizer extends AbstractObjectNormalizer
|
||||
{
|
||||
use AccessorCollisionResolverTrait;
|
||||
|
||||
private static $reflectionCache = [];
|
||||
private static $isReadableCache = [];
|
||||
private static $isWritableCache = [];
|
||||
|
||||
protected PropertyAccessorInterface $propertyAccessor;
|
||||
protected $propertyInfoExtractor;
|
||||
private $writeInfoExtractor;
|
||||
|
||||
private readonly \Closure $objectClassResolver;
|
||||
|
||||
public function __construct(?ClassMetadataFactoryInterface $classMetadataFactory = null, ?NameConverterInterface $nameConverter = null, ?PropertyAccessorInterface $propertyAccessor = null, ?PropertyTypeExtractorInterface $propertyTypeExtractor = null, ?ClassDiscriminatorResolverInterface $classDiscriminatorResolver = null, ?callable $objectClassResolver = null, array $defaultContext = [], ?PropertyInfoExtractorInterface $propertyInfoExtractor = null)
|
||||
{
|
||||
if (!class_exists(PropertyAccess::class)) {
|
||||
throw new LogicException('The ObjectNormalizer class requires the "PropertyAccess" component. Try running "composer require symfony/property-access".');
|
||||
}
|
||||
|
||||
parent::__construct($classMetadataFactory, $nameConverter, $propertyTypeExtractor, $classDiscriminatorResolver, $objectClassResolver, $defaultContext);
|
||||
|
||||
$this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor();
|
||||
|
||||
$this->objectClassResolver = ($objectClassResolver ?? static fn ($class) => \is_object($class) ? $class::class : $class)(...);
|
||||
$this->propertyInfoExtractor = $propertyInfoExtractor ?: new ReflectionExtractor();
|
||||
$this->writeInfoExtractor = new ReflectionExtractor();
|
||||
}
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return ['object' => true];
|
||||
}
|
||||
|
||||
protected function extractAttributes(object $object, ?string $format = null, array $context = []): array
|
||||
{
|
||||
if (\stdClass::class === $object::class) {
|
||||
return array_keys((array) $object);
|
||||
}
|
||||
|
||||
// If not using groups, detect manually
|
||||
$attributes = [];
|
||||
|
||||
// methods
|
||||
$class = ($this->objectClassResolver)($object);
|
||||
$reflClass = new \ReflectionClass($class);
|
||||
|
||||
foreach ($reflClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflMethod) {
|
||||
$name = $reflMethod->name;
|
||||
$attributeName = $this->getAttributeNameFromAccessor($reflClass, $reflMethod, false);
|
||||
|
||||
if ($this->hasPropertyForAccessor($reflMethod->getDeclaringClass(), $name) && (null === $attributeName || $this->hasAttributeNameCollision($reflClass, $attributeName, $name))) {
|
||||
$attributeName = $name;
|
||||
}
|
||||
|
||||
if (null !== $attributeName && $this->isAllowedAttribute($object, $attributeName, $format, $context)) {
|
||||
$attributes[$attributeName] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// properties
|
||||
foreach ($reflClass->getProperties() as $reflProperty) {
|
||||
if (!$reflProperty->isPublic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($reflProperty->isStatic() || !$this->isAllowedAttribute($object, $reflProperty->name, $format, $context)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attributes[$reflProperty->name] = true;
|
||||
}
|
||||
|
||||
return array_keys($attributes);
|
||||
}
|
||||
|
||||
protected function getAttributeValue(object $object, string $attribute, ?string $format = null, array $context = []): mixed
|
||||
{
|
||||
$mapping = $this->classDiscriminatorResolver?->getMappingForMappedObject($object);
|
||||
|
||||
return $attribute === $mapping?->getTypeProperty()
|
||||
? $mapping
|
||||
: $this->propertyAccessor->getValue($object, $attribute);
|
||||
}
|
||||
|
||||
protected function setAttributeValue(object $object, string $attribute, mixed $value, ?string $format = null, array $context = []): void
|
||||
{
|
||||
try {
|
||||
$this->propertyAccessor->setValue($object, $attribute, $value);
|
||||
} catch (NoSuchPropertyException) {
|
||||
// Properties not found are ignored
|
||||
}
|
||||
}
|
||||
|
||||
protected function isAllowedAttribute($classOrObject, string $attribute, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
if (!parent::isAllowedAttribute($classOrObject, $attribute, $format, $context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$class = \is_object($classOrObject) ? $classOrObject::class : $classOrObject;
|
||||
|
||||
if ($this->classDiscriminatorResolver?->getMappingForMappedObject($classOrObject)?->getTypeProperty() === $attribute) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($context['_read_attributes'] ?? true) {
|
||||
$context = array_intersect_key($context, ['enable_getter_setter_extraction' => true, 'enable_magic_methods_extraction' => true]);
|
||||
$cacheKey = $class.$attribute.hash('xxh128', serialize($context));
|
||||
|
||||
return self::$isReadableCache[$cacheKey] ??= $this->propertyInfoExtractor->isReadable($class, $attribute, $context) || $this->hasAttributeAccessorMethod($class, $attribute) || (\is_object($classOrObject) && $this->propertyAccessor->isReadable($classOrObject, $attribute));
|
||||
}
|
||||
|
||||
$context = array_intersect_key($context, ['enable_getter_setter_extraction' => true, 'enable_magic_methods_extraction' => true, 'enable_constructor_extraction' => true, 'enable_adder_remover_extraction' => true]);
|
||||
$cacheKey = $class.$attribute.hash('xxh128', serialize($context));
|
||||
|
||||
if (isset(self::$isWritableCache[$cacheKey])) {
|
||||
return self::$isWritableCache[$cacheKey];
|
||||
}
|
||||
|
||||
if (str_contains($attribute, '.') || $this->propertyInfoExtractor->isWritable($class, $attribute, $context)) {
|
||||
return self::$isWritableCache[$cacheKey] = true;
|
||||
}
|
||||
|
||||
$writeType = $this->writeInfoExtractor->getWriteInfo($class, $attribute, $context)?->getType();
|
||||
|
||||
return self::$isWritableCache[$cacheKey] = !\in_array($writeType, [null, PropertyWriteInfo::TYPE_NONE], true)
|
||||
&& (PropertyWriteInfo::TYPE_PROPERTY !== $writeType || !property_exists($class, $attribute));
|
||||
}
|
||||
|
||||
private function hasAttributeAccessorMethod(string $class, string $attribute): bool
|
||||
{
|
||||
$reflection = self::$reflectionCache[$class] ??= new \ReflectionClass($class);
|
||||
|
||||
if (!$reflection->hasMethod($attribute)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$method = $reflection->getMethod($attribute);
|
||||
|
||||
return !$method->isStatic()
|
||||
&& !$method->getAttributes(Ignore::class)
|
||||
&& !$method->getNumberOfRequiredParameters()
|
||||
&& !\in_array((string) $method->getReturnType(), ['void', 'never'], true);
|
||||
}
|
||||
}
|
||||
34
backend/vendor/symfony/serializer/Normalizer/ObjectToPopulateTrait.php
vendored
Normal file
34
backend/vendor/symfony/serializer/Normalizer/ObjectToPopulateTrait.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
trait ObjectToPopulateTrait
|
||||
{
|
||||
/**
|
||||
* Extract the `object_to_populate` field from the context if it exists
|
||||
* and is an instance of the provided $class.
|
||||
*
|
||||
* @param string $class The class the object should be
|
||||
* @param string|null $key They in which to look for the object to populate.
|
||||
* Keeps backwards compatibility with `AbstractNormalizer`.
|
||||
*/
|
||||
protected function extractObjectToPopulate(string $class, array $context, ?string $key = null): ?object
|
||||
{
|
||||
$key ??= AbstractNormalizer::OBJECT_TO_POPULATE;
|
||||
|
||||
if (isset($context[$key]) && \is_object($context[$key]) && $context[$key] instanceof $class) {
|
||||
return $context[$key];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
114
backend/vendor/symfony/serializer/Normalizer/ProblemNormalizer.php
vendored
Normal file
114
backend/vendor/symfony/serializer/Normalizer/ProblemNormalizer.php
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\ErrorHandler\Exception\FlattenException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
|
||||
use Symfony\Component\Messenger\Exception\ValidationFailedException as MessageValidationFailedException;
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\PartialDenormalizationException;
|
||||
use Symfony\Component\Serializer\SerializerAwareInterface;
|
||||
use Symfony\Component\Serializer\SerializerAwareTrait;
|
||||
use Symfony\Component\Validator\Exception\ValidationFailedException;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* Normalizes errors according to the API Problem spec (RFC 7807).
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc7807
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
* @author Yonel Ceruto <yonelceruto@gmail.com>
|
||||
*/
|
||||
class ProblemNormalizer implements NormalizerInterface, SerializerAwareInterface
|
||||
{
|
||||
use SerializerAwareTrait;
|
||||
|
||||
public const TITLE = 'title';
|
||||
public const TYPE = 'type';
|
||||
public const STATUS = 'status';
|
||||
|
||||
public function __construct(
|
||||
private bool $debug = false,
|
||||
private array $defaultContext = [],
|
||||
private ?TranslatorInterface $translator = null,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return [
|
||||
FlattenException::class => __CLASS__ === self::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function normalize(mixed $object, ?string $format = null, array $context = []): array
|
||||
{
|
||||
if (!$object instanceof FlattenException) {
|
||||
throw new InvalidArgumentException(\sprintf('The object must implement "%s".', FlattenException::class));
|
||||
}
|
||||
|
||||
$error = [];
|
||||
$context += $this->defaultContext;
|
||||
$debug = $this->debug && ($context['debug'] ?? true);
|
||||
$exception = $context['exception'] ?? null;
|
||||
if ($exception instanceof HttpExceptionInterface) {
|
||||
$exception = $exception->getPrevious();
|
||||
|
||||
if ($exception instanceof PartialDenormalizationException) {
|
||||
$trans = $this->translator ? $this->translator->trans(...) : fn ($m, $p) => strtr($m, $p);
|
||||
$template = 'This value should be of type {{ type }}.';
|
||||
$error = [
|
||||
self::TYPE => 'https://symfony.com/errors/validation',
|
||||
self::TITLE => 'Validation Failed',
|
||||
'violations' => array_map(
|
||||
fn ($e) => [
|
||||
'propertyPath' => $e->getPath(),
|
||||
'title' => $trans($template, [
|
||||
'{{ type }}' => implode('|', $e->getExpectedTypes() ?? ['?']),
|
||||
], 'validators'),
|
||||
'template' => $template,
|
||||
'parameters' => [
|
||||
'{{ type }}' => implode('|', $e->getExpectedTypes() ?? ['?']),
|
||||
],
|
||||
] + ($debug || $e->canUseMessageForUser() ? ['hint' => $e->getMessage()] : []),
|
||||
$exception->getErrors()
|
||||
),
|
||||
];
|
||||
$error['detail'] = implode("\n", array_map(fn ($e) => $e['propertyPath'].': '.$e['title'], $error['violations']));
|
||||
} elseif (($exception instanceof ValidationFailedException || $exception instanceof MessageValidationFailedException)
|
||||
&& $this->serializer instanceof NormalizerInterface
|
||||
&& $this->serializer->supportsNormalization($exception->getViolations(), $format, $context)
|
||||
) {
|
||||
$error = $this->serializer->normalize($exception->getViolations(), $format, $context);
|
||||
}
|
||||
}
|
||||
|
||||
$error = [
|
||||
self::TYPE => $error[self::TYPE] ?? $context[self::TYPE] ?? 'https://tools.ietf.org/html/rfc2616#section-10',
|
||||
self::TITLE => $error[self::TITLE] ?? $context[self::TITLE] ?? 'An error occurred',
|
||||
self::STATUS => $context[self::STATUS] ?? $object->getStatusCode(),
|
||||
'detail' => $error['detail'] ?? ($debug ? $object->getMessage() : $object->getStatusText()),
|
||||
] + $error;
|
||||
if ($debug) {
|
||||
$error['class'] = $object->getClass();
|
||||
$error['trace'] = $object->getTrace();
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return $data instanceof FlattenException;
|
||||
}
|
||||
}
|
||||
223
backend/vendor/symfony/serializer/Normalizer/PropertyNormalizer.php
vendored
Normal file
223
backend/vendor/symfony/serializer/Normalizer/PropertyNormalizer.php
vendored
Normal file
@@ -0,0 +1,223 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException;
|
||||
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
|
||||
use Symfony\Component\Serializer\Exception\LogicException;
|
||||
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorResolverInterface;
|
||||
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
|
||||
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
|
||||
|
||||
/**
|
||||
* Converts between objects and arrays by mapping properties.
|
||||
*
|
||||
* The normalization process looks for all the object's properties (public and private).
|
||||
* The result is a map from property names to property values. Property values
|
||||
* are normalized through the serializer.
|
||||
*
|
||||
* The denormalization first looks at the constructor of the given class to see
|
||||
* if any of the parameters have the same name as one of the properties. The
|
||||
* constructor is then called with all parameters or an exception is thrown if
|
||||
* any required parameters were not present as properties. Then the denormalizer
|
||||
* walks through the given map of property names to property values to see if a
|
||||
* property with the corresponding name exists. If found, the property gets the value.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
final class PropertyNormalizer extends AbstractObjectNormalizer
|
||||
{
|
||||
public const NORMALIZE_PUBLIC = 1;
|
||||
public const NORMALIZE_PROTECTED = 2;
|
||||
public const NORMALIZE_PRIVATE = 4;
|
||||
|
||||
/**
|
||||
* Flag to control whether fields should be output based on visibility.
|
||||
*/
|
||||
public const NORMALIZE_VISIBILITY = 'normalize_visibility';
|
||||
|
||||
public function __construct(?ClassMetadataFactoryInterface $classMetadataFactory = null, ?NameConverterInterface $nameConverter = null, ?PropertyTypeExtractorInterface $propertyTypeExtractor = null, ?ClassDiscriminatorResolverInterface $classDiscriminatorResolver = null, ?callable $objectClassResolver = null, array $defaultContext = [])
|
||||
{
|
||||
parent::__construct($classMetadataFactory, $nameConverter, $propertyTypeExtractor, $classDiscriminatorResolver, $objectClassResolver, $defaultContext);
|
||||
|
||||
if (!isset($this->defaultContext[self::NORMALIZE_VISIBILITY])) {
|
||||
$this->defaultContext[self::NORMALIZE_VISIBILITY] = self::NORMALIZE_PUBLIC | self::NORMALIZE_PROTECTED | self::NORMALIZE_PRIVATE;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return ['object' => true];
|
||||
}
|
||||
|
||||
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return parent::supportsNormalization($data, $format) && $this->supports($data::class);
|
||||
}
|
||||
|
||||
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return parent::supportsDenormalization($data, $type, $format) && $this->supports($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given class has any non-static property.
|
||||
*/
|
||||
private function supports(string $class): bool
|
||||
{
|
||||
if ($this->classDiscriminatorResolver?->getMappingForClass($class)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$class = new \ReflectionClass($class);
|
||||
|
||||
// We look for at least one non-static property
|
||||
do {
|
||||
foreach ($class->getProperties() as $property) {
|
||||
if (!$property->isStatic()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} while ($class = $class->getParentClass());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function isAllowedAttribute(object|string $classOrObject, string $attribute, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
if (!parent::isAllowedAttribute($classOrObject, $attribute, $format, $context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->classDiscriminatorResolver?->getMappingForMappedObject($classOrObject)?->getTypeProperty() === $attribute) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
$reflectionProperty = $this->getReflectionProperty($classOrObject, $attribute);
|
||||
} catch (\ReflectionException) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($reflectionProperty->isStatic()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$normalizeVisibility = $context[self::NORMALIZE_VISIBILITY] ?? $this->defaultContext[self::NORMALIZE_VISIBILITY];
|
||||
|
||||
if ((self::NORMALIZE_PUBLIC & $normalizeVisibility) && $reflectionProperty->isPublic()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((self::NORMALIZE_PROTECTED & $normalizeVisibility) && $reflectionProperty->isProtected()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((self::NORMALIZE_PRIVATE & $normalizeVisibility) && $reflectionProperty->isPrivate()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function extractAttributes(object $object, ?string $format = null, array $context = []): array
|
||||
{
|
||||
$reflectionObject = new \ReflectionObject($object);
|
||||
$attributes = [];
|
||||
|
||||
do {
|
||||
foreach ($reflectionObject->getProperties() as $property) {
|
||||
if (!$this->isAllowedAttribute($reflectionObject->getName(), $property->name, $format, $context)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attributes[] = $property->name;
|
||||
}
|
||||
} while ($reflectionObject = $reflectionObject->getParentClass());
|
||||
|
||||
return array_unique($attributes);
|
||||
}
|
||||
|
||||
protected function getAttributeValue(object $object, string $attribute, ?string $format = null, array $context = []): mixed
|
||||
{
|
||||
try {
|
||||
$reflectionProperty = $this->getReflectionProperty($object, $attribute);
|
||||
} catch (\ReflectionException) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($reflectionProperty->hasType()) {
|
||||
return $reflectionProperty->getValue($object);
|
||||
}
|
||||
|
||||
if (!method_exists($object, '__get') && !isset($object->$attribute)) {
|
||||
$propertyValues = (array) $object;
|
||||
|
||||
if (($reflectionProperty->isPublic() && !\array_key_exists($reflectionProperty->name, $propertyValues))
|
||||
|| ($reflectionProperty->isProtected() && !\array_key_exists("\0*\0{$reflectionProperty->name}", $propertyValues))
|
||||
|| ($reflectionProperty->isPrivate() && !\array_key_exists("\0{$reflectionProperty->class}\0{$reflectionProperty->name}", $propertyValues))
|
||||
) {
|
||||
throw new UninitializedPropertyException(\sprintf('The property "%s::$%s" is not initialized.', $object::class, $reflectionProperty->name));
|
||||
}
|
||||
}
|
||||
|
||||
return $reflectionProperty->getValue($object);
|
||||
}
|
||||
|
||||
protected function setAttributeValue(object $object, string $attribute, mixed $value, ?string $format = null, array $context = []): void
|
||||
{
|
||||
try {
|
||||
$reflectionProperty = $this->getReflectionProperty($object, $attribute);
|
||||
} catch (\ReflectionException) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($reflectionProperty->isStatic()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$reflectionProperty->isReadOnly()) {
|
||||
$reflectionProperty->setValue($object, $value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$reflectionProperty->isInitialized($object)) {
|
||||
$declaringClass = $reflectionProperty->getDeclaringClass();
|
||||
$declaringClass->getProperty($reflectionProperty->getName())->setValue($object, $value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($reflectionProperty->getValue($object) !== $value) {
|
||||
throw new LogicException(\sprintf('Attempting to change readonly property "%s"::$%s.', $object::class, $reflectionProperty->getName()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
private function getReflectionProperty(string|object $classOrObject, string $attribute): \ReflectionProperty
|
||||
{
|
||||
$reflectionClass = new \ReflectionClass($classOrObject);
|
||||
while (true) {
|
||||
try {
|
||||
return $reflectionClass->getProperty($attribute);
|
||||
} catch (\ReflectionException $e) {
|
||||
if (!$reflectionClass = $reflectionClass->getParentClass()) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
55
backend/vendor/symfony/serializer/Normalizer/TranslatableNormalizer.php
vendored
Normal file
55
backend/vendor/symfony/serializer/Normalizer/TranslatableNormalizer.php
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
|
||||
use Symfony\Contracts\Translation\TranslatableInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
final class TranslatableNormalizer implements NormalizerInterface
|
||||
{
|
||||
public const NORMALIZATION_LOCALE_KEY = 'translatable_normalization_locale';
|
||||
|
||||
private array $defaultContext = [
|
||||
self::NORMALIZATION_LOCALE_KEY => null,
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
private readonly TranslatorInterface $translator,
|
||||
array $defaultContext = [],
|
||||
) {
|
||||
$this->defaultContext = array_merge($this->defaultContext, $defaultContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function normalize(mixed $data, ?string $format = null, array $context = []): string
|
||||
{
|
||||
if (!$data instanceof TranslatableInterface) {
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The object must implement the "%s".', TranslatableInterface::class), $data, [TranslatableInterface::class]);
|
||||
}
|
||||
|
||||
return $data->trans($this->translator, $context[self::NORMALIZATION_LOCALE_KEY] ?? $this->defaultContext[self::NORMALIZATION_LOCALE_KEY]);
|
||||
}
|
||||
|
||||
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return $data instanceof TranslatableInterface;
|
||||
}
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return [TranslatableInterface::class => true];
|
||||
}
|
||||
}
|
||||
80
backend/vendor/symfony/serializer/Normalizer/UidNormalizer.php
vendored
Normal file
80
backend/vendor/symfony/serializer/Normalizer/UidNormalizer.php
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Exception\LogicException;
|
||||
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
|
||||
use Symfony\Component\Uid\AbstractUid;
|
||||
|
||||
final class UidNormalizer implements NormalizerInterface, DenormalizerInterface
|
||||
{
|
||||
public const NORMALIZATION_FORMAT_KEY = 'uid_normalization_format';
|
||||
|
||||
public const NORMALIZATION_FORMAT_CANONICAL = 'canonical';
|
||||
public const NORMALIZATION_FORMAT_BASE58 = 'base58';
|
||||
public const NORMALIZATION_FORMAT_BASE32 = 'base32';
|
||||
public const NORMALIZATION_FORMAT_RFC4122 = 'rfc4122';
|
||||
public const NORMALIZATION_FORMAT_RFC9562 = self::NORMALIZATION_FORMAT_RFC4122; // RFC 9562 obsoleted RFC 4122 but the format is the same
|
||||
|
||||
public const NORMALIZATION_FORMATS = [
|
||||
self::NORMALIZATION_FORMAT_CANONICAL,
|
||||
self::NORMALIZATION_FORMAT_BASE58,
|
||||
self::NORMALIZATION_FORMAT_BASE32,
|
||||
self::NORMALIZATION_FORMAT_RFC4122,
|
||||
];
|
||||
|
||||
private array $defaultContext = [
|
||||
self::NORMALIZATION_FORMAT_KEY => self::NORMALIZATION_FORMAT_CANONICAL,
|
||||
];
|
||||
|
||||
public function __construct(array $defaultContext = [])
|
||||
{
|
||||
$this->defaultContext = array_merge($this->defaultContext, $defaultContext);
|
||||
}
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return [
|
||||
AbstractUid::class => true,
|
||||
];
|
||||
}
|
||||
|
||||
public function normalize(mixed $data, ?string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null
|
||||
{
|
||||
return match ($context[self::NORMALIZATION_FORMAT_KEY] ?? $this->defaultContext[self::NORMALIZATION_FORMAT_KEY]) {
|
||||
self::NORMALIZATION_FORMAT_CANONICAL => (string) $data,
|
||||
self::NORMALIZATION_FORMAT_BASE58 => $data->toBase58(),
|
||||
self::NORMALIZATION_FORMAT_BASE32 => $data->toBase32(),
|
||||
self::NORMALIZATION_FORMAT_RFC4122 => $data->toRfc4122(),
|
||||
default => throw new LogicException(\sprintf('The "%s" format is not valid.', $context[self::NORMALIZATION_FORMAT_KEY] ?? $this->defaultContext[self::NORMALIZATION_FORMAT_KEY])),
|
||||
};
|
||||
}
|
||||
|
||||
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return $data instanceof AbstractUid;
|
||||
}
|
||||
|
||||
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed
|
||||
{
|
||||
try {
|
||||
return $type::fromString($data);
|
||||
} catch (\InvalidArgumentException|\TypeError) {
|
||||
throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('The data is not a valid "%s" string representation.', $type), $data, ['string'], $context['deserialization_path'] ?? null, true);
|
||||
}
|
||||
}
|
||||
|
||||
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return is_subclass_of($type, AbstractUid::class, true);
|
||||
}
|
||||
}
|
||||
65
backend/vendor/symfony/serializer/Normalizer/UnwrappingDenormalizer.php
vendored
Normal file
65
backend/vendor/symfony/serializer/Normalizer/UnwrappingDenormalizer.php
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||
use Symfony\Component\Serializer\Exception\LogicException;
|
||||
use Symfony\Component\Serializer\SerializerAwareInterface;
|
||||
use Symfony\Component\Serializer\SerializerAwareTrait;
|
||||
|
||||
/**
|
||||
* @author Eduard Bulava <bulavaeduard@gmail.com>
|
||||
*/
|
||||
final class UnwrappingDenormalizer implements DenormalizerInterface, SerializerAwareInterface
|
||||
{
|
||||
use SerializerAwareTrait;
|
||||
|
||||
public const UNWRAP_PATH = 'unwrap_path';
|
||||
|
||||
private readonly PropertyAccessorInterface $propertyAccessor;
|
||||
|
||||
public function __construct(?PropertyAccessorInterface $propertyAccessor = null)
|
||||
{
|
||||
$this->propertyAccessor = $propertyAccessor ?? PropertyAccess::createPropertyAccessor();
|
||||
}
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return ['*' => false];
|
||||
}
|
||||
|
||||
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed
|
||||
{
|
||||
$propertyPath = $context[self::UNWRAP_PATH];
|
||||
$context['unwrapped'] = true;
|
||||
|
||||
if ($propertyPath) {
|
||||
if (!$this->propertyAccessor->isReadable($data, $propertyPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$data = $this->propertyAccessor->getValue($data, $propertyPath);
|
||||
}
|
||||
|
||||
if (!$this->serializer instanceof DenormalizerInterface) {
|
||||
throw new LogicException('Cannot unwrap path because the injected serializer is not a denormalizer.');
|
||||
}
|
||||
|
||||
return $this->serializer->denormalize($data, $type, $format, $context);
|
||||
}
|
||||
|
||||
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
|
||||
{
|
||||
return \array_key_exists(self::UNWRAP_PATH, $context) && !isset($context['unwrapped']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user