浏览代码

If you mark property as Inline, then all sub properties will be serialized to the same level as the property is.

Miha Vrhovnik 13 年之前
父节点
当前提交
b8f6c64114

+ 27 - 0
Annotation/Inline.php

@@ -0,0 +1,27 @@
+<?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\Annotation;
+
+/**
+ * @Annotation
+ * @Target({"PROPERTY"})
+ */
+final class Inline
+{
+}

+ 3 - 0
Metadata/Driver/AnnotationDriver.php

@@ -43,6 +43,7 @@ use JMS\SerializerBundle\Annotation\SerializedName;
 use JMS\SerializerBundle\Annotation\Until;
 use JMS\SerializerBundle\Annotation\Until;
 use JMS\SerializerBundle\Annotation\Since;
 use JMS\SerializerBundle\Annotation\Since;
 use JMS\SerializerBundle\Annotation\ExclusionPolicy;
 use JMS\SerializerBundle\Annotation\ExclusionPolicy;
+use JMS\SerializerBundle\Annotation\Inline;
 use JMS\SerializerBundle\Metadata\ClassMetadata;
 use JMS\SerializerBundle\Metadata\ClassMetadata;
 use JMS\SerializerBundle\Metadata\PropertyMetadata;
 use JMS\SerializerBundle\Metadata\PropertyMetadata;
 use Metadata\Driver\DriverInterface;
 use Metadata\Driver\DriverInterface;
@@ -120,6 +121,8 @@ class AnnotationDriver implements DriverInterface
                         $accessor = array($annot->getter, $annot->setter);
                         $accessor = array($annot->getter, $annot->setter);
                     } else if ($annot instanceof Groups) {
                     } else if ($annot instanceof Groups) {
                         $propertyMetadata->setGroups($annot->names);
                         $propertyMetadata->setGroups($annot->names);
+                    } else if ($annot instanceof Inline) {
+                        $propertyMetadata->inline = true;
                     }
                     }
                 }
                 }
 
 

+ 4 - 0
Metadata/Driver/XmlDriver.php

@@ -143,6 +143,10 @@ class XmlDriver extends AbstractFileDriver
                         $getter ? (string) $getter : null,
                         $getter ? (string) $getter : null,
                         $setter ? (string) $setter : null
                         $setter ? (string) $setter : null
                     );
                     );
+
+                    if (null !== $inline = $pElem->attributes()->inline) {
+                        $pMetadata->inline = 'true' === strtolower($inline);
+                    }
                 }
                 }
 
 
                 if ((ExclusionPolicy::NONE === (string)$exclusionPolicy && !$isExclude)
                 if ((ExclusionPolicy::NONE === (string)$exclusionPolicy && !$isExclude)

+ 4 - 0
Metadata/Driver/YamlDriver.php

@@ -129,6 +129,10 @@ class YamlDriver extends AbstractFileDriver
                         isset($pConfig['access_type']) ? $pConfig['access_type'] : $classAccessType,
                         isset($pConfig['access_type']) ? $pConfig['access_type'] : $classAccessType,
                         isset($pConfig['accessor']) ? $pConfig['accessor'] : null
                         isset($pConfig['accessor']) ? $pConfig['accessor'] : null
                     );
                     );
+
+                    if (isset($pConfig['inline'])) {
+                        $pMetadata->inline = (Boolean) $pConfig['inline'];
+                    }
                 }
                 }
                 if ((ExclusionPolicy::NONE === $exclusionPolicy && !$isExclude)
                 if ((ExclusionPolicy::NONE === $exclusionPolicy && !$isExclude)
                 || (ExclusionPolicy::ALL === $exclusionPolicy && $isExpose)) {
                 || (ExclusionPolicy::ALL === $exclusionPolicy && $isExpose)) {

+ 3 - 0
Metadata/PropertyMetadata.php

@@ -37,6 +37,7 @@ class PropertyMetadata extends BasePropertyMetadata
     public $xmlValue = false;
     public $xmlValue = false;
     public $getter;
     public $getter;
     public $setter;
     public $setter;
+    public $inline = false;
 
 
     public function setAccessor($type, $getter = null, $setter = null)
     public function setAccessor($type, $getter = null, $setter = null)
     {
     {
@@ -81,6 +82,7 @@ class PropertyMetadata extends BasePropertyMetadata
             $this->xmlValue,
             $this->xmlValue,
             $this->getter,
             $this->getter,
             $this->setter,
             $this->setter,
+            $this->inline,
             parent::serialize(),
             parent::serialize(),
         ));
         ));
     }
     }
