Browse Source

Add @Virtual annotation

Aleksandr Klimenkov 13 years ago
parent
commit
38912e0d47

+ 18 - 0
Annotation/Virtual.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace JMS\SerializerBundle\Annotation;
+
+/**
+ * @Annotation
+ * @Target("METHOD")
+ *
+ * @author Alexander Klimenkov <alx.devel@gmail.com>
+ */
+final class Virtual
+{
+    /**
+     * @Required
+     * @var string
+     */
+    public $field;
+}

+ 30 - 22
Metadata/ClassMetadata.php

@@ -38,6 +38,7 @@ class ClassMetadata extends MergeableClassMetadata
     public $preSerializeMethods = array();
     public $postSerializeMethods = array();
     public $postDeserializeMethods = array();
+    public $virtualPropertyMethods = array();
     public $xmlRootName;
     public $accessorOrder;
     public $customOrder;
@@ -86,6 +87,11 @@ class ClassMetadata extends MergeableClassMetadata
         $this->postDeserializeMethods[] = $method;
     }
 
+    public function addVirtualPropertyMethod(MethodMetadata $method, $field)
+    {
+        $this->virtualPropertyMethods[$field] = $method;
+    }
+	
     public function merge(MergeableInterface $object)
     {
         if (!$object instanceof ClassMetadata) {
@@ -114,6 +120,7 @@ class ClassMetadata extends MergeableClassMetadata
             $this->preSerializeMethods,
             $this->postSerializeMethods,
             $this->postDeserializeMethods,
+            $this->virtualPropertyMethods,
             $this->xmlRootName,
             $this->accessorOrder,
             $this->customOrder,
@@ -127,6 +134,7 @@ class ClassMetadata extends MergeableClassMetadata
             $this->preSerializeMethods,
             $this->postSerializeMethods,
             $this->postDeserializeMethods,
+            $this->virtualPropertyMethods,
             $this->xmlRootName,
             $this->accessorOrder,
             $this->customOrder,
@@ -138,32 +146,32 @@ class ClassMetadata extends MergeableClassMetadata
 
     private function sortProperties()
     {
-        switch ($this->accessorOrder) {
-            case self::ACCESSOR_ORDER_ALPHABETICAL:
-                ksort($this->propertyMetadata);
-                break;
-
-            case self::ACCESSOR_ORDER_CUSTOM:
+        switch ($this->accessorOrder) {
+            case self::ACCESSOR_ORDER_ALPHABETICAL:
+                ksort($this->propertyMetadata);
+                break;
+
+            case self::ACCESSOR_ORDER_CUSTOM:
                 $order = $this->customOrder;
                 uksort($this->propertyMetadata, function($a, $b) use ($order) {
-                    $existsA = isset($order[$a]);
-                    $existsB = isset($order[$b]);
-
-                    if (!$existsA && !$existsB) {
-                        return 0;
-                    }
-
-                    if (!$existsA) {
-                        return 1;
-                    }
-
-                    if (!$existsB) {
-                        return -1;
+                    $existsA = isset($order[$a]);
+                    $existsB = isset($order[$b]);
+
+                    if (!$existsA && !$existsB) {
+                        return 0;
                     }
 
-                    return $order[$a] < $order[$b] ? -1 : 1;
+                    if (!$existsA) {
+                        return 1;
+                    }
+
+                    if (!$existsB) {
+                        return -1;
+                    }
+
+                    return $order[$a] < $order[$b] ? -1 : 1;
                 });
-                break;
-        }
+                break;
+        }
     }
 }

+ 4 - 0
Metadata/Driver/AnnotationDriver.php

@@ -32,6 +32,7 @@ use JMS\SerializerBundle\Annotation\XmlValue;
 use JMS\SerializerBundle\Annotation\PostSerialize;
 use JMS\SerializerBundle\Annotation\PostDeserialize;
 use JMS\SerializerBundle\Annotation\PreSerialize;
+use JMS\SerializerBundle\Annotation\Virtual;
 use Metadata\MethodMetadata;
 use Doctrine\Common\Annotations\Reader;
 use JMS\SerializerBundle\Annotation\Type;
@@ -152,6 +153,9 @@ class AnnotationDriver implements DriverInterface
                 } else if ($annot instanceof PostSerialize) {
                     $classMetadata->addPostSerializeMethod(new MethodMetadata($name, $method->getName()));
                     continue 2;
+                } else if ($annot instanceof Virtual) {
+                    $classMetadata->addVirtualPropertyMethod( new MethodMetadata($name, $method->getName()), $annot->field);
+                    continue 2;
                 }
             }
         }

