Browse Source

Support other annotations virtual properties

Aleksandr Klimenkov 13 years ago
parent
commit
896bfd9a3a

+ 1 - 1
Annotation/Exclude.php

@@ -20,7 +20,7 @@ namespace JMS\SerializerBundle\Annotation;
 
 /**
  * @Annotation
- * @Target({"PROPERTY", "CLASS"})
+ * @Target({"PROPERTY", "METHOD", "CLASS"})
  */
 final class Exclude
 {

+ 1 - 1
Annotation/Groups.php

@@ -22,7 +22,7 @@ use JMS\SerializerBundle\Exception\InvalidArgumentException;
 
 /**
  * @Annotation
- * @Target("PROPERTY")
+ * @Target({"PROPERTY","METHOD"})
  */
 final class Groups
 {

+ 1 - 1
Annotation/SerializedName.php

@@ -22,7 +22,7 @@ use JMS\SerializerBundle\Exception\RuntimeException;
 
 /**
  * @Annotation
- * @Target("PROPERTY")
+ * @Target({"PROPERTY","METHOD"})
  */
 final class SerializedName
 {

+ 1 - 1
Annotation/Virtual.php

@@ -8,7 +8,7 @@ namespace JMS\SerializerBundle\Annotation;
  *
  * @author Alexander Klimenkov <alx.devel@gmail.com>
  */
-final class Virtual
+final class VirtualProperty
 {
     /**
      * @Required

+ 1 - 1
Annotation/XmlAttribute.php

@@ -20,7 +20,7 @@ namespace JMS\SerializerBundle\Annotation;
 
 /**
  * @Annotation
- * @Target("PROPERTY")
+ * @Target({"PROPERTY", "METHOD"})
  */
 final class XmlAttribute
 {

+ 1 - 1
Annotation/XmlValue.php

@@ -20,7 +20,7 @@ namespace JMS\SerializerBundle\Annotation;
 
 /**
  * @Annotation
- * @Target("PROPERTY")
+ * @Target({"PROPERTY","METHOD"})
  */
 final class XmlValue
 {

+ 40 - 27
Metadata/Driver/AnnotationDriver.php

@@ -32,7 +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 JMS\SerializerBundle\Annotation\VirtualProperty;
 use Metadata\MethodMetadata;
 use Doctrine\Common\Annotations\Reader;
 use JMS\SerializerBundle\Annotation\Type;
@@ -64,6 +64,9 @@ class AnnotationDriver implements DriverInterface
         $classMetadata = new ClassMetadata($name = $class->getName());
         $classMetadata->fileResources[] = $class->getFilename();
 
+        $propertiesMetadata = array();
+        $propertiesAnnotations = array();
+
         $exclusionPolicy = 'NONE';
         $excludeAll = false;
         $classAccessType = PropertyMetadata::ACCESS_TYPE_PROPERTY;
@@ -81,17 +84,51 @@ class AnnotationDriver implements DriverInterface
             }
         }
 
+        foreach ($class->getMethods() as $method) {
+            if ($method->getDeclaringClass()->getName() !== $name) {
+                continue;
+            }
+
+            $methodAnnotations = $this->reader->getMethodAnnotations($method);
+
+            foreach ($methodAnnotations 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;
+                } else if ($annot instanceof PostSerialize) {
+                    $classMetadata->addPostSerializeMethod(new MethodMetadata($name, $method->getName()));
+                    continue 2;
+                } else if ($annot instanceof VirtualProperty) {
+                    $virtualPropertyMetadata = new VirtualPropertyMetadata($name, $annot->field);
+                    $virtualPropertyMetadata->getter = $method->getName();
+                    $propertiesMetadata[] = $virtualPropertyMetadata;
+                    $propertiesAnnotations[] = $methodAnnotations;
+                    continue 2;
+                }
+            }
+        }
+
         if (!$excludeAll) {
             foreach ($class->getProperties() as $property) {
                 if ($property->getDeclaringClass()->getName() !== $name) {
                     continue;
                 }
+                $propertiesMetadata[] = new PropertyMetadata($name, $property->getName());
+                $propertiesAnnotations[] = $this->reader->getPropertyAnnotations($property);
+            }
+
+            foreach ($propertiesMetadata as $propertyKey => $propertyMetadata) {
 
-                $propertyMetadata = new PropertyMetadata($name, $property->getName());
                 $isExclude = $isExpose = false;
                 $AccessType = $classAccessType;
                 $accessor = array(null, null);
-                foreach ($this->reader->getPropertyAnnotations($property) as $annot) {
+
+                $propertyAnnotations = $propertiesAnnotations[$propertyKey];
+
+                foreach ($propertyAnnotations as $annot) {
                     if ($annot instanceof Since) {
                         $propertyMetadata->sinceVersion = $annot->version;
                     } else if ($annot instanceof Until) {
@@ -139,30 +176,6 @@ class AnnotationDriver implements DriverInterface
             }
         }
 
-        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;
-                } else if ($annot instanceof PostSerialize) {
-                    $classMetadata->addPostSerializeMethod(new MethodMetadata($name, $method->getName()));
-                    continue 2;
-                } else if ($annot instanceof Virtual) {
-                    $virtualPropertyMetadata = new VirtualPropertyMetadata($name, $annot->field);
-                    $virtualPropertyMetadata->getter = $method->getName();
-                    $classMetadata->addPropertyMetadata( $virtualPropertyMetadata );
-                    continue 2;
-                }
-            }
-        }
-
         return $classMetadata;
     }
 }

+ 44 - 8
Metadata/VirtualPropertyMetadata.php

@@ -22,35 +22,71 @@ namespace JMS\SerializerBundle\Metadata;
 class VirtualPropertyMetadata extends PropertyMetadata
 {
 
-	public function __construct($class, $name)
+    public function __construct($class, $name)
     {
         $this->class = $class;
         $this->name = $name;
-		$this->readOnly = true;
+        $this->readOnly = true;
     }
 
     public function getValue($obj)
     {
         return $obj->{$this->getter}();
     }
-	
+
     public function setValue($obj, $value)
     {
         return false;
     }
 
+    public function setAccessor($type, $getter = null, $setter = null)
+    {
+        return false;
+    }
+
     public function serialize()
     {
         return serialize(array(
+            $this->sinceVersion,
+            $this->untilVersion,
+            $this->groups,
+            $this->serializedName,
+            $this->type,
+            $this->xmlCollection,
+            $this->xmlCollectionInline,
+            $this->xmlEntryName,
+            $this->xmlKeyAttribute,
+            $this->xmlAttribute,
+            $this->xmlValue,
+            $this->getter,
+            $this->setter,
+            $this->inline,
+            $this->readOnly,
             $this->class,
-            $this->name,
-			$this->getter
+            $this->name
         ));
     }
 
     public function unserialize($str)
     {
-        list($this->class, $this->name, $this->getter) = unserialize($str);
-		$this->readOnly = true;
-    }	
+        list(
+            $this->sinceVersion,
+            $this->untilVersion,
+            $this->groups,
+            $this->serializedName,
+            $this->type,
+            $this->xmlCollection,
+            $this->xmlCollectionInline,
+            $this->xmlEntryName,
+            $this->xmlKeyAttribute,
+            $this->xmlAttribute,
+            $this->xmlValue,
+            $this->getter,
+            $this->setter,
+            $this->inline,
+            $this->readOnly,
+            $this->class,
+            $this->name
+        ) = unserialize($str);
+    }
 }