@@ -100,6 +102,7 @@ class PropertyMetadata extends BasePropertyMetadata
             $this->xmlValue,
             $this->xmlValue,
             $this->getter,
             $this->getter,
             $this->setter,
             $this->setter,
+            $this->inline,
             $parentStr
             $parentStr
         ) = unserialize($str);
         ) = unserialize($str);
 
 

+ 8 - 0
Resources/doc/index.rst

@@ -332,6 +332,12 @@ default the order is undefined, but you may change it to either "alphabetical",
         private $name;
         private $name;
     }
     }
 
 
+@Inline
+~~~~~~~~
+This annotation can be defined on a property to indicate that the property should
+be serialized inline. AccessorOrder doesn't work when using inline annotation.
+NOTE: If the property contains properties with the same name, properties in parent will be overriden.
+
 @PreSerialize
 @PreSerialize
 ~~~~~~~~~~~~~
 ~~~~~~~~~~~~~
 This annotation can be defined on a method which is supposed to be called before
 This annotation can be defined on a method which is supposed to be called before
@@ -573,6 +579,7 @@ XML Reference
                       access-type="public_method"
                       access-type="public_method"
                       accessor-getter="getSomeProperty"
                       accessor-getter="getSomeProperty"
                       accessor-setter="setSomeProperty"
                       accessor-setter="setSomeProperty"
+                      inline="true"
             >
             >
                 <!-- You can also specify the type as element which is necessary if
                 <!-- You can also specify the type as element which is necessary if
                      your type contains "<" or ">" characters. -->
                      your type contains "<" or ">" characters. -->
@@ -608,6 +615,7 @@ YAML Reference
                 since_version: 1.0
                 since_version: 1.0
                 until_version: 1.1
                 until_version: 1.1
                 xml_attribute: true
                 xml_attribute: true
+                inline: true
                 xml_list:
                 xml_list:
                     inline: true
                     inline: true
                     entry_name: foo
                     entry_name: foo

+ 5 - 1
Serializer/GenericSerializationVisitor.php

@@ -139,7 +139,11 @@ abstract class GenericSerializationVisitor extends AbstractSerializationVisitor
 
 
         $k = $this->namingStrategy->translateName($metadata);
         $k = $this->namingStrategy->translateName($metadata);
 
 
-        $this->data[$k] = $v;
+        if ($metadata->inline && is_array($v)) {
+            $this->data = array_merge($this->data, $v);
+        } else {
+            $this->data[$k] = $v;
+        }
     }
     }
 
 
     public function visitPropertyUsingCustomHandler(PropertyMetadata $metadata, $object)
     public function visitPropertyUsingCustomHandler(PropertyMetadata $metadata, $object)

+ 1 - 1
Serializer/XmlSerializationVisitor.php

@@ -183,7 +183,7 @@ class XmlSerializationVisitor extends AbstractSerializationVisitor
             return;
             return;
         }
         }
 
 
-        if ($addEnclosingElement = !$metadata->xmlCollection || !$metadata->xmlCollectionInline) {
+        if ($addEnclosingElement = (!$metadata->xmlCollection || !$metadata->xmlCollectionInline) && !$metadata->inline) {
             $element = $this->document->createElement($this->namingStrategy->translateName($metadata));
             $element = $this->document->createElement($this->namingStrategy->translateName($metadata));
             $this->setCurrentNode($element);
             $this->setCurrentNode($element);
         }
         }

+ 9 - 5
Serializer/YamlSerializationVisitor.php

@@ -156,10 +156,12 @@ class YamlSerializationVisitor extends AbstractSerializationVisitor
 
 
         $name = $this->namingStrategy->translateName($metadata);
         $name = $this->namingStrategy->translateName($metadata);
 
 
-        $this->writer
-            ->writeln(Inline::dump($name).':')
-            ->indent()
-        ;
+        if (!$metadata->inline) {
+            $this->writer
+                 ->writeln(Inline::dump($name).':')
+                 ->indent();
+        }
+
         $this->setCurrentMetadata($metadata);
         $this->setCurrentMetadata($metadata);
 
 
         $count = $this->writer->changeCount;
         $count = $this->writer->changeCount;
@@ -173,7 +175,9 @@ class YamlSerializationVisitor extends AbstractSerializationVisitor
             $this->writer->revert();
             $this->writer->revert();
         }
         }
 
 
-        $this->writer->outdent();
+        if (!$metadata->inline) {
+            $this->writer->outdent();
+        }
         $this->revertCurrentMetadata();
         $this->revertCurrentMetadata();
     }
     }
 
 