+ 4 - 0
Serializer/GenericSerializationVisitor.php

@@ -113,6 +113,10 @@ abstract class GenericSerializationVisitor extends AbstractSerializationVisitor
 
         $this->dataStack->push($this->data);
         $this->data = array();
+		
+        foreach( $metadata->virtualPropertyMethods as $field => $method ) {
+            $this->data[$field] = $method->invoke($data);
+        }
     }
 
     public function endVisitingObject(ClassMetadata $metadata, $data, $type)

+ 6 - 0
Serializer/XmlSerializationVisitor.php

@@ -143,6 +143,12 @@ class XmlSerializationVisitor extends AbstractSerializationVisitor
         }
 
         $this->hasValue = false;
+
+        foreach( $metadata->virtualPropertyMethods as $field => $method ) {
+            $element = $this->getDocument()->createElement($field);
+            $element->appendChild($this->getDocument()->createCDATASection( (string) $method->invoke($data)));
+            $this->getCurrentNode()->appendChild($element);
+        }
     }
 
     public function visitProperty(PropertyMetadata $metadata, $object)

+ 4 - 0
Serializer/YamlSerializationVisitor.php

@@ -143,6 +143,10 @@ class YamlSerializationVisitor extends AbstractSerializationVisitor
 
     public function startVisitingObject(ClassMetadata $metadata, $data, $type)
     {
+        foreach( $metadata->virtualPropertyMethods as $field => $method ) {
+            $this->writer
+                ->writeln(Inline::dump($field).': ' . $method->invoke($data));
+        }
     }
 
     public function visitProperty(PropertyMetadata $metadata, $data)

+ 36 - 0
Tests/Fixtures/ObjectWithVirtualProperty.php

@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace JMS\SerializerBundle\Tests\Fixtures;
+
+use JMS\SerializerBundle\Annotation\SerializedName;
+use JMS\SerializerBundle\Annotation\Virtual;
+
+class ObjectWithVirtualProperty
+{
+
+	protected $existField = 'value';
+    
+	/**
+     *
+     * @Virtual(field="foo")
+     */
+    public function getValue() {
+        return 'bar';
+    }
+}

+ 5 - 0
Tests/Serializer/BaseSerializationTest.php

@@ -58,6 +58,7 @@ use JMS\SerializerBundle\Tests\Fixtures\ObjectWithLifecycleCallbacks;
 use JMS\SerializerBundle\Tests\Fixtures\CircularReferenceParent;
 use JMS\SerializerBundle\Tests\Fixtures\InlineParent;
 use JMS\SerializerBundle\Tests\Fixtures\GroupsObject;
+use JMS\SerializerBundle\Tests\Fixtures\ObjectWithVirtualProperty;
 use JMS\SerializerBundle\Serializer\XmlSerializationVisitor;
 use Doctrine\Common\Annotations\AnnotationReader;
 use JMS\SerializerBundle\Metadata\Driver\AnnotationDriver;
@@ -438,6 +439,10 @@ abstract class BaseSerializationTest extends \PHPUnit_Framework_TestCase
         $serializer->setGroups(array());
         $this->assertEquals($this->getContent('groups_all'), $serializer->serialize($groupsObject, $this->getFormat()));
     }
+	
+    public function testVirtualProperty() {
+        $this->assertEquals($this->getContent('virtual_property'), $this->serialize(new ObjectWithVirtualProperty()));
+    }
 
     abstract protected function getContent($key);
     abstract protected function getFormat();

+ 1 - 0
Tests/Serializer/JsonSerializationTest.php

@@ -64,6 +64,7 @@ class JsonSerializationTest extends BaseSerializationTest
             $outputs['groups_all'] = '{"foo":"foo","foobar":"foobar","bar":"bar","none":"none"}';
             $outputs['groups_foo'] = '{"foo":"foo","foobar":"foobar"}';
             $outputs['groups_foobar'] = '{"foo":"foo","foobar":"foobar","bar":"bar"}';
+            $outputs['virtual_property'] = '{"foo":"bar","exist_field":"value"}';
         }
 
         if (!isset($outputs[$key])) {

+ 5 - 0
Tests/Serializer/xml/virtual_property.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<result>
+  <foo><![CDATA[bar]]></foo>
+  <exist_field><![CDATA[value]]></exist_field>
+</result>

+ 2 - 0
Tests/Serializer/yml/virtual_property.yml

@@ -0,0 +1,2 @@
+foo: bar
+exist_field: value