소스 검색

Merge branch 'objectBasedHandler'

Johannes M. Schmitt 14 년 전
부모
커밋
c9387b0eb4

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+/phpunit.xml

+ 11 - 1
DependencyInjection/Configuration.php

@@ -49,6 +49,16 @@ class Configuration implements ConfigurationInterface
                     ->arrayNode('handlers')
                         ->addDefaultsIfNotSet()
                         ->children()
+                            ->arrayNode('object_based')
+                                ->treatTrueLike(array('serialization' => true, 'deserialization' => true))
+                                ->treatNullLike(array('serialization' => true, 'deserialization' => true))
+                                ->treatFalseLike(array('serialization' => false, 'deserialization' => false))
+                                ->addDefaultsIfNotSet()
+                                ->children()
+                                    ->booleanNode('serialization')->defaultFalse()->end()
+                                    ->booleanNode('deserialization')->defaultFalse()->end()
+                                ->end()
+                            ->end()
                             ->arrayNode('datetime')
                                 ->addDefaultsIfNotSet()
                                 ->canBeUnset()
@@ -91,4 +101,4 @@ class Configuration implements ConfigurationInterface
 
         return $tb;
     }
-}
+}

+ 9 - 1
DependencyInjection/JMSSerializerExtension.php

@@ -51,6 +51,14 @@ class JMSSerializerExtension extends Extension
             $container->setAlias('jms_serializer.naming_strategy', 'jms_serializer.cache_naming_strategy');
         }
 
+        // object based custom handler
+        if ($config['handlers']['object_based']['serialization']) {
+            $container->getDefinition('jms_serializer.object_based_custom_handler')->addTag('jms_serialization.serialization_handler');
+        }
+        if ($config['handlers']['object_based']['deserialization']) {
+            $container->getDefinition('jms_serializer.object_based_custom_handler')->addTag('jms_serialization.deserialization_handler');
+        }
+
         // datetime handler
         if (isset($config['handlers']['datetime'])) {
             $container
@@ -125,4 +133,4 @@ class JMSSerializerExtension extends Extension
 
         return $processor->process($config->getConfigTreeBuilder()->buildTree(), $configs);
     }
-}
+}

+ 6 - 1
Resources/config/services.xml

@@ -31,6 +31,7 @@
         <parameter key="jms_serializer.xml_serialization_visitor.class">JMS\SerializerBundle\Serializer\XmlSerializationVisitor</parameter>
         <parameter key="jms_serializer.xml_deserialization_visitor.class">JMS\SerializerBundle\Serializer\XmlDeserializationVisitor</parameter>
         
+        <parameter key="jms_serializer.object_based_custom_handler.class">JMS\SerializerBundle\Serializer\Handler\ObjectBasedCustomHandler</parameter>
         <parameter key="jms_serializer.datetime_handler.class">JMS\SerializerBundle\Serializer\Handler\DateTimeHandler</parameter>
         <parameter key="jms_serializer.array_collection_handler.class">JMS\SerializerBundle\Serializer\Handler\ArrayCollectionHandler</parameter>
         <parameter key="jms_serializer.form_error_handler.class">JMS\SerializerBundle\Serializer\Handler\FormErrorHandler</parameter>
@@ -137,6 +138,10 @@
         </service>
         
         <!-- Custom Handlers -->
+        <service id="jms_serializer.object_based_custom_handler" class="%jms_serializer.object_based_custom_handler.class%" public="false">
+            <argument type="service" id="jms_serializer.unserialize_object_constructor" />
+            <argument type="service" id="jms_serializer.metadata_factory" />
+        </service>
         <service id="jms_serializer.datetime_handler" class="%jms_serializer.datetime_handler.class%" public="false">
             <tag name="jms_serializer.serialization_handler" />
             <tag name="jms_serializer.deserialization_handler" />
@@ -152,4 +157,4 @@
             <tag name="jms_serializer.serialization_handler" />
         </service>
     </services>
-</container>
+</container>

+ 1 - 0
Resources/doc/index.rst

@@ -53,6 +53,7 @@ suit your needs::
 
     jms_serializer:
         handlers:
+            object_based: false
             datetime:
                 format: Y-m-dTH:i:s
                 default_timezone: UTC

+ 1 - 2
Serializer/GenericDeserializationVisitor.php

