[Serializer] Move the normalization logic in an abstract class
This commit is contained in:
parent
5c16f40492
commit
3bec8138b5
@ -199,14 +199,34 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N
|
|||||||
|
|
||||||
$allowedAttributes = array();
|
$allowedAttributes = array();
|
||||||
foreach ($this->classMetadataFactory->getMetadataFor($classOrObject)->getAttributesMetadata() as $attributeMetadata) {
|
foreach ($this->classMetadataFactory->getMetadataFor($classOrObject)->getAttributesMetadata() as $attributeMetadata) {
|
||||||
if (count(array_intersect($attributeMetadata->getGroups(), $context['groups']))) {
|
$name = $attributeMetadata->getName();
|
||||||
$allowedAttributes[] = $attributesAsString ? $attributeMetadata->getName() : $attributeMetadata;
|
|
||||||
|
if (
|
||||||
|
count(array_intersect($attributeMetadata->getGroups(), $context['groups'])) &&
|
||||||
|
$this->isAllowedAttribute($classOrObject, $name, null, $context)
|
||||||
|
) {
|
||||||
|
$allowedAttributes[] = $attributesAsString ? $name : $attributeMetadata;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $allowedAttributes;
|
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())
|
||||||
|
{
|
||||||
|
return !in_array($attribute, $this->ignoredAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalizes the given data to an array. It's particularly useful during
|
* Normalizes the given data to an array. It's particularly useful during
|
||||||
* the denormalization process.
|
* the denormalization process.
|
||||||
|
@ -0,0 +1,167 @@
|
|||||||
|
<?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\LogicException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for a normalizer dealing with objects.
|
||||||
|
*
|
||||||
|
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||||
|
*/
|
||||||
|
abstract class AbstractObjectNormalizer extends AbstractNormalizer
|
||||||
|
{
|
||||||
|
private $attributesCache = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function supportsNormalization($data, $format = null)
|
||||||
|
{
|
||||||
|
return is_object($data) && !$data instanceof \Traversable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @throws CircularReferenceException
|
||||||
|
*/
|
||||||
|
public function normalize($object, $format = null, array $context = array())
|
||||||
|
{
|
||||||
|
if ($this->isCircularReference($object, $context)) {
|
||||||
|
return $this->handleCircularReference($object);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = array();
|
||||||
|
$attributes = $this->getAttributes($object, $format, $context);
|
||||||
|
|
||||||
|
foreach ($attributes as $attribute) {
|
||||||
|
$attributeValue = $this->getAttributeValue($object, $attribute, $format, $context);
|
||||||
|
|
||||||
|
if (isset($this->callbacks[$attribute])) {
|
||||||
|
$attributeValue = call_user_func($this->callbacks[$attribute], $attributeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $attributeValue && !is_scalar($attributeValue)) {
|
||||||
|
if (!$this->serializer instanceof NormalizerInterface) {
|
||||||
|
throw new LogicException(sprintf('Cannot normalize attribute "%s" because injected serializer is not a normalizer', $attribute));
|
||||||
|
}
|
||||||
|
|
||||||
|
$attributeValue = $this->serializer->normalize($attributeValue, $format, $context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->nameConverter) {
|
||||||
|
$attribute = $this->nameConverter->normalize($attribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data[$attribute] = $attributeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets and caches attributes for the given object, format and context.
|
||||||
|
*
|
||||||
|
* @param object $object
|
||||||
|
* @param string|null $format
|
||||||
|
* @param array $context
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
protected function getAttributes($object, $format = null, array $context)
|
||||||
|
{
|
||||||
|
$key = sprintf('%s-%s', get_class($object), serialize($context));
|
||||||
|
|
||||||
|
if (isset($this->attributesCache[$key])) {
|
||||||
|
return $this->attributesCache[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
$allowedAttributes = $this->getAllowedAttributes($object, $context, true);
|
||||||
|
|
||||||
|
if (false !== $allowedAttributes) {
|
||||||
|
return $this->attributesCache[$key] = $allowedAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->attributesCache[$key] = $this->extractAttributes($object, $format, $context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts attributes to normalize from the class of the given object, format and context.
|
||||||
|
*
|
||||||
|
* @param object $object
|
||||||
|
* @param string|null $format
|
||||||
|
* @param array $context
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
abstract protected function extractAttributes($object, $format = null, array $context = array());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the attribute value.
|
||||||
|
*
|
||||||
|
* @param object $object
|
||||||
|
* @param string $attribute
|
||||||
|
* @param string|null $format
|
||||||
|
* @param array $context
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
abstract protected function getAttributeValue($object, $attribute, $format = null, array $context = array());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function supportsDenormalization($data, $type, $format = null)
|
||||||
|
{
|
||||||
|
return class_exists($type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function denormalize($data, $class, $format = null, array $context = array())
|
||||||
|
{
|
||||||
|
$allowedAttributes = $this->getAllowedAttributes($class, $context, true);
|
||||||
|
$normalizedData = $this->prepareForDenormalization($data);
|
||||||
|
|
||||||
|
$reflectionClass = new \ReflectionClass($class);
|
||||||
|
$object = $this->instantiateObject($normalizedData, $class, $context, $reflectionClass, $allowedAttributes);
|
||||||
|
|
||||||
|
foreach ($normalizedData as $attribute => $value) {
|
||||||
|
if ($this->nameConverter) {
|
||||||
|
$attribute = $this->nameConverter->denormalize($attribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
$allowed = $allowedAttributes === false || in_array($attribute, $allowedAttributes);
|
||||||
|
$ignored = in_array($attribute, $this->ignoredAttributes);
|
||||||
|
|
||||||
|
if ($allowed && !$ignored) {
|
||||||
|
$this->setAttributeValue($object, $attribute, $value, $format, $context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets attribute value.
|
||||||
|
*
|
||||||
|
* @param object $object
|
||||||
|
* @param string $attribute
|
||||||
|
* @param mixed $value
|
||||||
|
* @param string|null $format
|
||||||
|
* @param array $context
|
||||||
|
*/
|
||||||
|
abstract protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = array());
|
||||||
|
}
|
@ -11,8 +11,6 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Serializer\Normalizer;
|
namespace Symfony\Component\Serializer\Normalizer;
|
||||||
|
|
||||||
use Symfony\Component\Serializer\Exception\CircularReferenceException;
|
|
||||||
use Symfony\Component\Serializer\Exception\LogicException;
|
|
||||||
use Symfony\Component\Serializer\Exception\RuntimeException;
|
use Symfony\Component\Serializer\Exception\RuntimeException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,59 +34,8 @@ use Symfony\Component\Serializer\Exception\RuntimeException;
|
|||||||
* @author Nils Adermann <naderman@naderman.de>
|
* @author Nils Adermann <naderman@naderman.de>
|
||||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||||
*/
|
*/
|
||||||
class GetSetMethodNormalizer extends AbstractNormalizer
|
class GetSetMethodNormalizer extends AbstractObjectNormalizer
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*
|
|
||||||
* @throws LogicException
|
|
||||||
* @throws CircularReferenceException
|
|
||||||
*/
|
|
||||||
public function normalize($object, $format = null, array $context = array())
|
|
||||||
{
|
|
||||||
if ($this->isCircularReference($object, $context)) {
|
|
||||||
return $this->handleCircularReference($object);
|
|
||||||
}
|
|
||||||
|
|
||||||
$reflectionObject = new \ReflectionObject($object);
|
|
||||||
$reflectionMethods = $reflectionObject->getMethods(\ReflectionMethod::IS_PUBLIC);
|
|
||||||
$allowedAttributes = $this->getAllowedAttributes($object, $context, true);
|
|
||||||
|
|
||||||
$attributes = array();
|
|
||||||
foreach ($reflectionMethods as $method) {
|
|
||||||
if ($this->isGetMethod($method)) {
|
|
||||||
$attributeName = lcfirst(substr($method->name, 0 === strpos($method->name, 'is') ? 2 : 3));
|
|
||||||
if (in_array($attributeName, $this->ignoredAttributes)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false !== $allowedAttributes && !in_array($attributeName, $allowedAttributes)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$attributeValue = $method->invoke($object);
|
|
||||||
if (isset($this->callbacks[$attributeName])) {
|
|
||||||
$attributeValue = call_user_func($this->callbacks[$attributeName], $attributeValue);
|
|
||||||
}
|
|
||||||
if (null !== $attributeValue && !is_scalar($attributeValue)) {
|
|
||||||
if (!$this->serializer instanceof NormalizerInterface) {
|
|
||||||
throw new LogicException(sprintf('Cannot normalize attribute "%s" because injected serializer is not a normalizer', $attributeName));
|
|
||||||
}
|
|
||||||
|
|
||||||
$attributeValue = $this->serializer->normalize($attributeValue, $format, $context);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->nameConverter) {
|
|
||||||
$attributeName = $this->nameConverter->normalize($attributeName);
|
|
||||||
}
|
|
||||||
|
|
||||||
$attributes[$attributeName] = $attributeValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*
|
*
|
||||||
@ -128,7 +75,7 @@ class GetSetMethodNormalizer extends AbstractNormalizer
|
|||||||
*/
|
*/
|
||||||
public function supportsNormalization($data, $format = null)
|
public function supportsNormalization($data, $format = null)
|
||||||
{
|
{
|
||||||
return is_object($data) && !$data instanceof \Traversable && $this->supports(get_class($data));
|
return parent::supportsNormalization($data, $format) && $this->supports(get_class($data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -136,7 +83,7 @@ class GetSetMethodNormalizer extends AbstractNormalizer
|
|||||||
*/
|
*/
|
||||||
public function supportsDenormalization($data, $type, $format = null)
|
public function supportsDenormalization($data, $type, $format = null)
|
||||||
{
|
{
|
||||||
return class_exists($type) && $this->supports($type);
|
return parent::supportsDenormalization($data, $type, $format) && $this->supports($type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -179,4 +126,58 @@ class GetSetMethodNormalizer extends AbstractNormalizer
|
|||||||
)
|
)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function extractAttributes($object, $format = null, array $context = array())
|
||||||
|
{
|
||||||
|
$reflectionObject = new \ReflectionObject($object);
|
||||||
|
$reflectionMethods = $reflectionObject->getMethods(\ReflectionMethod::IS_PUBLIC);
|
||||||
|
|
||||||
|
$attributes = array();
|
||||||
|
foreach ($reflectionMethods as $method) {
|
||||||
|
if (!$this->isGetMethod($method)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$attributeName = lcfirst(substr($method->name, 0 === strpos($method->name, 'is') ? 2 : 3));
|
||||||
|
|
||||||
|
if ($this->isAllowedAttribute($object, $attributeName)) {
|
||||||
|
$attributes[] = $attributeName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getAttributeValue($object, $attribute, $format = null, array $context = array())
|
||||||
|
{
|
||||||
|
$ucfirsted = ucfirst($attribute);
|
||||||
|
|
||||||
|
$getter = 'get'.$ucfirsted;
|
||||||
|
if (is_callable(array($object, $getter))) {
|
||||||
|
return $object->$getter();
|
||||||
|
}
|
||||||
|
|
||||||
|
$isser = 'is'.$ucfirsted;
|
||||||
|
if (is_callable(array($object, $isser))) {
|
||||||
|
return $object->$isser();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = array())
|
||||||
|
{
|
||||||
|
$setter = 'set'.ucfirst($attribute);
|
||||||
|
|
||||||
|
if (is_callable(array($object, $setter))) {
|
||||||
|
$object->$setter($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,6 @@ namespace Symfony\Component\Serializer\Normalizer;
|
|||||||
use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
|
use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
|
||||||
use Symfony\Component\PropertyAccess\PropertyAccess;
|
use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||||
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||||
use Symfony\Component\Serializer\Exception\CircularReferenceException;
|
|
||||||
use Symfony\Component\Serializer\Exception\LogicException;
|
|
||||||
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
|
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
|
||||||
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
|
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
|
||||||
|
|
||||||
@ -24,10 +22,8 @@ use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
|
|||||||
*
|
*
|
||||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||||
*/
|
*/
|
||||||
class ObjectNormalizer extends AbstractNormalizer
|
class ObjectNormalizer extends AbstractObjectNormalizer
|
||||||
{
|
{
|
||||||
private static $attributesCache = array();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var PropertyAccessorInterface
|
* @var PropertyAccessorInterface
|
||||||
*/
|
*/
|
||||||
@ -43,115 +39,8 @@ class ObjectNormalizer extends AbstractNormalizer
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function supportsNormalization($data, $format = null)
|
protected function extractAttributes($object, $format = null, array $context = array())
|
||||||
{
|
{
|
||||||
return is_object($data) && !$data instanceof \Traversable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*
|
|
||||||
* @throws CircularReferenceException
|
|
||||||
*/
|
|
||||||
public function normalize($object, $format = null, array $context = array())
|
|
||||||
{
|
|
||||||
if ($this->isCircularReference($object, $context)) {
|
|
||||||
return $this->handleCircularReference($object);
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = array();
|
|
||||||
$attributes = $this->getAttributes($object, $context);
|
|
||||||
|
|
||||||
foreach ($attributes as $attribute) {
|
|
||||||
if (in_array($attribute, $this->ignoredAttributes)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$attributeValue = $this->propertyAccessor->getValue($object, $attribute);
|
|
||||||
|
|
||||||
if (isset($this->callbacks[$attribute])) {
|
|
||||||
$attributeValue = call_user_func($this->callbacks[$attribute], $attributeValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null !== $attributeValue && !is_scalar($attributeValue)) {
|
|
||||||
if (!$this->serializer instanceof NormalizerInterface) {
|
|
||||||
throw new LogicException(sprintf('Cannot normalize attribute "%s" because injected serializer is not a normalizer', $attribute));
|
|
||||||
}
|
|
||||||
|
|
||||||
$attributeValue = $this->serializer->normalize($attributeValue, $format, $context);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->nameConverter) {
|
|
||||||
$attribute = $this->nameConverter->normalize($attribute);
|
|
||||||
}
|
|
||||||
|
|
||||||
$data[$attribute] = $attributeValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function supportsDenormalization($data, $type, $format = null)
|
|
||||||
{
|
|
||||||
return class_exists($type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function denormalize($data, $class, $format = null, array $context = array())
|
|
||||||
{
|
|
||||||
$allowedAttributes = $this->getAllowedAttributes($class, $context, true);
|
|
||||||
$normalizedData = $this->prepareForDenormalization($data);
|
|
||||||
|
|
||||||
$reflectionClass = new \ReflectionClass($class);
|
|
||||||
$object = $this->instantiateObject($normalizedData, $class, $context, $reflectionClass, $allowedAttributes);
|
|
||||||
|
|
||||||
foreach ($normalizedData as $attribute => $value) {
|
|
||||||
if ($this->nameConverter) {
|
|
||||||
$attribute = $this->nameConverter->denormalize($attribute);
|
|
||||||
}
|
|
||||||
|
|
||||||
$allowed = $allowedAttributes === false || in_array($attribute, $allowedAttributes);
|
|
||||||
$ignored = in_array($attribute, $this->ignoredAttributes);
|
|
||||||
|
|
||||||
if ($allowed && !$ignored) {
|
|
||||||
try {
|
|
||||||
$this->propertyAccessor->setValue($object, $attribute, $value);
|
|
||||||
} catch (NoSuchPropertyException $exception) {
|
|
||||||
// Properties not found are ignored
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets and caches attributes for this class and context.
|
|
||||||
*
|
|
||||||
* @param object $object
|
|
||||||
* @param array $context
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function getAttributes($object, array $context)
|
|
||||||
{
|
|
||||||
$key = sprintf('%s-%s', get_class($object), serialize($context));
|
|
||||||
|
|
||||||
if (isset(self::$attributesCache[$key])) {
|
|
||||||
return self::$attributesCache[$key];
|
|
||||||
}
|
|
||||||
|
|
||||||
$allowedAttributes = $this->getAllowedAttributes($object, $context, true);
|
|
||||||
|
|
||||||
if (false !== $allowedAttributes) {
|
|
||||||
return self::$attributesCache[$key] = $allowedAttributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not using groups, detect manually
|
// If not using groups, detect manually
|
||||||
$attributes = array();
|
$attributes = array();
|
||||||
|
|
||||||
@ -171,22 +60,46 @@ class ObjectNormalizer extends AbstractNormalizer
|
|||||||
|
|
||||||
if (strpos($name, 'get') === 0 || strpos($name, 'has') === 0) {
|
if (strpos($name, 'get') === 0 || strpos($name, 'has') === 0) {
|
||||||
// getters and hassers
|
// getters and hassers
|
||||||
$attributes[lcfirst(substr($name, 3))] = true;
|
$attributeName = lcfirst(substr($name, 3));
|
||||||
} elseif (strpos($name, 'is') === 0) {
|
} elseif (strpos($name, 'is') === 0) {
|
||||||
// issers
|
// issers
|
||||||
$attributes[lcfirst(substr($name, 2))] = true;
|
$attributeName = lcfirst(substr($name, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isAllowedAttribute($object, $attributeName)) {
|
||||||
|
$attributes[$attributeName] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// properties
|
// properties
|
||||||
foreach ($reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $reflProperty) {
|
foreach ($reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $reflProperty) {
|
||||||
if ($reflProperty->isStatic()) {
|
if ($reflProperty->isStatic() || !$this->isAllowedAttribute($object, $reflProperty->name)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$attributes[$reflProperty->getName()] = true;
|
$attributes[$reflProperty->getName()] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$attributesCache[$key] = array_keys($attributes);
|
return array_keys($attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getAttributeValue($object, $attribute, $format = null, array $context = array())
|
||||||
|
{
|
||||||
|
return $this->propertyAccessor->getValue($object, $attribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = array())
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->propertyAccessor->setValue($object, $attribute, $value);
|
||||||
|
} catch (NoSuchPropertyException $exception) {
|
||||||
|
// Properties not found are ignored
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,6 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Serializer\Normalizer;
|
namespace Symfony\Component\Serializer\Normalizer;
|
||||||
|
|
||||||
use Symfony\Component\Serializer\Exception\CircularReferenceException;
|
|
||||||
use Symfony\Component\Serializer\Exception\LogicException;
|
|
||||||
use Symfony\Component\Serializer\Exception\RuntimeException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts between objects and arrays by mapping properties.
|
* Converts between objects and arrays by mapping properties.
|
||||||
*
|
*
|
||||||
@ -32,106 +28,14 @@ use Symfony\Component\Serializer\Exception\RuntimeException;
|
|||||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||||
*/
|
*/
|
||||||
class PropertyNormalizer extends AbstractNormalizer
|
class PropertyNormalizer extends AbstractObjectNormalizer
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*
|
|
||||||
* @throws CircularReferenceException
|
|
||||||
*/
|
|
||||||
public function normalize($object, $format = null, array $context = array())
|
|
||||||
{
|
|
||||||
if ($this->isCircularReference($object, $context)) {
|
|
||||||
return $this->handleCircularReference($object);
|
|
||||||
}
|
|
||||||
|
|
||||||
$reflectionObject = new \ReflectionObject($object);
|
|
||||||
$attributes = array();
|
|
||||||
$allowedAttributes = $this->getAllowedAttributes($object, $context, true);
|
|
||||||
|
|
||||||
foreach ($reflectionObject->getProperties() as $property) {
|
|
||||||
if (in_array($property->name, $this->ignoredAttributes) || $property->isStatic()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false !== $allowedAttributes && !in_array($property->name, $allowedAttributes)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override visibility
|
|
||||||
if (!$property->isPublic()) {
|
|
||||||
$property->setAccessible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$attributeValue = $property->getValue($object);
|
|
||||||
|
|
||||||
if (isset($this->callbacks[$property->name])) {
|
|
||||||
$attributeValue = call_user_func($this->callbacks[$property->name], $attributeValue);
|
|
||||||
}
|
|
||||||
if (null !== $attributeValue && !is_scalar($attributeValue)) {
|
|
||||||
if (!$this->serializer instanceof NormalizerInterface) {
|
|
||||||
throw new LogicException(sprintf('Cannot normalize attribute "%s" because injected serializer is not a normalizer', $property->name));
|
|
||||||
}
|
|
||||||
|
|
||||||
$attributeValue = $this->serializer->normalize($attributeValue, $format, $context);
|
|
||||||
}
|
|
||||||
|
|
||||||
$propertyName = $property->name;
|
|
||||||
if ($this->nameConverter) {
|
|
||||||
$propertyName = $this->nameConverter->normalize($propertyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
$attributes[$propertyName] = $attributeValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function denormalize($data, $class, $format = null, array $context = array())
|
|
||||||
{
|
|
||||||
$allowedAttributes = $this->getAllowedAttributes($class, $context, true);
|
|
||||||
$data = $this->prepareForDenormalization($data);
|
|
||||||
|
|
||||||
$reflectionClass = new \ReflectionClass($class);
|
|
||||||
$object = $this->instantiateObject($data, $class, $context, $reflectionClass, $allowedAttributes);
|
|
||||||
|
|
||||||
foreach ($data as $propertyName => $value) {
|
|
||||||
if ($this->nameConverter) {
|
|
||||||
$propertyName = $this->nameConverter->denormalize($propertyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
$allowed = $allowedAttributes === false || in_array($propertyName, $allowedAttributes);
|
|
||||||
$ignored = in_array($propertyName, $this->ignoredAttributes);
|
|
||||||
if ($allowed && !$ignored && $reflectionClass->hasProperty($propertyName)) {
|
|
||||||
$property = $reflectionClass->getProperty($propertyName);
|
|
||||||
|
|
||||||
if ($property->isStatic()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override visibility
|
|
||||||
if (!$property->isPublic()) {
|
|
||||||
$property->setAccessible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$property->setValue($object, $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function supportsNormalization($data, $format = null)
|
public function supportsNormalization($data, $format = null)
|
||||||
{
|
{
|
||||||
return is_object($data) && !$data instanceof \Traversable && $this->supports(get_class($data));
|
return parent::supportsNormalization($data, $format) && $this->supports(get_class($data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -139,7 +43,7 @@ class PropertyNormalizer extends AbstractNormalizer
|
|||||||
*/
|
*/
|
||||||
public function supportsDenormalization($data, $type, $format = null)
|
public function supportsDenormalization($data, $type, $format = null)
|
||||||
{
|
{
|
||||||
return class_exists($type) && $this->supports($type);
|
return parent::supportsDenormalization($data, $type, $format) && $this->supports($type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -162,4 +66,86 @@ class PropertyNormalizer extends AbstractNormalizer
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function isAllowedAttribute($classOrObject, $attribute, $format = null, array $context = array())
|
||||||
|
{
|
||||||
|
if (!parent::isAllowedAttribute($classOrObject, $attribute, $format, $context)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$reflectionProperty = new \ReflectionProperty(is_string($classOrObject) ? $classOrObject : get_class($classOrObject), $attribute);
|
||||||
|
if ($reflectionProperty->isStatic()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (\ReflectionException $reflectionException) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function extractAttributes($object, $format = null, array $context = array())
|
||||||
|
{
|
||||||
|
$reflectionObject = new \ReflectionObject($object);
|
||||||
|
$attributes = array();
|
||||||
|
|
||||||
|
foreach ($reflectionObject->getProperties() as $property) {
|
||||||
|
if (!$this->isAllowedAttribute($object, $property->name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$attributes[] = $property->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getAttributeValue($object, $attribute, $format = null, array $context = array())
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$reflectionProperty = new \ReflectionProperty(get_class($object), $attribute);
|
||||||
|
} catch (\ReflectionException $reflectionException) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override visibility
|
||||||
|
if (!$reflectionProperty->isPublic()) {
|
||||||
|
$reflectionProperty->setAccessible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $reflectionProperty->getValue($object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = array())
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$reflectionProperty = new \ReflectionProperty(get_class($object), $attribute);
|
||||||
|
} catch (\ReflectionException $reflectionException) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($reflectionProperty->isStatic()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override visibility
|
||||||
|
if (!$reflectionProperty->isPublic()) {
|
||||||
|
$reflectionProperty->setAccessible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$reflectionProperty->setValue($object, $value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user