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/Encoder/XmlEncoder.php b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php
index 13da7c0ec7..2e6dd1df8c 100644
--- a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php
+++ b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php
@@ -224,14 +224,14 @@ class XmlEncoder extends AbstractEncoder implements DecoderInterface
$append = $this->selectNodeType($parentNode, $data);
} elseif (is_array($data) && false === is_numeric($key)) {
/**
- * Is this array fully numeric keys?
- */
+ * Is this array fully numeric keys?
+ */
if (ctype_digit(implode('', array_keys($data)))) {
/**
- * Create nodes to append to $parentNode based on the $key of this array
- * Produces - 0
- 1
- * From array("item" => array(0,1));
- */
+ * Create nodes to append to $parentNode based on the $key of this array
+ * Produces - 0
- 1
+ * From array("item" => array(0,1));
+ */
foreach ($data as $subData) {
$append = $this->appendNode($parentNode, $subData, $key);
}
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 9a33861084..2350db7293 100644
--- a/src/Symfony/Component/Serializer/Normalizer/NormalizerInterface.php
+++ b/src/Symfony/Component/Serializer/Normalizer/NormalizerInterface.php
@@ -14,7 +14,7 @@ use Symfony\Component\Serializer\SerializerInterface;
*/
/**
- * Defines the interface of serializers
+ * Defines the interface of normalizers.
*
* @author Jordi Boggiano
*/
@@ -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 f7f012c110..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
@@ -46,7 +47,14 @@ class Serializer implements SerializerInterface
*/
public function serialize($data, $format)
{
- return $this->encode($data, $format);
+ return $this->encode($this->normalize($data, $format), $format);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function deserialize($data, $type, $format) {
+ return $this->denormalize($this->decode($data, $format), $type, $format);
}
/**
@@ -61,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);
}
@@ -79,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);
}
}
@@ -95,20 +101,38 @@ class Serializer implements SerializerInterface
/**
* {@inheritdoc}
*/
- public function normalize($data, $format)
+ public function normalize($data, $format = null)
{
- if (is_array($data)) {
- foreach ($data as $key => $val) {
- $data[$key] = $this->isStructuredType($val) ? $this->normalize($val, $format) : $val;
- }
+ if (!$this->isStructuredType($data)) {
return $data;
}
+ if ($data instanceof Traversable) {
+ $normalized = array();
+ foreach ($data as $key => $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));
}
+ /**
+ * {@inheritDoc}
+ */
+ public function denormalize($data, $type, $format = null)
+ {
+ return $this->denormalizeObject($data, $type, $format);
+ }
+
/**
* {@inheritdoc}
*/
diff --git a/src/Symfony/Component/Serializer/SerializerInterface.php b/src/Symfony/Component/Serializer/SerializerInterface.php
index 7f557221c5..262e06a893 100644
--- a/src/Symfony/Component/Serializer/SerializerInterface.php
+++ b/src/Symfony/Component/Serializer/SerializerInterface.php
@@ -31,6 +31,15 @@ interface SerializerInterface
*/
function serialize($data, $format);
+ /**
+ * Deserializes data into the given type.
+ *
+ * @param mixed $data
+ * @param string $type
+ * @param string $format
+ */
+ function deserialize($data, $type, $format);
+
/**
* Normalizes any data into a set of arrays/scalars
*
@@ -39,27 +48,18 @@ interface SerializerInterface
* @return array|scalar
* @api
*/
- function normalize($data, $format);
+ function normalize($data, $format = null);
/**
- * Normalizes an object into a set of arrays/scalars
+ * Denormalizes data into the given type.
*
- * @param object $object object to normalize
- * @param string $format format name, present to give the option to normalizers to act differently based on formats
- * @param array $properties a list of properties to extract, if null all properties are returned
- * @return array|scalar
- */
- function normalizeObject($object, $format, $properties = null);
-
- /**
- * Denormalizes data back into an object of the given class
+ * @param mixed $data
+ * @param string $type
+ * @param string $format
*
- * @param mixed $data data to restore
- * @param string $class the expected class to instantiate
- * @param string $format format name, present to give the option to normalizers to act differently based on formats
- * @return object
+ * @return mixed
*/
- function denormalizeObject($data, $class, $format = null);
+ function denormalize($data, $type, $format = null);
/**
* Encodes data into the given format
@@ -80,48 +80,4 @@ interface SerializerInterface
* @api
*/
function decode($data, $format);
-
- /**
- * @param NormalizerInterface $normalizer
- */
- function addNormalizer(NormalizerInterface $normalizer);
-
- /**
- * @return array[]NormalizerInterface
- */
- function getNormalizers();
-
- /**
- * @param NormalizerInterface $normalizer
- */
- function removeNormalizer(NormalizerInterface $normalizer);
-
- /**
- * @param string $format format name
- * @param EncoderInterface $encoder
- */
- function setEncoder($format, EncoderInterface $encoder);
-
- /**
- * @return EncoderInterface
- */
- function getEncoders();
-
- /**
- * @return array[]EncoderInterface
- */
- function getEncoder($format);
-
- /**
- * Checks whether the serializer has an encoder registered for the given format
- *
- * @param string $format format name
- * @return Boolean
- */
- function hasEncoder($format);
-
- /**
- * @param string $format format name
- */
- function removeEncoder($format);
}
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'));
}
}
diff --git a/tests/Symfony/Tests/Component/Serializer/Normalizer/GetSetMethodNormalizerTest.php b/tests/Symfony/Tests/Component/Serializer/Normalizer/GetSetMethodNormalizerTest.php
index 6544075598..2ac0b1c024 100644
--- a/tests/Symfony/Tests/Component/Serializer/Normalizer/GetSetMethodNormalizerTest.php
+++ b/tests/Symfony/Tests/Component/Serializer/Normalizer/GetSetMethodNormalizerTest.php
@@ -29,7 +29,8 @@ class GetSetMethodNormalizerTest extends \PHPUnit_Framework_TestCase
$obj->setBar('bar');
$this->assertEquals(
array('foo' => 'foo', 'bar' => 'bar', 'foobar' => 'foobar'),
- $this->normalizer->normalize($obj, 'any'));
+ $this->normalizer->normalize($obj, 'any')
+ );
}
public function testNormalizeRestricted()
@@ -39,14 +40,17 @@ class GetSetMethodNormalizerTest extends \PHPUnit_Framework_TestCase
$obj->setBar('bar');
$this->assertEquals(
array('foo' => 'foo'),
- $this->normalizer->normalize($obj, 'any', array('foo')));
+ $this->normalizer->normalize($obj, 'any', array('foo'))
+ );
}
public function testDenormalize()
{
$obj = $this->normalizer->denormalize(
array('foo' => 'foo', 'bar' => 'bar', 'foobar' => 'foobar'),
- __NAMESPACE__.'\GetSetDummy', 'any');
+ __NAMESPACE__.'\GetSetDummy',
+ 'any'
+ );
$this->assertEquals('foo', $obj->getFoo());
$this->assertEquals('bar', $obj->getBar());
}