@@ -190,7 +190,6 @@ abstract class GenericDeserializationVisitor extends AbstractVisitor
 
     public function visitUsingCustomHandler($data, $type, &$visited)
     {
-        $visited = false;
         foreach ($this->customHandlers as $handler) {
             $rs = $handler->deserialize($this, $data, $type, $visited);
             if ($visited) {
@@ -227,4 +226,4 @@ abstract class GenericDeserializationVisitor extends AbstractVisitor
     }
 
     abstract protected function decode($str);
-}
+}

+ 1 - 2
Serializer/GenericSerializationVisitor.php

@@ -141,7 +141,6 @@ abstract class GenericSerializationVisitor extends AbstractVisitor
 
     public function visitUsingCustomHandler($data, $type, &$visited)
     {
-        $visited = false;
         foreach ($this->customHandlers as $handler) {
             $rs = $handler->serialize($this, $data, $type, $visited);
             if ($visited) {
@@ -165,4 +164,4 @@ abstract class GenericSerializationVisitor extends AbstractVisitor
     {
         $this->root = $data;
     }
-}
+}

+ 3 - 2
Serializer/GraphNavigator.php

@@ -67,7 +67,8 @@ final class GraphNavigator
                 $this->visiting->attach($data);
             }
 
-             // try custom handler
+            // try custom handler
+            $handled = false;
             $rs = $visitor->visitUsingCustomHandler($data, $type, $handled);
             if ($handled) {
                 if ($isSerialization) {
@@ -136,4 +137,4 @@ final class GraphNavigator
             }
         }
     }
-}
+}

+ 46 - 0
Serializer/Handler/ObjectBasedCustomHandler.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace JMS\SerializerBundle\Serializer\Handler;
+
+use Metadata\MetadataFactoryInterface;
+
+use JMS\SerializerBundle\Serializer\VisitorInterface;
+use JMS\SerializerBundle\Serializer\Construction\ObjectConstructorInterface;
+
+class ObjectBasedCustomHandler implements SerializationHandlerInterface, DeserializationHandlerInterface
+{
+    private $objectConstructor;
+    private $metadataFactory;
+
+    public function __construct(ObjectConstructorInterface $objectConstructor, MetadataFactoryInterface $metadataFactory)
+    {
+        $this->objectConstructor = $objectConstructor;
+        $this->metadataFactory = $metadataFactory;
+    }
+
+    public function serialize(VisitorInterface $visitor, $data, $type, &$handled)
+    {
+        if (!$data instanceof SerializationHandlerInterface) {
+            return;
+        }
+
+        return $data->serialize($visitor, $data, $type, $handled);
+    }
+
+    public function deserialize(VisitorInterface $visitor, $data, $type, &$handled)
+    {
+        if (!class_exists($type)
+            || !in_array('JMS\SerializerBundle\Serializer\Handler\DeserializationHandlerInterface', class_implements($type))
+        ) {
+            return;
+        }
+
+        $metadata = $this->metadataFactory->getMetadataForClass($type);
+        $visitor->startVisitingObject($metadata, $data, $type);
+
+        $instance = $visitor->getResult();
+        $instance->deserialize($visitor, $data, $type, $handled);
+
+        return $instance;
+    }
+}

+ 1 - 2
Serializer/XmlSerializationVisitor.php

@@ -136,7 +136,6 @@ class XmlSerializationVisitor extends AbstractVisitor
 
     public function visitUsingCustomHandler($data, $type, &$visited)
     {
-        $visited = false;
         foreach ($this->customHandlers as $handler) {
             $rs = $handler->serialize($this, $data, $type, $visited);
             if ($visited) {
@@ -268,4 +267,4 @@ class XmlSerializationVisitor extends AbstractVisitor
 
         return $this->document->createTextNode((string) $data);
     }
-}
+}

+ 30 - 20
Tests/DependencyInjection/JMSSerializerExtensionTest.php

@@ -18,17 +18,20 @@
 
 namespace JMS\SerializerBundle\Tests\DependencyInjection;
 
-use JMS\SerializerBundle\Tests\Fixtures\SimpleObject;
+use Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass;
 
-use Doctrine\Common\Annotations\AnnotationReader;
+use Symfony\Component\DependencyInjection\Compiler\RepeatedPass;
+
+use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass;
 
+use Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass;
+
+use JMS\SerializerBundle\Tests\Fixtures\SimpleObject;
+use Doctrine\Common\Annotations\AnnotationReader;
 use Symfony\Component\DependencyInjection\Compiler\ResolveDefinitionTemplatesPass;
 use JMS\SerializerBundle\JMSSerializerBundle;
-
 use Doctrine\Common\Annotations\Reader;
