[Serializer] Split supports in supportsNormalization and supportsDenormalization

This commit is contained in:
Jordi Boggiano 2011-05-06 19:36:56 +02:00
parent 919f16a7d6
commit ded30a2937
6 changed files with 81 additions and 36 deletions

View File

@ -124,6 +124,9 @@ beta1 to beta2
'allow_delete' => true, 'allow_delete' => true,
)); ));
* Serializer: The NormalizerInterface's `supports()` method has been split in
two methods: `supportsNormalization` and `supportsDenormalization`.
PR12 to beta1 PR12 to beta1
------------- -------------
@ -210,11 +213,11 @@ PR11 to PR12
<app:engine>twig</app:engine> <app:engine>twig</app:engine>
<twig:extension>twig.extension.debug</twig:extension> <twig:extension>twig.extension.debug</twig:extension>
* Fixes a critical security issue which allowed all users to switch to * Fixes a critical security issue which allowed all users to switch to
arbitrary accounts when the SwitchUserListener was activated. Configurations arbitrary accounts when the SwitchUserListener was activated. Configurations
which do not use the SwitchUserListener are not affected. which do not use the SwitchUserListener are not affected.
* The Dependency Injection Container now strongly validates the references of * The Dependency Injection Container now strongly validates the references of
all your services at the end of its compilation process. If you have invalid all your services at the end of its compilation process. If you have invalid
references this will result in a compile-time exception instead of a run-time references this will result in a compile-time exception instead of a run-time
exception (the previous behavior). exception (the previous behavior).

View File

@ -39,13 +39,27 @@ class CustomNormalizer extends AbstractNormalizer
/** /**
* Checks if the given class implements the NormalizableInterface. * Checks if the given class implements the NormalizableInterface.
* *
* @param ReflectionClass $class A ReflectionClass instance of the class * @param mixed $data Data to normalize.
* to serialize into or from. * @param string $format The format being (de-)serialized from or into.
* @param string $format The format being (de-)serialized from or into.
* @return Boolean * @return Boolean
*/ */
public function supports(\ReflectionClass $class, $format = null) public function supportsNormalization($data, $format = null)
{ {
return $class->implementsInterface('Symfony\Component\Serializer\Normalizer\NormalizableInterface'); return $data instanceof NormalizableInterface;
}
/**
* Checks if the given class implements the NormalizableInterface.
*
* @param mixed $data Data to denormalize from.
* @param string $type The class to which the data should be denormalized.
* @param string $format The format being deserialized from.
* @return Boolean
*/
public function supportsDenormalization($data, $type, $format = null)
{
$class = new \ReflectionClass($type);
return $class->isSubclassOf('Symfony\Component\Serializer\Normalizer\NormalizableInterface');
} }
} }

View File

@ -107,23 +107,37 @@ class GetSetMethodNormalizer extends AbstractNormalizer
return $object; return $object;
} }
/**
* {@inheritDoc}
*/
public function supportsNormalization($data, $format = null)
{
return $this->supports(get_class($data));
}
/**
* {@inheritDoc}
*/
public function supportsDenormalization($data, $type, $format = null)
{
return $this->supports($type);
}
/** /**
* Checks if the given class has any get{Property} method. * Checks if the given class has any get{Property} method.
* *
* @param ReflectionClass $class A ReflectionClass instance of the class * @param string $class
* to serialize into or from. * @return Boolean
* @param string $format The format being (de-)serialized from or into.
* @return Boolean Whether the class has any getters.
*/ */
public function supports(\ReflectionClass $class, $format = null) private function supports($class)
{ {
$class = new \ReflectionClass($type);
$methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC); $methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC);
foreach ($methods as $method) { foreach ($methods as $method) {
if ($this->isGetMethod($method)) { if ($this->isGetMethod($method)) {
return true; return true;
} }
} }
return false; return false;
} }

View File

