From ded30a2937a053eae91ceac09cae3d4570a988b9 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 6 May 2011 19:36:56 +0200 Subject: [PATCH] [Serializer] Split supports in supportsNormalization and supportsDenormalization --- UPDATE.md | 7 +++-- .../Normalizer/CustomNormalizer.php | 24 +++++++++++++---- .../Normalizer/GetSetMethodNormalizer.php | 26 +++++++++++++----- .../Normalizer/NormalizerInterface.php | 21 ++++++++++----- .../Component/Serializer/Serializer.php | 27 +++++++++---------- .../Normalizer/CustomNormalizerTest.php | 12 ++++++--- 6 files changed, 81 insertions(+), 36 deletions(-) diff --git a/UPDATE.md b/UPDATE.md index 7f0d58bab7..9e05a08d84 100644 --- a/UPDATE.md +++ b/UPDATE.md @@ -124,6 +124,9 @@ beta1 to beta2 'allow_delete' => true, )); +* Serializer: The NormalizerInterface's `supports()` method has been split in + two methods: `supportsNormalization` and `supportsDenormalization`. + PR12 to beta1 ------------- @@ -210,11 +213,11 @@ PR11 to PR12 twig twig.extension.debug -* 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 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 references this will result in a compile-time exception instead of a run-time exception (the previous behavior). diff --git a/src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php index ecbf5f061e..1f1c6a0504 100644 --- a/src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php @@ -39,13 +39,27 @@ class CustomNormalizer extends AbstractNormalizer /** * Checks if the given class implements the NormalizableInterface. * - * @param ReflectionClass $class A ReflectionClass instance of the class - * to serialize into or from. - * @param string $format The format being (de-)serialized from or into. + * @param mixed $data Data to normalize. + * @param string $format The format being (de-)serialized from or into. * @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'); } } diff --git a/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php index b4bf69e3df..76f5e397a4 100644 --- a/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php @@ -107,23 +107,37 @@ class GetSetMethodNormalizer extends AbstractNormalizer 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. * - * @param ReflectionClass $class A ReflectionClass instance of the class - * to serialize into or from. - * @param string $format The format being (de-)serialized from or into. - * @return Boolean Whether the class has any getters. + * @param string $class + * @return Boolean */ - public function supports(\ReflectionClass $class, $format = null) + private function supports($class) { + $class = new \ReflectionClass($type); $methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC); foreach ($methods as $method) { if ($this->isGetMethod($method)) { return true; } } - return false; } diff --git a/src/Symfony/Component/Serializer/Normalizer/NormalizerInterface.php b/src/Symfony/Component/Serializer/Normalizer/NormalizerInterface.php index 7b5ee8c247..2350db7293 100644 --- a/src/Symfony/Component/Serializer/Normalizer/NormalizerInterface.php +++ b/src/Symfony/Component/Serializer/Normalizer/NormalizerInterface.php @@ -43,16 +43,25 @@ interface NormalizerInterface function denormalize($data, $class, $format = null); /** - * Checks whether the given class is supported by this normalizer - * - * @param ReflectionClass $class - * @param string $format format the given data was extracted from + * Checks whether the given class is supported for normalization by this normalizer * + * @param mixed $data Data to normalize. + * @param string $format The format being (de-)serialized from or into. * @return Boolean - * * @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 diff --git a/src/Symfony/Component/Serializer/Serializer.php b/src/Symfony/Component/Serializer/Serializer.php index 0933eab677..123fd7f4b0 100644 --- a/src/Symfony/Component/Serializer/Serializer.php +++ b/src/Symfony/Component/Serializer/Serializer.php @@ -31,6 +31,7 @@ class Serializer implements SerializerInterface private $normalizers = array(); private $encoders = array(); protected $normalizerCache = array(); + protected $denormalizerCache = array(); /** * @param mixed $value value to test @@ -68,9 +69,8 @@ class Serializer implements SerializerInterface if (isset($this->normalizerCache[$class][$format])) { return $this->normalizerCache[$class][$format]->normalize($object, $format, $properties); } - $reflClass = new \ReflectionClass($class); foreach ($this->normalizers as $normalizer) { - if ($normalizer->supports($reflClass, $format)) { + if ($normalizer->supportsNormalization($object, $class, $format)) { $this->normalizerCache[$class][$format] = $normalizer; return $normalizer->normalize($object, $format, $properties); } @@ -86,13 +86,12 @@ class Serializer implements SerializerInterface if (!$this->normalizers) { throw new \LogicException('You must register at least one normalizer to be able to denormalize objects.'); } - if (isset($this->normalizerCache[$class][$format])) { - return $this->normalizerCache[$class][$format]->denormalize($data, $class, $format); + if (isset($this->denormalizerCache[$class][$format])) { + return $this->denormalizerCache[$class][$format]->denormalize($data, $class, $format); } - $reflClass = new \ReflectionClass($class); foreach ($this->normalizers as $normalizer) { - if ($normalizer->supports($reflClass, $format)) { - $this->normalizerCache[$class][$format] = $normalizer; + if ($normalizer->supportsDenormalization($class, $format)) { + $this->denormalizerCache[$class][$format] = $normalizer; return $normalizer->denormalize($data, $class, $format); } } @@ -107,22 +106,22 @@ class Serializer implements SerializerInterface if (!$this->isStructuredType($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) { $normalized = array(); foreach ($data as $key => $val) { - $normalized[$key] = $this->isStructuredType($val) ? $this->normalize($val, $format) : $val; + $normalized[$key] = $this->normalize($val, $format); } return $normalized; } if (is_object($data)) { 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)); } diff --git a/tests/Symfony/Tests/Component/Serializer/Normalizer/CustomNormalizerTest.php b/tests/Symfony/Tests/Component/Serializer/Normalizer/CustomNormalizerTest.php index a441544b4d..4a98954dcc 100644 --- a/tests/Symfony/Tests/Component/Serializer/Normalizer/CustomNormalizerTest.php +++ b/tests/Symfony/Tests/Component/Serializer/Normalizer/CustomNormalizerTest.php @@ -44,9 +44,15 @@ class CustomNormalizerTest extends \PHPUnit_Framework_TestCase $this->assertNull($obj->xmlFoo); } - public function testSupports() + public function testSupportsNormalization() { - $this->assertTrue($this->normalizer->supports(new \ReflectionClass(get_class(new ScalarDummy)))); - $this->assertFalse($this->normalizer->supports(new \ReflectionClass('stdClass'))); + $this->assertTrue($this->normalizer->supportsNormalization(new ScalarDummy)); + $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')); } }