+ 64 - 0
Tests/Fixtures/ObjectWithVirtualProperties.php

@@ -0,0 +1,64 @@
+<?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\AccessorOrder;
+use JMS\SerializerBundle\Annotation\Type;
+use JMS\SerializerBundle\Annotation\VirtualProperty;
+use JMS\SerializerBundle\Annotation\SerializedName;
+use JMS\SerializerBundle\Annotation\Exclude;
+
+/**
+ * @AccessorOrder("custom", custom = {"prop_name", "existField", "foo" }) 
+ */
+class ObjectWithVirtualProperties
+{
+
+    /**
+     * @Type("string")
+     */
+    protected $existField = 'value';
+   
+    /**
+     * 
+     * @VirtualProperty("foo")
+     */
+    public function getVirualValue()
+    {
+        return 'value';
+    }
+
+    /**
+     * @VirtualProperty("prop_name")
+     * @SerializedName("test")
+     */
+    public function getVirualSerializedValue()
+    {
+        return 'other-name';
+    }
+    
+    /**
+     * @VirtualProperty("excluded")
+     * @Exclude
+     */
+    public function getVirualExcudedValue()
+    {
+        return 'excluded';
+    }
+}

+ 22 - 11
Tests/Fixtures/ObjectWithVirtualProperty.php