@ -43,16 +43,25 @@ interface NormalizerInterface
function denormalize($data, $class, $format = null); function denormalize($data, $class, $format = null);
/** /**
* Checks whether the given class is supported by this normalizer * Checks whether the given class is supported for normalization by this normalizer
*
* @param ReflectionClass $class
* @param string $format format the given data was extracted from
* *
* @param mixed $data Data to normalize.
* @param string $format The format being (de-)serialized from or into.
* @return Boolean * @return Boolean
*
* @api * @api
*/ */
function supports(\ReflectionClass $class, $format = null); function supportsNormalization($data, $format = null);
/**
* 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 $format The format being deserialized from.
* @return Boolean
* @api
*/
function supportsDenormalization($data, $type, $format = null);
/** /**
* Sets the owning Serializer object * Sets the owning Serializer object

View File

@ -31,6 +31,7 @@ class Serializer implements SerializerInterface
private $normalizers = array(); private $normalizers = array();
private $encoders = array(); private $encoders = array();
protected $normalizerCache = array(); protected $normalizerCache = array();
protected $denormalizerCache = array();
/** /**
* @param mixed $value value to test * @param mixed $value value to test
@ -68,9 +69,8 @@ class Serializer implements SerializerInterface
if (isset($this->normalizerCache[$class][$format])) { if (isset($this->normalizerCache[$class][$format])) {
return $this->normalizerCache[$class][$format]->normalize($object, $format, $properties); return $this->normalizerCache[$class][$format]->normalize($object, $format, $properties);
} }
$reflClass = new \ReflectionClass($class);
foreach ($this->normalizers as $normalizer) { foreach ($this->normalizers as $normalizer) {
if ($normalizer->supports($reflClass, $format)) { if ($normalizer->supportsNormalization($object, $class, $format)) {
$this->normalizerCache[$class][$format] = $normalizer; $this->normalizerCache[$class][$format] = $normalizer;
return $normalizer->normalize($object, $format, $properties); return $normalizer->normalize($object, $format, $properties);
} }
@ -86,13 +86,12 @@ class Serializer implements SerializerInterface
if (!$this->normalizers) { if (!$this->normalizers) {
throw new \LogicException('You must register at least one normalizer to be able to denormalize objects.'); throw new \LogicException('You must register at least one normalizer to be able to denormalize objects.');
} }
if (isset($this->normalizerCache[$class][$format])) { if (isset($this->denormalizerCache[$class][$format])) {
return $this->normalizerCache[$class][$format]->denormalize($data, $class, $format); return $this->denormalizerCache[$class][$format]->denormalize($data, $class, $format);
} }
$reflClass = new \ReflectionClass($class);
foreach ($this->normalizers as $normalizer) { foreach ($this->normalizers as $normalizer) {
if ($normalizer->supports($reflClass, $format)) { if ($normalizer->supportsDenormalization($class, $format)) {
$this->normalizerCache[$class][$format] = $normalizer; $this->denormalizerCache[$class][$format] = $normalizer;
return $normalizer->denormalize($data, $class, $format); return $normalizer->denormalize($data, $class, $format);
} }
} }
@ -107,22 +106,22 @@ class Serializer implements SerializerInterface
if (!$this->isStructuredType($data)) { if (!$this->isStructuredType($data)) {
return $data; return $data;
} }
if (is_array($data)) {
foreach ($data as $key => $val) {
$data[$key] = $this->isStructuredType($val) ? $this->normalize($val, $format) : $val;
}
return $data;
}
if ($data instanceof Traversable) { if ($data instanceof Traversable) {
$normalized = array(); $normalized = array();
foreach ($data as $key => $val) { foreach ($data as $key => $val) {
$normalized[$key] = $this->isStructuredType($val) ? $this->normalize($val, $format) : $val; $normalized[$key] = $this->normalize($val, $format);
} }
return $normalized; return $normalized;
} }
if (is_object($data)) { if (is_object($data)) {
return $this->normalizeObject($data, $format); return $this->normalizeObject($data, $format);
} }
if (is_array($data)) {
foreach ($data as $key => $val) {
$data[$key] = $this->normalize($val, $format);
}
return $data;
}
throw new \UnexpectedValueException('An unexpected value could not be normalized: '.var_export($data, true)); throw new \UnexpectedValueException('An unexpected value could not be normalized: '.var_export($data, true));
} }

View File

@ -44,9 +44,15 @@ class CustomNormalizerTest extends \PHPUnit_Framework_TestCase
$this->assertNull($obj->xmlFoo); $this->assertNull($obj->xmlFoo);
} }
public function testSupports() public function testSupportsNormalization()
{ {
$this->assertTrue($this->normalizer->supports(new \ReflectionClass(get_class(new ScalarDummy)))); $this->assertTrue($this->normalizer->supportsNormalization(new ScalarDummy));
$this->assertFalse($this->normalizer->supports(new \ReflectionClass('stdClass'))); $this->assertFalse($this->normalizer->supportsNormalization(new \stdClass));
}
public function testSupportsDenormalization()
{
$this->assertTrue($this->normalizer->supportsDenormalization(array(), 'Symfony\Tests\Component\Serializer\Fixtures\ScalarDummy'));
$this->assertFalse($this->normalizer->supportsDenormalization(array(), 'stdClass'));
} }
} }