+ 19 - 0
Tests/Fixtures/InlineChild.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace JMS\SerializerBundle\Tests\Fixtures;
+
+use JMS\SerializerBundle\Annotation as Serializer;
+use JMS\SerializerBundle\Annotation\Type;
+
+class InlineChild
+{
+    /**
+     * @Type("string")
+     */
+    private $a = 'a';
+
+    /**
+     * @Type("string")
+     */
+    private $b = 'b';
+}

+ 31 - 0
Tests/Fixtures/InlineParent.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace JMS\SerializerBundle\Tests\Fixtures;
+
+use JMS\SerializerBundle\Annotation as Serializer;
+use JMS\SerializerBundle\Annotation\Type;
+
+/** @Serializer\AccessorOrder("alphabetical") */
+class InlineParent
+{
+    /**
+     * @Type("string")
+     */
+    private $c = 'c';
+
+    /**
+     * @Type("string")
+     */
+    private $d = 'd';
+
+    /**
+     * @Type("JMS\SerializerBundle\Tests\Fixtures\InlineChild")
+     * @Serializer\Inline
+     */
+    private $child;
+
+    public function __construct()
+    {
+        $this->child = new InlineChild();
+    }
+}

+ 14 - 0
Tests/Serializer/BaseSerializationTest.php

@@ -55,6 +55,7 @@ use JMS\SerializerBundle\Tests\Fixtures\Author;
 use JMS\SerializerBundle\Tests\Fixtures\BlogPost;
 use JMS\SerializerBundle\Tests\Fixtures\BlogPost;
 use JMS\SerializerBundle\Tests\Fixtures\ObjectWithLifecycleCallbacks;
 use JMS\SerializerBundle\Tests\Fixtures\ObjectWithLifecycleCallbacks;
 use JMS\SerializerBundle\Tests\Fixtures\CircularReferenceParent;
 use JMS\SerializerBundle\Tests\Fixtures\CircularReferenceParent;
+use JMS\SerializerBundle\Tests\Fixtures\InlineParent;
 use JMS\SerializerBundle\Serializer\XmlSerializationVisitor;
 use JMS\SerializerBundle\Serializer\XmlSerializationVisitor;
 use Doctrine\Common\Annotations\AnnotationReader;
 use Doctrine\Common\Annotations\AnnotationReader;
 use JMS\SerializerBundle\Metadata\Driver\AnnotationDriver;
 use JMS\SerializerBundle\Metadata\Driver\AnnotationDriver;
@@ -252,6 +253,19 @@ abstract class BaseSerializationTest extends \PHPUnit_Framework_TestCase
         }
         }
     }
     }
 
 
+    public function testInline()
+    {
+        $inline = new InlineParent();
+
+        $result = $this->serialize($inline);
+        $this->assertEquals($this->getContent('inline'), $result);
+
+        //no deserialization support
+        /*if ($this->hasDeserializer()) {
+            $this->assertEquals($inline, $this->deserialize($result, 'JMS\SerializerBundle\Tests\Serializer\InlineParent'));
+        }*/
+    }
+
     /**
     /**
      * @group test
      * @group test
      */
      */

+ 1 - 0
Tests/Serializer/JsonSerializationTest.php

@@ -59,6 +59,7 @@ class JsonSerializationTest extends BaseSerializationTest
             $outputs['mixed_access_types'] = '{"id":1,"name":"Johannes"}';
             $outputs['mixed_access_types'] = '{"id":1,"name":"Johannes"}';
             $outputs['accessor_order_child'] = '{"c":"c","d":"d","a":"a","b":"b"}';
             $outputs['accessor_order_child'] = '{"c":"c","d":"d","a":"a","b":"b"}';
             $outputs['accessor_order_parent'] = '{"a":"a","b":"b"}';
             $outputs['accessor_order_parent'] = '{"a":"a","b":"b"}';
+            $outputs['inline'] = '{"c":"c","a":"a","b":"b","d":"d"}';
         }
         }
 
 
         if (!isset($outputs[$key])) {
         if (!isset($outputs[$key])) {

+ 7 - 0
Tests/Serializer/xml/inline.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<result>
+  <c><![CDATA[c]]></c>
+  <a><![CDATA[a]]></a>
+  <b><![CDATA[b]]></b>
+  <d><![CDATA[d]]></d>
+</result>

+ 4 - 0
Tests/Serializer/yml/inline.yml

@@ -0,0 +1,4 @@
+c: c
+a: a
+b: b
+d: d