@@ -18,22 +18,33 @@
 
 namespace JMS\SerializerBundle\Tests\Fixtures;
 
-use JMS\SerializerBundle\Annotation\Type;
-use JMS\SerializerBundle\Annotation\Virtual;
+use JMS\SerializerBundle\Annotation\Groups;
+use JMS\SerializerBundle\Annotation\XmlValue;
+use JMS\SerializerBundle\Annotation\XmlAttribute;
+use JMS\SerializerBundle\Annotation\VirtualProperty;
 
-class ObjectWithVirtualProperty
+class ObjectWithVirtualXmlProperties
 {
 
-	/**
-	 * @Type("string")
-	 */
-	protected $existField = 'value';
-    
-	/**
+    /**
      *
-     * @Virtual(field="foo")
+     * @VirtualProperty("foo")
+     * @Groups({"attributes"})
+     * @XmlAttribute
      */
-    public function getValue() {
+    public function getVirualXmlAttributeValue()
+    {
         return 'bar';
     }
+
+    /**
+     *
+     * @Groups({"values"})
+     * @VirtualProperty("xml-value")
+     * @XmlValue
+     */
+    public function getVirualXmlValue()
+    {
+        return 'xml-value';
+    }
 }

+ 3 - 3
Tests/Serializer/BaseSerializationTest.php

@@ -58,7 +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\Tests\Fixtures\ObjectWithVirtualProperties;
 use JMS\SerializerBundle\Serializer\XmlSerializationVisitor;
 use Doctrine\Common\Annotations\AnnotationReader;
 use JMS\SerializerBundle\Metadata\Driver\AnnotationDriver;
@@ -439,9 +439,9 @@ 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()));
+        $this->assertEquals($this->getContent('virtual_properties'), $this->serialize(new ObjectWithVirtualProperties()));
     }
 
     abstract protected function getContent($key);

+ 1 - 1
Tests/Serializer/JsonSerializationTest.php

@@ -64,7 +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'] = '{"exist_field":"value","foo":"bar"}';
+            $outputs['virtual_properties'] = '{"test":"other-name","exist_field":"value","foo":"value"}';
         }
 
         if (!isset($outputs[$key])) {

+ 13 - 0
Tests/Serializer/XmlSerializationTest.php

@@ -22,6 +22,7 @@ use JMS\SerializerBundle\Tests\Fixtures\InvalidUsageOfXmlValue;
 use JMS\SerializerBundle\Exception\InvalidArgumentException;
 use JMS\SerializerBundle\Annotation\Type;
 use JMS\SerializerBundle\Annotation\XmlValue;
+use JMS\SerializerBundle\Tests\Fixtures\ObjectWithVirtualXmlProperties;
 
 class XmlSerializationTest extends BaseSerializationTest
 {
@@ -50,6 +51,18 @@ class XmlSerializationTest extends BaseSerializationTest
         $this->assertEquals('', trim($entity->foo));
     }
 
+    public function testVirtualAttributes() {
+        $serializer = $this->getSerializer();
+        $serializer->setGroups(array('attributes'));
+        $this->assertEquals($this->getContent('virtual_attributes'), $serializer->serialize(new ObjectWithVirtualXmlProperties(),'xml'));
+    }
+
+    public function testVirtualValues() {
+        $serializer = $this->getSerializer();
+        $serializer->setGroups(array('values'));
+        $this->assertEquals($this->getContent('virtual_values'), $serializer->serialize(new ObjectWithVirtualXmlProperties(),'xml'));
+    }
+
     protected function getContent($key)
     {
         if (!file_exists($file = __DIR__.'/xml/'.$key.'.xml')) {

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

@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<result foo="bar"/>

+ 2 - 1
Tests/Serializer/xml/virtual_property.xml

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

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

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

+ 3 - 0
Tests/Serializer/yml/virtual_properties.yml

@@ -0,0 +1,3 @@
+test: other-name
+exist_field: value
+foo: value

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

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