Ver Fonte

added lifecycle callbacks

Johannes Schmitt há 14 anos atrás
pai
commit
5ff027bad3

+ 15 - 0
Annotation/PostDeserialize.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace JMS\SerializerBundle\Annotation;
+
+/**
+ * This annotation can be defined on methods which are called after the
+ * deserialization of the object is complete.
+ *
+ * These methods do not necessarily have to be public.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class PostDeserialize
+{
+}

+ 16 - 0
Annotation/PreSerialize.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace JMS\SerializerBundle\Annotation;
+
+/**
+ * This annotation can be declared on methods which should be called
+ * before the Serialization process.
+ *
+ * These methods do not need to be public, and should do any clean-up, or
+ * preparation of the object that is necessary.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class PreSerialize
+{
+}

+ 17 - 0
Metadata/ClassMetadata.php

@@ -18,16 +18,31 @@
 
 namespace JMS\SerializerBundle\Metadata;
 
+use Metadata\MethodMetadata;
 use Metadata\ClassMetadata as BaseClassMetadata;
 
 class ClassMetadata extends BaseClassMetadata
 {
     public $exclusionPolicy = 'NONE';
+    public $preSerializeMethods = array();
+    public $postDeserializeMethods = array();
+
+    public function addPreSerializeMethod(MethodMetadata $method)
+    {
+        $this->preSerializeMethods[] = $method;
+    }
+
+    public function addPostDeserializeMethod(MethodMetadata $method)
+    {
+        $this->postDeserializeMethods[] = $method;
+    }
 
     public function serialize()
     {
         return serialize(array(
             $this->exclusionPolicy,
+            $this->preSerializeMethods,
+            $this->postDeserializeMethods,
             parent::serialize(),
         ));
     }
@@ -36,6 +51,8 @@ class ClassMetadata extends BaseClassMetadata
     {
         list(
             $this->exclusionPolicy,
+            $this->preSerializeMethods,
+            $this->postDeserializeMethods,
             $parentStr
         ) = unserialize($str);
 

+ 22 - 0
Metadata/Driver/AnnotationDriver.php

@@ -18,6 +18,12 @@
 
 namespace JMS\SerializerBundle\Metadata\Driver;
 
+use JMS\SerializerBundle\Annotation\PostDeserialize;
+
+use JMS\SerializerBundle\Annotation\PreSerialize;
+
+use Metadata\MethodMetadata;
+
 use Doctrine\Common\Annotations\Reader;
 use JMS\SerializerBundle\Annotation\Type;
 use JMS\SerializerBundle\Annotation\Exclude;
@@ -74,6 +80,22 @@ class AnnotationDriver implements DriverInterface
             $classMetadata->addPropertyMetadata($propertyMetadata);
         }
 
+        foreach ($class->getMethods() as $method) {
+            if ($method->getDeclaringClass()->getName() !== $name) {
+                continue;
+            }
+
+            foreach ($this->reader->getMethodAnnotations($method) as $annot) {
+                if ($annot instanceof PreSerialize) {
+                    $classMetadata->addPreSerializeMethod(new MethodMetadata($name, $method->getName()));
+                    continue 2;
+                } else if ($annot instanceof PostDeserialize) {
+                    $classMetadata->addPostDeserializeMethod(new MethodMetadata($name, $method->getName()));
+                    continue 2;
+                }
+            }
+        }
+
         return $classMetadata;
     }
 }

+ 9 - 0
Serializer/Normalizer/PropertyBasedNormalizer.php

@@ -66,6 +66,11 @@ class PropertyBasedNormalizer extends SerializerAwareNormalizer
 
         foreach ($metadata->classMetadata as $classMetadata) {
             $exclusionStrategy = $this->exclusionStrategyFactory->getStrategy($classMetadata->exclusionPolicy);
+
+            foreach ($classMetadata->preSerializeMethods as $method) {
+                $method->invoke($object);
+            }
+
             foreach ($classMetadata->propertyMetadata as $propertyMetadata) {
                 if ($exclusionStrategy->shouldSkipProperty($propertyMetadata)) {
                     continue;
@@ -117,6 +122,10 @@ class PropertyBasedNormalizer extends SerializerAwareNormalizer
                 $value = $this->serializer->denormalize($data[$serializedName], $type, $format);
                 $propertyMetadata->reflection->setValue($object, $value);
             }
+
+            foreach ($classMetadata->postDeserializeMethods as $method) {
+                $method->invoke($object);
+            }
         }
 
         return $object;

+ 48 - 0
Tests/Fixtures/ObjectWithLifecycleCallbacks.php

@@ -0,0 +1,48 @@
+<?php
+
+namespace JMS\SerializerBundle\Tests\Fixtures;
+
+use JMS\SerializerBundle\Annotation\Exclude;
+use JMS\SerializerBundle\Annotation\PreSerialize;
+use JMS\SerializerBundle\Annotation\PostDeserialize;
+use JMS\SerializerBundle\Annotation\Type;
+
+class ObjectWithLifecycleCallbacks
+{
+    /**
+     * @Exclude
+     */
+    private $firstname;
+
+    /**
+     * @Exclude
+     */
+    private $lastname;
+
+    /**
+     * @Type("string")
+     */
+    private $name;
+
+    public function __construct($firstname = 'Foo', $lastname = 'Bar')
+    {
+        $this->firstname = $firstname;
+        $this->lastname = $lastname;
+    }
+
+    /**
+     * @PreSerialize
+     */
+    private function prepareForSerialization()
+    {
+        $this->name = $this->firstname.' '.$this->lastname;
+    }
+
+    /**
+     * @PostDeserialize
+     */
+    private function afterDeserialization()
+    {
+        list($this->firstname, $this->lastname) = explode(' ', $this->name);
+    }
+}

+ 13 - 0
Tests/Serializer/SerializerTest.php

@@ -2,6 +2,7 @@
 
 namespace JMS\SerializerBundle\Tests\Serializer;
 
+use JMS\SerializerBundle\Tests\Fixtures\ObjectWithLifecycleCallbacks;
 use Doctrine\Common\Annotations\AnnotationReader;
 use Metadata\MetadataFactory;
 use JMS\SerializerBundle\Serializer\UnserializeInstanceCreator;
@@ -89,6 +90,18 @@ class SerializerTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($post, $post2);
     }
 
+    public function testLifecycleCallbacks()
+    {
+        $serializer = $this->getSerializer();
+
+        $object = new ObjectWithLifecycleCallbacks();
+        $this->assertEquals(json_encode(array(
+            'name' => 'Foo Bar',
+        )), $serialized = $serializer->serialize($object, 'json'));
+
+        $this->assertEquals($object, $serializer->deserialize($serialized, 'JMS\SerializerBundle\Tests\Fixtures\ObjectWithLifecycleCallbacks', 'json'));
+    }
+
     private function getSerializer($propertyNamingStrategy = null, $encoders = null, $customNormalizers = null)
     {
         if (null === $propertyNamingStrategy) {