-
 use JMS\SerializerBundle\Tests\Fixtures\VersionedObject;
-
 use Symfony\Component\DependencyInjection\ContainerBuilder;
 use JMS\SerializerBundle\DependencyInjection\JMSSerializerExtension;
 
@@ -53,6 +56,26 @@ class JMSSerializerExtensionTest extends \PHPUnit_Framework_TestCase
     }
 
     public function testLoad()
+    {
+        $container = $this->getContainerForConfig(array(array()));
+
+        $simpleObject = new SimpleObject('foo', 'bar');
+        $versionedObject  = new VersionedObject('foo', 'bar');
+        $serializer = $container->get('serializer');
+
+        // test that all components have been wired correctly
+        $this->assertEquals(json_encode(array('name' => 'bar')), $serializer->serialize($versionedObject, 'json'));
+        $this->assertEquals($simpleObject, $serializer->deserialize($serializer->serialize($simpleObject, 'json'), get_class($simpleObject), 'json'));
+        $this->assertEquals($simpleObject, $serializer->deserialize($serializer->serialize($simpleObject, 'xml'), get_class($simpleObject), 'xml'));
+
+        $serializer->setVersion('0.0.1');
+        $this->assertEquals(json_encode(array('name' => 'foo')), $serializer->serialize($versionedObject, 'json'));
+
+        $serializer->setVersion('1.1.1');
+        $this->assertEquals(json_encode(array('name' => 'bar')), $serializer->serialize($versionedObject, 'json'));
+    }
+
+    private function getContainerForConfig(array $configs)
     {
         $extension = new JMSSerializerExtension();
         $container = new ContainerBuilder();
@@ -62,7 +85,7 @@ class JMSSerializerExtensionTest extends \PHPUnit_Framework_TestCase
         $container->set('annotation_reader', new AnnotationReader());
         $container->set('service_container', $container);
         $container->set('translator', $this->getMock('Symfony\\Component\\Translation\\TranslatorInterface'));
-        $extension->load(array(array()), $container);
+        $extension->load($configs, $container);
 
         $bundle = new JMSSerializerBundle();
         $bundle->build($container);
@@ -73,19 +96,6 @@ class JMSSerializerExtensionTest extends \PHPUnit_Framework_TestCase
         $container->getCompilerPassConfig()->setRemovingPasses(array());
         $container->compile();
 
-        $simpleObject = new SimpleObject('foo', 'bar');
-        $versionedObject  = new VersionedObject('foo', 'bar');
-        $serializer = $container->get('serializer');
-
-        // test that all components have been wired correctly
-        $this->assertEquals(json_encode(array('name' => 'bar')), $serializer->serialize($versionedObject, 'json'));
-        $this->assertEquals($simpleObject, $serializer->deserialize($serializer->serialize($simpleObject, 'json'), get_class($simpleObject), 'json'));
-        $this->assertEquals($simpleObject, $serializer->deserialize($serializer->serialize($simpleObject, 'xml'), get_class($simpleObject), 'xml'));
-
-        $serializer->setVersion('0.0.1');
-        $this->assertEquals(json_encode(array('name' => 'foo')), $serializer->serialize($versionedObject, 'json'));
-
-        $serializer->setVersion('1.1.1');
-        $this->assertEquals(json_encode(array('name' => 'bar')), $serializer->serialize($versionedObject, 'json'));
+        return $container;
     }
 }

+ 71 - 1
Tests/Serializer/BaseSerializationTest.php

@@ -24,6 +24,7 @@ use Symfony\Component\Form\FormError;
 use Symfony\Component\Validator\ConstraintViolation;
 use Symfony\Component\Validator\ConstraintViolationList;
 use JMS\SerializerBundle\Serializer\Handler\DeserializationHandlerInterface;
+use JMS\SerializerBundle\Serializer\Handler\SerializationHandlerInterface;
 use JMS\SerializerBundle\Tests\Fixtures\AuthorList;
 use JMS\SerializerBundle\Serializer\VisitorInterface;
 use JMS\SerializerBundle\Serializer\XmlDeserializationVisitor;
@@ -31,6 +32,7 @@ use JMS\SerializerBundle\Serializer\Construction\UnserializeObjectConstructor;
 use JMS\SerializerBundle\Serializer\JsonDeserializationVisitor;
 use JMS\SerializerBundle\Tests\Fixtures\Log;
 use JMS\SerializerBundle\Serializer\Handler\ArrayCollectionHandler;
