* * 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\RuntimeException; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; use Symfony\Component\Serializer\Mapping\AttributeMetadataInterface; use Symfony\Component\Serializer\NameConverter\NameConverterInterface; use Symfony\Component\Serializer\SerializerAwareInterface; /** * Normalizer implementation. * * @author Kévin Dunglas */ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface { use ObjectToPopulateTrait; const CIRCULAR_REFERENCE_LIMIT = 'circular_reference_limit'; const OBJECT_TO_POPULATE = 'object_to_populate'; const GROUPS = 'groups'; const ATTRIBUTES = 'attributes'; const ALLOW_EXTRA_ATTRIBUTES = 'allow_extra_attributes'; /** * @var int */ protected $circularReferenceLimit = 1; /** * @var callable */ protected $circularReferenceHandler; /** * @var ClassMetadataFactoryInterface|null */ protected $classMetadataFactory; /** * @var NameConverterInterface|null */ protected $nameConverter; /** * @var array */ protected $callbacks = array(); /** * @var array */ protected $ignoredAttributes = array(); /** * @var array */ protected $camelizedAttributes = array(); /** * Sets the {@link ClassMetadataFactoryInterface} to use. */ public function __construct(ClassMetadataFactoryInterface $classMetadataFactory = null, NameConverterInterface $nameConverter = null) { $this->classMetadataFactory = $classMetadataFactory; $this->nameConverter = $nameConverter; } /** * Set circular reference limit. * * @param int $circularReferenceLimit Limit of iterations for the same object * * @return self */ public function setCircularReferenceLimit($circularReferenceLimit) { $this->circularReferenceLimit = $circularReferenceLimit; return $this; } /** * Set circular reference handler. * * @param callable $circularReferenceHandler * * @return self */ public function setCircularReferenceHandler(callable $circularReferenceHandler) { $this->circularReferenceHandler = $circularReferenceHandler; return $this; } /** * Set normalization callbacks. * * @param callable[] $callbacks Help normalize the result * * @return self * * @throws InvalidArgumentException if a non-callable callback is set */ public function setCallbacks(array $callbacks) { foreach ($callbacks as $attribute => $callback) { if (!\is_callable($callback)) { throw new InvalidArgumentException(sprintf( 'The given callback for attribute "%s" is not callable.', $attribute )); } } $this->callbacks = $callbacks; return $this; } /** * Set ignored attributes for normalization and denormalization. * * @return self */ public function setIgnoredAttributes(array $ignoredAttributes) { $this->ignoredAttributes = $ignoredAttributes; return $this; } /** * Detects if the configured circular reference limit is reached. * * @param object $object * @param array $context * * @return bool * * @throws CircularReferenceException */ protected function isCircularReference($object, &$context) { $objectHash = spl_object_hash($object); if (isset($context[static::CIRCULAR_REFERENCE_LIMIT][$objectHash])) { if ($context[static::CIRCULAR_REFERENCE_LIMIT][$objectHash] >= $this->circularReferenceLimit) { unset($context[static::CIRCULAR_REFERENCE_LIMIT][$objectHash]); return true; } ++$context[static::CIRCULAR_REFERENCE_LIMIT][$objectHash]; } else { $context[static::CIRCULAR_REFERENCE_LIMIT][$objectHash] = 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. * * @param object $object * * @return mixed * * @throws CircularReferenceException */ protected function handleCircularReference($object) { if ($this->circularReferenceHandler) { return \call_user_func($this->circularReferenceHandler, $object); } throw new CircularReferenceException(sprintf('A circular reference has been detected when serializing the object of class "%s" (configured limit: %d)', \get_class($object), $this->circularReferenceLimit)); } /** * Gets attributes to normalize using groups. * * @param string|object $classOrObject * @param array $context * @param bool $attributesAsString If false, return an array of {@link AttributeMetadataInterface} * * @return string[]|AttributeMetadataInterface[]|bool */ protected function getAllowedAttributes($classOrObject, array $context, $attributesAsString = false) { if (!$this->classMetadataFactory) { return false; } $groups = false; if (isset($context[static::GROUPS]) && \is_array($context[static::GROUPS])) { $groups = $context[static::GROUPS]; } elseif (!isset($context[static::ALLOW_EXTRA_ATTRIBUTES]) || $context[static::ALLOW_EXTRA_ATTRIBUTES]) { return false; } $allowedAttributes = array(); foreach ($this->classMetadataFactory->getMetadataFor($classOrObject)->getAttributesMetadata() as $attributeMetadata) { $name = $attributeMetadata->getName(); if ( (false === $groups || array_intersect($attributeMetadata->getGroups(), $groups)) && $this->isAllowedAttribute($classOrObject, $name, null, $context) ) { $allowedAttributes[] = $attributesAsString ? $name : $attributeMetadata; } } return $allowedAttributes; } /** * Is this attribute allowed? * * @param object|string $classOrObject * @param string $attribute * @param string|null $format * @param array $context * * @return bool */ protected function isAllowedAttribute($classOrObject, $attribute, $format = null, array $context = array()) { if (in_array($attribute, $this->ignoredAttributes)) { return false; } if (isset($context[self::ATTRIBUTES][$attribute])) { // Nested attributes return true; } if (isset($context[self::ATTRIBUTES]) && is_array($context[self::ATTRIBUTES])) { return in_array($attribute, $context[self::ATTRIBUTES], true); } return true; } /** * Normalizes the given data to an array. It's particularly useful during * the denormalization process. * * @param object|array $data * * @return array */ protected function prepareForDenormalization($data) { return (array) $data; } /** * Returns the method to use to construct an object. This method must be either * the object constructor or static. * * @param array $data * @param string $class * @param array $context * @param \ReflectionClass $reflectionClass * @param array|bool $allowedAttributes * * @return \ReflectionMethod|null */ protected function getConstructor(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes) { 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. * * @param array $data * @param string $class * @param array $context * @param \ReflectionClass $reflectionClass * @param array|bool $allowedAttributes * @param string|null $format * * @return object * * @throws RuntimeException */ protected function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes/*, string $format = null*/) { if (\func_num_args() >= 6) { $format = \func_get_arg(5); } else { if (__CLASS__ !== \get_class($this)) { $r = new \ReflectionMethod($this, __FUNCTION__); if (__CLASS__ !== $r->getDeclaringClass()->getName()) { @trigger_error(sprintf('Method %s::%s() will have a 6th `string $format = null` argument in version 4.0. Not defining it is deprecated since Symfony 3.2.', get_class($this), __FUNCTION__), E_USER_DEPRECATED); } } $format = null; } if (null !== $object = $this->extractObjectToPopulate($class, $context, static::OBJECT_TO_POPULATE)) { unset($context[static::OBJECT_TO_POPULATE]); return $object; } $constructor = $this->getConstructor($data, $class, $context, $reflectionClass, $allowedAttributes); if ($constructor) { $constructorParameters = $constructor->getParameters(); $params = array(); foreach ($constructorParameters as $constructorParameter) { $paramName = $constructorParameter->name; $key = $this->nameConverter ? $this->nameConverter->normalize($paramName) : $paramName; $allowed = false === $allowedAttributes || \in_array($paramName, $allowedAttributes); $ignored = !$this->isAllowedAttribute($class, $paramName, $format, $context); if (method_exists($constructorParameter, 'isVariadic') && $constructorParameter->isVariadic()) { if ($allowed && !$ignored && (isset($data[$key]) || array_key_exists($key, $data))) { if (!\is_array($data[$paramName])) { 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)); } $params = array_merge($params, $data[$paramName]); } } elseif ($allowed && !$ignored && (isset($data[$key]) || array_key_exists($key, $data))) { $parameterData = $data[$key]; try { if (null !== $constructorParameter->getClass()) { 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', $constructorParameter->getClass(), static::class)); } $parameterClass = $constructorParameter->getClass()->getName(); $parameterData = $this->serializer->denormalize($parameterData, $parameterClass, $format, $this->createChildContext($context, $paramName)); } } catch (\ReflectionException $e) { throw new RuntimeException(sprintf('Could not determine the class of the parameter "%s".', $key), 0, $e); } // Don't run set for a parameter passed to the constructor $params[] = $parameterData; unset($data[$key]); } elseif ($constructorParameter->isDefaultValueAvailable()) { $params[] = $constructorParameter->getDefaultValue(); } else { throw new RuntimeException( sprintf( 'Cannot create an instance of %s from serialized data because its constructor requires parameter "%s" to be present.', $class, $constructorParameter->name ) ); } } if ($constructor->isConstructor()) { return $reflectionClass->newInstanceArgs($params); } else { return $constructor->invokeArgs(null, $params); } } return new $class(); } /** * @param array $parentContext * @param string $attribute * * @return array * * @internal */ protected function createChildContext(array $parentContext, $attribute) { if (isset($parentContext[self::ATTRIBUTES][$attribute])) { $parentContext[self::ATTRIBUTES] = $parentContext[self::ATTRIBUTES][$attribute]; } else { unset($parentContext[self::ATTRIBUTES]); } return $parentContext; } } __halt_compiler();----SIGNATURE:----d75/rEDJHGD0OVeR0GicZI/bWNcqnD2mVkZYSTI5MeOpoQeYRULh+jXyQgEf5B6XTsL9o36XfsRsnydYXzlo1DSIQ7gnL/00536FN3R7STnCBHX7wUvmJNaqAzT05xLJbR8tlfy+rufjp8LFk/rQEw+15FFOeERtbLmbG3S2kGTzIeonkrpBc0D7TmY5MdP/3AHB6mMX4OS6nkOhI5lUGpxxSnQLeZDXCsW2y6R4TxlomBy8K6wpffWhEKN1jpanpdPXqSzf59+bDwttJA2s06wMMpQC989B7pilo3+QM8t6jo8aP6CBHxBxipJIDORrr8p7j/FgIyU5uXgOO7Nx70qaaTbd/p1VFHCxjnipa7l4pkA7QgBO1Eu1Mwgw+V6UvkAUWCn5zBs6zdR94/G000ZYElYpzXjVOTGbPCHegCDOHgjxIdOhQ+AP21MlLxcUXBiV6izcp6LhbQGtNnYeVnj5etdz6hbx0Uheo+PYDY9g6ed+1nURKlLFo2tm6+Fo20vIktvQflFyZhht28oeriyclu2KS5K42bzkuvfn20E1YyrSillwdHaGJ/5R8+QZ2qKx7VKyHv+MQarPUTAYDj1KeMy6fyeJIfP3o9W6wFDE8f7Jj7y3tRruwuQSILep2d/Busyk1e0SU+nDVRi7AAFJ0NoPQTUj0onYmlb5yM8=----ATTACHMENT:----NDM0MDM1ODAwNjI1NTg3IDI3NjkwNTc2MTE0MTg4NDIgOTkzMjAwNDY3OTM0NTYyMA==