Browse Source

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

Miha Vrhovnik 13 years ago
parent
commit
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\Since;
 use JMS\SerializerBundle\Annotation\ExclusionPolicy;
+use JMS\SerializerBundle\Annotation\Inline;
 use JMS\SerializerBundle\Metadata\ClassMetadata;
 use JMS\SerializerBundle\Metadata\PropertyMetadata;
 use Metadata\Driver\DriverInterface;
@@ -120,6 +121,8 @@ class AnnotationDriver implements DriverInterface
                         $accessor = array($annot->getter, $annot->setter);
                     } else if ($annot instanceof Groups) {
                         $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,
                         $setter ? (string) $setter : null
                     );
+
+                    if (null !== $inline = $pElem->attributes()->inline) {
+                        $pMetadata->inline = 'true' === strtolower($inline);
+                    }
                 }
 
                 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['accessor']) ? $pConfig['accessor'] : null
                     );
+
+                    if (isset($pConfig['inline'])) {
+                        $pMetadata->inline = (Boolean) $pConfig['inline'];
+                    }
                 }
                 if ((ExclusionPolicy::NONE === $exclusionPolicy && !$isExclude)
                 || (ExclusionPolicy::ALL === $exclusionPolicy && $isExpose)) {

+ 3 - 0
Metadata/PropertyMetadata.php

@@ -37,6 +37,7 @@ class PropertyMetadata extends BasePropertyMetadata
     public $xmlValue = false;
     public $getter;
     public $setter;
+    public $inline = false;
 
     public function setAccessor($type, $getter = null, $setter = null)
     {
@@ -81,6 +82,7 @@ class PropertyMetadata extends BasePropertyMetadata
             $this->xmlValue,
             $this->getter,
             $this->setter,
+            $this->inline,
             parent::serialize(),
         ));
     }
@@ -100,6 +102,7 @@ class PropertyMetadata extends BasePropertyMetadata
             $this->xmlValue,
             $this->getter,
             $this->setter,
+            $this->inline,
             $parentStr
         ) = 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;
     }
 
+@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
 ~~~~~~~~~~~~~
 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"
                       accessor-getter="getSomeProperty"
                       accessor-setter="setSomeProperty"
+                      inline="true"
             >
                 <!-- You can also specify the type as element which is necessary if
                      your type contains "<" or ">" characters. -->
@@ -608,6 +615,7 @@ YAML Reference
                 since_version: 1.0
                 until_version: 1.1
                 xml_attribute: true
+                inline: true
                 xml_list:
                     inline: true
                     entry_name: foo

+ 5 - 1
Serializer/GenericSerializationVisitor.php

@@ -139,7 +139,11 @@ abstract class GenericSerializationVisitor extends AbstractSerializationVisitor
 
         $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)

+ 1 - 1
Serializer/XmlSerializationVisitor.php

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

+ 9 - 5
Serializer/YamlSerializationVisitor.php

@@ -156,10 +156,12 @@ class YamlSerializationVisitor extends AbstractSerializationVisitor
 
         $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);
 
         $count = $this->writer->changeCount;
@@ -173,7 +175,9 @@ class YamlSerializationVisitor extends AbstractSerializationVisitor
             $this->writer->revert();
         }
 
-        $this->writer->outdent();
+        if (!$metadata->inline) {
+            $this->writer->outdent();
+        }
         $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\ObjectWithLifecycleCallbacks;
 use JMS\SerializerBundle\Tests\Fixtures\CircularReferenceParent;
+use JMS\SerializerBundle\Tests\Fixtures\InlineParent;
 use JMS\SerializerBundle\Serializer\XmlSerializationVisitor;
 use Doctrine\Common\Annotations\AnnotationReader;
 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
      */

+ 1 - 0
Tests/Serializer/JsonSerializationTest.php

@@ -59,6 +59,7 @@ class JsonSerializationTest extends BaseSerializationTest
             $outputs['mixed_access_types'] = '{"id":1,"name":"Johannes"}';
             $outputs['accessor_order_child'] = '{"c":"c","d":"d","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])) {

+ 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