+use JMS\SerializerBundle\Serializer\Handler\ObjectBasedCustomHandler;
 use JMS\SerializerBundle\Serializer\Handler\DateTimeHandler;
 use JMS\SerializerBundle\Serializer\Handler\FormErrorHandler;
 use JMS\SerializerBundle\Serializer\Handler\ConstraintViolationHandler;
@@ -150,6 +152,18 @@ abstract class BaseSerializationTest extends \PHPUnit_Framework_TestCase
         $this->assertAttributeEquals($author, 'author', $deserialized);
     }
 
+    public function testArticle()
+    {
+        $article = new Article();
+        $article->element = 'custom';
+        $article->value = 'serialized';
+
+        $result = $this->serialize($article);
+        $this->assertEquals($this->getContent('article'), $result);
+
+        $this->assertEquals($article, $this->deserialize($result, 'JMS\SerializerBundle\Tests\Serializer\Article'));
+    }
+
     /**
      * @group test
      */
@@ -275,7 +289,11 @@ abstract class BaseSerializationTest extends \PHPUnit_Framework_TestCase
             ->method('trans')
             ->will($this->returnArgument(0));
 
+        $factory = new MetadataFactory(new AnnotationDriver(new AnnotationReader()));
+        $objectConstructor = new UnserializeObjectConstructor();
+
         $handlers = array(
+            new ObjectBasedCustomHandler($objectConstructor, $factory),
             new DateTimeHandler(),
             new FormErrorHandler($translatorMock),
             new ConstraintViolationHandler(),
@@ -286,7 +304,11 @@ abstract class BaseSerializationTest extends \PHPUnit_Framework_TestCase
 
     protected function getDeserializationHandlers()
     {
+        $factory = new MetadataFactory(new AnnotationDriver(new AnnotationReader()));
+        $objectConstructor = new UnserializeObjectConstructor();
+
         $handlers = array(
+            new ObjectBasedCustomHandler($objectConstructor, $factory),
             new DateTimeHandler(),
             new ArrayCollectionHandler(),
             new AuthorListDeserializationHandler(),
@@ -328,4 +350,52 @@ class AuthorListDeserializationHandler implements DeserializationHandlerInterfac
 
         return $list;
     }
-}
+}
+
+class Article implements SerializationHandlerInterface, DeserializationHandlerInterface
+{
+    public $element;
+    public $value;
+
+    public function serialize(VisitorInterface $visitor, $data, $type, &$visited)
+    {
+        if (!$data instanceof Article) {
+            return;
+        }
+
+        if ($visitor instanceof XmlSerializationVisitor) {
+            $visited = true;
+
+            if (null === $visitor->document) {
+                $visitor->document = $visitor->createDocument(null, null, false);
+            }
+
+            $visitor->document->appendChild($visitor->document->createElement($this->element, $this->value));
+        } elseif ($visitor instanceof JsonSerializationVisitor) {
+            $visited = true;
+
+            $visitor->setRoot(array($this->element => $this->value));
+        }
+    }
+
+    public function deserialize(VisitorInterface $visitor, $data, $type, &$visited)
+    {
+        if ('JMS\SerializerBundle\Tests\Serializer\Article' !== $type) {
+            return;
+        }
+
+        if ($visitor instanceof XmlDeserializationVisitor) {
+            $visited = true;
+
+            $this->element = $data->getName();
+            $this->value = (string)$data;
+        } elseif ($visitor instanceof JsonDeserializationVisitor) {
+            $visited = true;
+
+            $this->element = key($data);
+            $this->value = reset($data);
+        }
+
+        return $this;
+    }
+}

+ 2 - 1
Tests/Serializer/JsonSerializationTest.php

@@ -49,6 +49,7 @@ class JsonSerializationTest extends BaseSerializationTest
             $outputs['nested_form_errors'] = '{"errors":["This is the form error"],"children":{"bar":{"errors":["Error of the child form"]}}}';
             $outputs['constraint_violation'] = '{"property_path":"foo","message":"Message of violation"}';
             $outputs['constraint_violation_list'] = '[{"property_path":"foo","message":"Message of violation"},{"property_path":"bar","message":"Message of another violation"}]';
+            $outputs['article'] = '{"custom":"serialized"}';
         }
 
         if (!isset($outputs[$key])) {
@@ -62,4 +63,4 @@ class JsonSerializationTest extends BaseSerializationTest
     {
         return 'json';
     }
-}
+}

+ 2 - 0
Tests/Serializer/xml/article.xml

@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<custom>serialized</custom>