From a81d0cb920bd914f89f8c6df9c4adfa2539b1bd3 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Mon, 30 Jul 2012 16:28:39 +0200 Subject: [PATCH 1/6] Start with repalcing serialization using JMS --- Annotation/FormType.php | 56 ++++++++++++++++++ Serializer/JMS/FormMetadataDriver.php | 59 +++++++++++++++++++ Tests/Serializer/Fixture/User.php | 2 + .../Serializer/JmsFormMetadataDriverTest.php | 21 +++++++ Tests/TestCase.php | 2 +- Tests/bootstrap.php | 5 +- 6 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 Annotation/FormType.php create mode 100644 Serializer/JMS/FormMetadataDriver.php create mode 100644 Tests/Serializer/JmsFormMetadataDriverTest.php diff --git a/Annotation/FormType.php b/Annotation/FormType.php new file mode 100644 index 0000000..06f0dfb --- /dev/null +++ b/Annotation/FormType.php @@ -0,0 +1,56 @@ +type = $values['value']; + } + if (isset($values['group'])) { + $this->group = $values['group']; + } + } + + public function getType() + { + return $this->type; + } + + public function getGroup() + { + return $this->group; + } +} + diff --git a/Serializer/JMS/FormMetadataDriver.php b/Serializer/JMS/FormMetadataDriver.php new file mode 100644 index 0000000..6d6d8b6 --- /dev/null +++ b/Serializer/JMS/FormMetadataDriver.php @@ -0,0 +1,59 @@ +reader = $reader; + $this->formFactory = $formFactory; + } + + public function loadMetadataForClass(\ReflectionClass $class) + { + $classMetadata = new ClassMetadata($name = $class->getName()); + + foreach ($this->reader->getClassAnnotations($class) as $annot) { + if ($annot instanceof FormType) { + $type = $annot->getType(); + $group = $annot->getGroup(); + + if (class_exists($type)) { + $type = new $type; + } + + $form = $this->formFactory->create($type, null, array()); + $options = $form->getConfig()->getOptions(); + + $classMetadata->xmlRootName = $options['serialize_xml_name']; + + $propertiesMetadata = array(); + foreach ($form->getChildren() as $children) { + $childOptions = $children->getConfig()->getOptions(); + + $property = $class->getProperty($children->getName()); + $propertyMetadata = new PropertyMetadata($name, $property->getName()); + + var_dump($propertyMetadata); + } + } + } + + return $classMetadata; + } +} + diff --git a/Tests/Serializer/Fixture/User.php b/Tests/Serializer/Fixture/User.php index 8016731..2cd1c7d 100644 --- a/Tests/Serializer/Fixture/User.php +++ b/Tests/Serializer/Fixture/User.php @@ -3,9 +3,11 @@ namespace SimpleThings\FormSerializerBundle\Tests\Serializer\Fixture; use JMS\SerializerBundle\Annotation as JMS; +use SimpleThings\FormSerializerBundle\Annotation\FormType; /** * @JMS\ExclusionPolicy("none") + * @FormType("SimpleThings\FormSerializerBundle\Tests\Serializer\Fixture\UserType") */ class User { diff --git a/Tests/Serializer/JmsFormMetadataDriverTest.php b/Tests/Serializer/JmsFormMetadataDriverTest.php new file mode 100644 index 0000000..3758770 --- /dev/null +++ b/Tests/Serializer/JmsFormMetadataDriverTest.php @@ -0,0 +1,21 @@ +createFormFactory()); + + $reflClass = new \ReflectionClass('SimpleThings\FormSerializerBundle\Tests\Serializer\Fixture\User'); + $metadata = $driver->loadMetadataForClass($reflClass); + + var_dump($metadata); + } +} + diff --git a/Tests/TestCase.php b/Tests/TestCase.php index 3b1cbf2..fd9bc45 100644 --- a/Tests/TestCase.php +++ b/Tests/TestCase.php @@ -175,7 +175,7 @@ protected function formatJson($json) } default: $new_json .= $char; - break; + break; } } diff --git a/Tests/bootstrap.php b/Tests/bootstrap.php index b88a643..efcf863 100644 --- a/Tests/bootstrap.php +++ b/Tests/bootstrap.php @@ -9,7 +9,7 @@ ); } -spl_autoload_register(function($class) { +$bundleLoader = (function($class) { if (0 === strpos($class, 'SimpleThings\\FormSerializerBundle\\')) { $path = __DIR__.'/../'.implode('/', array_slice(explode('\\', $class), 2)).'.php'; if (!stream_resolve_include_path($path)) { @@ -19,5 +19,8 @@ return true; } }); +spl_autoload_register($bundleLoader); Doctrine\Common\Annotations\AnnotationRegistry::registerLoader(array($loader, 'loadClass')); +Doctrine\Common\Annotations\AnnotationRegistry::registerLoader($bundleLoader); + From fb2ec07414c242f298efdb0b86115bce4372791f Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Mon, 30 Jul 2012 18:00:51 +0200 Subject: [PATCH 2/6] Implement some basic converting of form type into JMS Serializer --- Annotation/FormType.php | 13 ---- Serializer/JMS/FormMetadataDriver.php | 63 ++++++++++++++++++- Tests/Serializer/Fixture/Address.php | 2 + .../Serializer/JmsFormMetadataDriverTest.php | 28 +++++++++ Tests/TestCase.php | 25 +++++--- composer.lock | 4 +- 6 files changed, 108 insertions(+), 27 deletions(-) diff --git a/Annotation/FormType.php b/Annotation/FormType.php index 06f0dfb..a553fd3 100644 --- a/Annotation/FormType.php +++ b/Annotation/FormType.php @@ -28,29 +28,16 @@ class FormType */ private $type; - /** - * @var string - */ - private $group = 'default'; - public function __construct(array $values) { if (isset($values['value'])) { $this->type = $values['value']; } - if (isset($values['group'])) { - $this->group = $values['group']; - } } public function getType() { return $this->type; } - - public function getGroup() - { - return $this->group; - } } diff --git a/Serializer/JMS/FormMetadataDriver.php b/Serializer/JMS/FormMetadataDriver.php index 6d6d8b6..8508766 100644 --- a/Serializer/JMS/FormMetadataDriver.php +++ b/Serializer/JMS/FormMetadataDriver.php @@ -30,7 +30,6 @@ public function loadMetadataForClass(\ReflectionClass $class) foreach ($this->reader->getClassAnnotations($class) as $annot) { if ($annot instanceof FormType) { $type = $annot->getType(); - $group = $annot->getGroup(); if (class_exists($type)) { $type = new $type; @@ -44,16 +43,74 @@ public function loadMetadataForClass(\ReflectionClass $class) $propertiesMetadata = array(); foreach ($form->getChildren() as $children) { $childOptions = $children->getConfig()->getOptions(); + $type = $children->getConfig()->getType(); $property = $class->getProperty($children->getName()); $propertyMetadata = new PropertyMetadata($name, $property->getName()); - - var_dump($propertyMetadata); + #$propertyMetadata->setAccessor('public_method', null, null); + + if ( !empty($childOptions['serialize_name'])) { + $propertyMetadata->serializedName = $childOptions['serialize_name']; + } + + if ($type->getName() == "collection") { + $propertyMetadata->xmlCollection = true; + $propertyMetadata->xmlCollectionInline = $childOptions['serialize_xml_inline']; + + if ( ! empty($childOptions['serialize_xml_name'])) { + $propertyMetadata->xmlEntryName = $childOptions['serialize_xml_name']; + } + + $subForm = $this->formFactory->create($childOptions['type']); + + $propertyMetadata->type = sprintf('array<%s>', $this->translateType($subForm)); + } else if ($type->getName() == "choice") { + $propertyMetadata->type = $childOptions['multiple'] ? "array" : "string"; + } else if ($type->getName() == "entity") { + $propertyMetadata->type = $childOptions['multiple'] ? "array" : "string"; + } else { + $propertyMetadata->type = $this->translateType($children); + } + + if ($childOptions['serialize_xml_attribute']) { + $propertyMetadata->xmlAttribute = true; + } else if ($childOptions['serialize_xml_value']) { + $propertyMetadata->xmlValue = true; + } + + if ($childOptions['disabled']) { + $propertyMetadata->readOnly = true; + } + + #var_dump($propertyMetadata); + $classMetadata->addPropertyMetadata($propertyMetadata); } } } return $classMetadata; } + + private function translateType($form) + { + $options = $form->getConfig()->getOptions(); + if ($options['data_class']) { + return $options['data_class']; + } + + switch ($form->getConfig()->getType()->getName()) { + case 'date': + case 'datetime': + case 'time': + case 'birthday'; + return 'DateTime'; + case 'number': + return 'float'; + case 'checkbox': + return 'boolean'; + default: + return 'string'; + } + } } diff --git a/Tests/Serializer/Fixture/Address.php b/Tests/Serializer/Fixture/Address.php index 22078e8..92f0ca8 100644 --- a/Tests/Serializer/Fixture/Address.php +++ b/Tests/Serializer/Fixture/Address.php @@ -2,9 +2,11 @@ namespace SimpleThings\FormSerializerBundle\Tests\Serializer\Fixture; use JMS\SerializerBundle\Annotation as JMS; +use SimpleThings\FormSerializerBundle\Annotation\FormType; /** * @JMS\ExclusionPolicy("none") + * @FormType("SimpleThings\FormSerializerBundle\Tests\Serializer\Fixture\AddressType") */ class Address { diff --git a/Tests/Serializer/JmsFormMetadataDriverTest.php b/Tests/Serializer/JmsFormMetadataDriverTest.php index 3758770..1028968 100644 --- a/Tests/Serializer/JmsFormMetadataDriverTest.php +++ b/Tests/Serializer/JmsFormMetadataDriverTest.php @@ -5,6 +5,11 @@ use SimpleThings\FormSerializerBundle\Tests\TestCase; use SimpleThings\FormSerializerBundle\Serializer\JMS\FormMetadataDriver; +use SimpleThings\FormSerializerBundle\Tests\Serializer\Fixture\User; +use SimpleThings\FormSerializerBundle\Tests\Serializer\Fixture\Address; +use SimpleThings\FormSerializerBundle\Tests\Serializer\Fixture\UserType; +use SimpleThings\FormSerializerBundle\Tests\Serializer\Fixture\AddressType; + class JmsFormMetadataDriverTest extends TestCase { public function testLoadMetadata() @@ -17,5 +22,28 @@ public function testLoadMetadata() var_dump($metadata); } + + public function testSerialize() + { + $serializer = $this->createJmsSerializer(true); + + $address = new Address(); + $address->street = "Somestreet 1"; + $address->zipCode = 12345; + $address->city = "Bonn"; + + $user = new User(); + $user->username = "beberlei"; + $user->email = "kontakt@beberlei.de"; + $user->birthday = new \DateTime("1984-03-18"); + $user->gender = 'male'; + $user->interests = array('sport', 'reading'); + $user->country = "DE"; + $user->address = $address; + + $xml = $serializer->serialize($user, 'xml'); + + var_dump($xml); + } } diff --git a/Tests/TestCase.php b/Tests/TestCase.php index fd9bc45..3365870 100644 --- a/Tests/TestCase.php +++ b/Tests/TestCase.php @@ -59,7 +59,7 @@ public function createFormSerializer(SerializerOptions $options = null) return $formSerializer; } - public function createJmsSerializer() + public function createJmsSerializer($forms = false) { $namingStrategy = new SerializedNameAnnotationStrategy(new CamelCaseNamingStrategy()); $objectConstructor = new UnserializeObjectConstructor(); @@ -83,19 +83,26 @@ public function createJmsSerializer() 'xml' => new XmlDeserializationVisitor($namingStrategy, $customDeserializationHandlers, $objectConstructor), ); - $factory = $this->createJmsMetadataFactory(); + $factory = $this->createJmsMetadataFactory($forms); return new JMSSerializer($factory, $serializationVisitors, $deserializationVisitors); } - public function createJmsMetadataFactory() + public function createJmsMetadataFactory($forms = false) { $fileLocator = new \Metadata\Driver\FileLocator(array()); - $driver = new \Metadata\Driver\DriverChain(array( - new \JMS\SerializerBundle\Metadata\Driver\YamlDriver($fileLocator), - new \JMS\SerializerBundle\Metadata\Driver\XmlDriver($fileLocator), - new \JMS\SerializerBundle\Metadata\Driver\PhpDriver($fileLocator), - new \JMS\SerializerBundle\Metadata\Driver\AnnotationDriver(new \Doctrine\Common\Annotations\AnnotationReader()) - )); + if ($forms) { + $driver = new \SimpleThings\FormSerializerBundle\Serializer\JMS\FormMetadataDriver( + new \Doctrine\Common\Annotations\AnnotationReader(), + $this->createFormFactory() + ); + } else { + $driver = new \Metadata\Driver\DriverChain(array( + new \JMS\SerializerBundle\Metadata\Driver\YamlDriver($fileLocator), + new \JMS\SerializerBundle\Metadata\Driver\XmlDriver($fileLocator), + new \JMS\SerializerBundle\Metadata\Driver\PhpDriver($fileLocator), + new \JMS\SerializerBundle\Metadata\Driver\AnnotationDriver(new \Doctrine\Common\Annotations\AnnotationReader()) + )); + } return new MetadataFactory($driver); } diff --git a/composer.lock b/composer.lock index 48b5760..730fa16 100644 --- a/composer.lock +++ b/composer.lock @@ -14,8 +14,8 @@ { "package": "symfony/symfony", "version": "dev-master", - "source-reference": "cbd03ec4c66567cf2bf4ea9e0e3315a522b4eeb3", - "commit-date": "1343635713" + "source-reference": "a172a812960d060cd5dd13e4dcf3b2bc4043a18f", + "commit-date": "1343639879" }, { "package": "twig/twig", From 036e78f692e4000abcf7be44dbc152b268ba5431 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Mon, 30 Jul 2012 18:19:50 +0200 Subject: [PATCH 3/6] Cleanup JMS Form Metadata Driver test --- .../Serializer/JmsFormMetadataDriverTest.php | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/Tests/Serializer/JmsFormMetadataDriverTest.php b/Tests/Serializer/JmsFormMetadataDriverTest.php index 1028968..d48342a 100644 --- a/Tests/Serializer/JmsFormMetadataDriverTest.php +++ b/Tests/Serializer/JmsFormMetadataDriverTest.php @@ -20,7 +20,8 @@ public function testLoadMetadata() $reflClass = new \ReflectionClass('SimpleThings\FormSerializerBundle\Tests\Serializer\Fixture\User'); $metadata = $driver->loadMetadataForClass($reflClass); - var_dump($metadata); + $this->assertInstanceOf('JMS\SerializerBundle\Metadata\ClassMetadata', $metadata); + $this->assertEquals(array('username', 'email', 'birthday', 'country', 'address', 'addresses'), array_keys($metadata->propertyMetadata)); } public function testSerialize() @@ -40,10 +41,33 @@ public function testSerialize() $user->interests = array('sport', 'reading'); $user->country = "DE"; $user->address = $address; + $user->addresses = array($address, $address); $xml = $serializer->serialize($user, 'xml'); - var_dump($xml); + $this->assertEquals(<< + + + + 1984-03-18T00:00:00+0100 + +
+ +
+
+ + + +XML + , $xml); + + $json = $serializer->serialize($user, 'json'); + + $this->assertEquals(<< Date: Mon, 30 Jul 2012 18:23:36 +0200 Subject: [PATCH 4/6] Add JMS + Form Metadata to performance test --- Tests/Serializer/PerformanceTest.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Tests/Serializer/PerformanceTest.php b/Tests/Serializer/PerformanceTest.php index 63b7f9e..8d1398f 100644 --- a/Tests/Serializer/PerformanceTest.php +++ b/Tests/Serializer/PerformanceTest.php @@ -37,16 +37,21 @@ public function testSerializeList20Elements() $start = microtime(true); $xml = $formSerializer->serializeList($list, new UserType(), 'xml', 'users'); - echo number_format(microtime(true) - $start, 4) . "\n"; + echo "Form Serializer: " . number_format(microtime(true) - $start, 4) . "\n"; #echo $this->formatXml($xml); $jmsSerializer = $this->createJmsSerializer(); $start = microtime(true); $xml = $jmsSerializer->serialize($list, 'xml'); - echo number_format(microtime(true) - $start, 4) . "\n"; + echo "JMS Annotations: " . number_format(microtime(true) - $start, 4) . "\n"; #echo $this->formatXml($xml); + + $jmsSerializer = $this->createJmsSerializer(true); + $start = microtime(true); + $xml = $jmsSerializer->serialize($list, 'xml'); + echo "JMS with Form Metadata: " . number_format(microtime(true) - $start, 4) . "\n"; } } From 59f1d85c628911a4ddf7359244ad3173d5beddf6 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Mon, 30 Jul 2012 18:45:36 +0200 Subject: [PATCH 5/6] Fix some cs and other issues --- Serializer/JMS/FormMetadataDriver.php | 7 ++++--- Tests/Serializer/PerformanceTest.php | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Serializer/JMS/FormMetadataDriver.php b/Serializer/JMS/FormMetadataDriver.php index 8508766..2f87897 100644 --- a/Serializer/JMS/FormMetadataDriver.php +++ b/Serializer/JMS/FormMetadataDriver.php @@ -49,7 +49,7 @@ public function loadMetadataForClass(\ReflectionClass $class) $propertyMetadata = new PropertyMetadata($name, $property->getName()); #$propertyMetadata->setAccessor('public_method', null, null); - if ( !empty($childOptions['serialize_name'])) { + if (!empty($childOptions['serialize_name'])) { $propertyMetadata->serializedName = $childOptions['serialize_name']; } @@ -82,7 +82,6 @@ public function loadMetadataForClass(\ReflectionClass $class) $propertyMetadata->readOnly = true; } - #var_dump($propertyMetadata); $classMetadata->addPropertyMetadata($propertyMetadata); } } @@ -105,9 +104,11 @@ private function translateType($form) case 'birthday'; return 'DateTime'; case 'number': - return 'float'; + return 'double'; case 'checkbox': return 'boolean'; + case 'integer'; + return 'integer'; default: return 'string'; } diff --git a/Tests/Serializer/PerformanceTest.php b/Tests/Serializer/PerformanceTest.php index 8d1398f..0f57bc6 100644 --- a/Tests/Serializer/PerformanceTest.php +++ b/Tests/Serializer/PerformanceTest.php @@ -42,6 +42,7 @@ public function testSerializeList20Elements() #echo $this->formatXml($xml); $jmsSerializer = $this->createJmsSerializer(); + $xml = $jmsSerializer->serialize($list, 'xml'); $start = microtime(true); $xml = $jmsSerializer->serialize($list, 'xml'); echo "JMS Annotations: " . number_format(microtime(true) - $start, 4) . "\n"; @@ -49,6 +50,7 @@ public function testSerializeList20Elements() #echo $this->formatXml($xml); $jmsSerializer = $this->createJmsSerializer(true); + $xml = $jmsSerializer->serialize($list, 'xml'); $start = microtime(true); $xml = $jmsSerializer->serialize($list, 'xml'); echo "JMS with Form Metadata: " . number_format(microtime(true) - $start, 4) . "\n"; From 53d0c717db5dab4ec5d1fd4708f028c9053cbcf9 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Mon, 30 Jul 2012 18:55:33 +0200 Subject: [PATCH 6/6] Increase performance in FormBuilder case --- Serializer/FormSerializer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Serializer/FormSerializer.php b/Serializer/FormSerializer.php index 9da3dfd..f2f7d43 100644 --- a/Serializer/FormSerializer.php +++ b/Serializer/FormSerializer.php @@ -71,8 +71,8 @@ public function serialize($object, $typeBuilder, $format) if (($typeBuilder instanceof FormTypeInterface) || is_string($typeBuilder)) { $form = $this->factory->create($typeBuilder, $object); } else if ($typeBuilder instanceof FormBuilderInterface) { + $typeBuilder->setData($object); $form = $typeBuilder->getForm(); - $form->setData($object); } else if ($typeBuilder instanceof FormInterface) { $form = $typeBuilder; if ( ! $form->isBound()) {