浏览代码

Merge remote branch 'Seldaek/serializer'

* Seldaek/serializer:
  [Serializer] CS fixes
  [Serializer] Split supports in supportsNormalization and supportsDenormalization
  [Serializer] Add support for Traversable objects
  Fixed docs typo
  [Serializer] updated SerializerInterface
Fabien Potencier 14 年之前
父节点
当前提交
c98bf4ff94

+ 5 - 2
UPDATE.md

@@ -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).

+ 6 - 6
src/Symfony/Component/Serializer/Encoder/XmlEncoder.php

@@ -224,14 +224,14 @@ class XmlEncoder extends AbstractEncoder implements DecoderInterface
                     $append = $this->selectNodeType($parentNode, $data);
                     $append = $this->selectNodeType($parentNode, $data);
                 } elseif (is_array($data) && false === is_numeric($key)) {
                 } 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)))) {
                     if (ctype_digit(implode('', array_keys($data)))) {
                         /**
                         /**
-                        * Create nodes to append to $parentNode based on the $key of this array
-                        * Produces <xml><item>0</item><item>1</item></xml>
-                        * From array("item" => array(0,1));
-                        */
+                         * Create nodes to append to $parentNode based on the $key of this array
+                         * Produces <xml><item>0</item><item>1</item></xml>
+                         * From array("item" => array(0,1));
+                         */
                         foreach ($data as $subData) {
                         foreach ($data as $subData) {
                             $append = $this->appendNode($parentNode, $subData, $key);
                             $append = $this->appendNode($parentNode, $subData, $key);
                         }
                         }

+ 19 - 5
src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php

@@ -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
-     *                                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
      * @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');
     }
     }
 }
 }

+ 20 - 6
src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php

@@ -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
-     *                                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);
         $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;
     }
     }
 
 

+ 15 - 6
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 <j.boggiano@seld.be>
  * @author Jordi Boggiano <j.boggiano@seld.be>
  */
  */
@@ -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
-     *
-     * @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
      * @return Boolean
+     * @api
+     */
+    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
      * @api
      */
      */
-    function supports(\ReflectionClass $class, $format = null);
+    function supportsDenormalization($data, $type, $format = null);
 
 
     /**
     /**
      * Sets the owning Serializer object
      * Sets the owning Serializer object

+ 36 - 12
src/Symfony/Component/Serializer/Serializer.php

@@ -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
@@ -46,7 +47,14 @@ class Serializer implements SerializerInterface
      */
      */
     public function serialize($data, $format)
     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])) {
         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);
             }
             }
@@ -79,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])) {
-            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) {
         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);
                 return $normalizer->denormalize($data, $class, $format);
             }
             }
         }
         }
@@ -95,20 +101,38 @@ class Serializer implements SerializerInterface
     /**
     /**
      * {@inheritdoc}
      * {@inheritdoc}
      */
      */
-    public function normalize($data, $format)
+    public function normalize($data, $format = null)
     {
     {
-        if (is_array($data)) {
+        if (!$this->isStructuredType($data)) {
+            return $data;
+        }
+        if ($data instanceof Traversable) {
+            $normalized = array();
             foreach ($data as $key => $val) {
             foreach ($data as $key => $val) {
-                $data[$key] = $this->isStructuredType($val) ? $this->normalize($val, $format) : $val;
+                $normalized[$key] = $this->normalize($val, $format);
             }
             }
-            return $data;
+            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));
     }
     }
 
 
+    /**
+     * {@inheritDoc}
+     */
+    public function denormalize($data, $type, $format = null)
+    {
+        return $this->denormalizeObject($data, $type, $format);
+    }
+
     /**
     /**
      * {@inheritdoc}
      * {@inheritdoc}
      */
      */

+ 16 - 60
src/Symfony/Component/Serializer/SerializerInterface.php

@@ -32,34 +32,34 @@ interface SerializerInterface
     function serialize($data, $format);
     function serialize($data, $format);
 
 
     /**
     /**
-     * Normalizes any data into a set of arrays/scalars
+     * Deserializes data into the given type.
      *
      *
-     * @param mixed $data data to normalize
-     * @param string $format format name, present to give the option to normalizers to act differently based on formats
-     * @return array|scalar
-     * @api
+     * @param mixed $data
+     * @param string $type
+     * @param string $format
      */
      */
-    function normalize($data, $format);
+    function deserialize($data, $type, $format);
 
 
     /**
     /**
-     * Normalizes an object into a set of arrays/scalars
+     * Normalizes any data into a set of arrays/scalars
      *
      *
-     * @param object $object object to normalize
+     * @param mixed $data data to normalize
      * @param string $format format name, present to give the option to normalizers to act differently based on formats
      * @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
      * @return array|scalar
+     * @api
      */
      */
-    function normalizeObject($object, $format, $properties = null);
+    function normalize($data, $format = null);
 
 
     /**
     /**
-     * Denormalizes data back into an object of the given class
+     * Denormalizes data into the given type.
      *
      *
-     * @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
+     * @param mixed $data
+     * @param string $type
+     * @param string $format
+     *
+     * @return mixed
      */
      */
-    function denormalizeObject($data, $class, $format = null);
+    function denormalize($data, $type, $format = null);
 
 
     /**
     /**
      * Encodes data into the given format
      * Encodes data into the given format
@@ -80,48 +80,4 @@ interface SerializerInterface
      * @api
      * @api
      */
      */
     function decode($data, $format);
     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);
 }
 }

+ 9 - 3
tests/Symfony/Tests/Component/Serializer/Normalizer/CustomNormalizerTest.php

@@ -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->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'));
     }
     }
 }
 }

+ 7 - 3
tests/Symfony/Tests/Component/Serializer/Normalizer/GetSetMethodNormalizerTest.php

@@ -29,7 +29,8 @@ class GetSetMethodNormalizerTest extends \PHPUnit_Framework_TestCase
         $obj->setBar('bar');
         $obj->setBar('bar');
         $this->assertEquals(
         $this->assertEquals(
             array('foo' => 'foo', 'bar' => 'bar', 'foobar' => 'foobar'),
             array('foo' => 'foo', 'bar' => 'bar', 'foobar' => 'foobar'),
-            $this->normalizer->normalize($obj, 'any'));
+            $this->normalizer->normalize($obj, 'any')
+        );
     }
     }
 
 
     public function testNormalizeRestricted()
     public function testNormalizeRestricted()
@@ -39,14 +40,17 @@ class GetSetMethodNormalizerTest extends \PHPUnit_Framework_TestCase
         $obj->setBar('bar');
         $obj->setBar('bar');
         $this->assertEquals(
         $this->assertEquals(
             array('foo' => 'foo'),
             array('foo' => 'foo'),
-            $this->normalizer->normalize($obj, 'any', array('foo')));
+            $this->normalizer->normalize($obj, 'any', array('foo'))
+        );
     }
     }
 
 
     public function testDenormalize()
     public function testDenormalize()
     {
     {
         $obj = $this->normalizer->denormalize(
         $obj = $this->normalizer->denormalize(
             array('foo' => 'foo', 'bar' => 'bar', 'foobar' => 'foobar'),
             array('foo' => 'foo', 'bar' => 'bar', 'foobar' => 'foobar'),
-            __NAMESPACE__.'\GetSetDummy', 'any');
+            __NAMESPACE__.'\GetSetDummy',
+            'any'
+        );
         $this->assertEquals('foo', $obj->getFoo());
         $this->assertEquals('foo', $obj->getFoo());
         $this->assertEquals('bar', $obj->getBar());
         $this->assertEquals('bar', $obj->getBar());
     }
     }