X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=blobdiff_plain;f=vendor%2Fsymfony%2Fserializer%2FNormalizer%2FAbstractNormalizer.php;fp=vendor%2Fsymfony%2Fserializer%2FNormalizer%2FAbstractNormalizer.php;h=63bfb871e819d265bada25e29dcdc7ba472b93cb;hp=0000000000000000000000000000000000000000;hb=a2bd1bf0c2c1f1a17d188f4dc0726a45494cefae;hpb=57c063afa3f66b07c4bbddc2d6129a96d90f0aad diff --git a/vendor/symfony/serializer/Normalizer/AbstractNormalizer.php b/vendor/symfony/serializer/Normalizer/AbstractNormalizer.php new file mode 100644 index 000000000..63bfb871e --- /dev/null +++ b/vendor/symfony/serializer/Normalizer/AbstractNormalizer.php @@ -0,0 +1,360 @@ + + * + * 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\CamelCaseToSnakeCaseNameConverter; +use Symfony\Component\Serializer\NameConverter\NameConverterInterface; + +/** + * Normalizer implementation. + * + * @author Kévin Dunglas + */ +abstract class AbstractNormalizer extends SerializerAwareNormalizer implements NormalizerInterface, DenormalizerInterface +{ + const CIRCULAR_REFERENCE_LIMIT = 'circular_reference_limit'; + const OBJECT_TO_POPULATE = 'object_to_populate'; + const GROUPS = 'groups'; + + /** + * @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. + * + * @param ClassMetadataFactoryInterface|null $classMetadataFactory + * @param NameConverterInterface|null $nameConverter + */ + 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 + * + * @throws InvalidArgumentException + */ + public function setCircularReferenceHandler($circularReferenceHandler) + { + if (!is_callable($circularReferenceHandler)) { + throw new InvalidArgumentException('The given circular reference handler is not callable.'); + } + + $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. + * + * @param array $ignoredAttributes + * + * @return self + */ + public function setIgnoredAttributes(array $ignoredAttributes) + { + $this->ignoredAttributes = $ignoredAttributes; + + return $this; + } + + /** + * Set attributes to be camelized on denormalize. + * + * @deprecated Deprecated since version 2.7, to be removed in 3.0. Use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter instead. + * + * @param array $camelizedAttributes + * + * @return self + * + * @throws LogicException + */ + public function setCamelizedAttributes(array $camelizedAttributes) + { + @trigger_error(sprintf('%s is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter instead.', __METHOD__), E_USER_DEPRECATED); + + if ($this->nameConverter && !$this->nameConverter instanceof CamelCaseToSnakeCaseNameConverter) { + throw new LogicException(sprintf('%s cannot be called if a custom Name Converter is defined.', __METHOD__)); + } + + $attributes = array(); + foreach ($camelizedAttributes as $camelizedAttribute) { + $attributes[] = lcfirst(preg_replace_callback('/(^|_|\.)+(.)/', function ($match) { + return ('.' === $match[1] ? '_' : '').strtoupper($match[2]); + }, $camelizedAttribute)); + } + + $this->nameConverter = new CamelCaseToSnakeCaseNameConverter($attributes); + + 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 (configured limit: %d).', $this->circularReferenceLimit)); + } + + /** + * Format an attribute name, for example to convert a snake_case name to camelCase. + * + * @deprecated Deprecated since version 2.7, to be removed in 3.0. Use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter instead. + * + * @param string $attributeName + * + * @return string + */ + protected function formatAttribute($attributeName) + { + @trigger_error(sprintf('%s is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter instead.', __METHOD__), E_USER_DEPRECATED); + + return $this->nameConverter ? $this->nameConverter->normalize($attributeName) : $attributeName; + } + + /** + * 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 || !isset($context[static::GROUPS]) || !is_array($context[static::GROUPS])) { + return false; + } + + $allowedAttributes = array(); + foreach ($this->classMetadataFactory->getMetadataFor($classOrObject)->getAttributesMetadata() as $attributeMetadata) { + if (count(array_intersect($attributeMetadata->getGroups(), $context[static::GROUPS]))) { + $allowedAttributes[] = $attributesAsString ? $attributeMetadata->getName() : $attributeMetadata; + } + } + + return $allowedAttributes; + } + + /** + * 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; + } + + /** + * 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 + * + * @return object + * + * @throws RuntimeException + */ + protected function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes) + { + if ( + isset($context[static::OBJECT_TO_POPULATE]) && + is_object($context[static::OBJECT_TO_POPULATE]) && + $context[static::OBJECT_TO_POPULATE] instanceof $class + ) { + $object = $context[static::OBJECT_TO_POPULATE]; + unset($context[static::OBJECT_TO_POPULATE]); + + return $object; + } + + $constructor = $reflectionClass->getConstructor(); + if ($constructor) { + $constructorParameters = $constructor->getParameters(); + + $params = array(); + foreach ($constructorParameters as $constructorParameter) { + $paramName = $constructorParameter->name; + $key = $this->nameConverter ? $this->nameConverter->normalize($paramName) : $paramName; + + $allowed = $allowedAttributes === false || in_array($paramName, $allowedAttributes); + $ignored = in_array($paramName, $this->ignoredAttributes); + 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))) { + $params[] = $data[$key]; + // don't run set for a parameter passed to the constructor + 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 + ) + ); + } + } + + return $reflectionClass->newInstanceArgs($params); + } + + return new $class(); + } +}