Selaa lähdekoodia

merged branch marcw/issue-1746 (PR #1758)

Commits
-------

2e024f8 [Form] CollectionType now checks for data_class parameter instead of only class.
0327beb [Form] Added ObjectFactoryListener. Fixes #1746.

Discussion
----------

[Form] Added ObjectFactoryListener. Fixes #1746.

---------------------------------------------------------------------------

by marcw at 2011/07/21 09:32:17 -0700

This patch also fixes a validation issue because it was impossible for the validator to validate an array.

---------------------------------------------------------------------------

by stof at 2011/07/21 09:47:46 -0700

yeah, using the data_class of the prototype would be great
Fabien Potencier 14 vuotta sitten
vanhempi
commit
49dda530e0

+ 66 - 0
src/Symfony/Component/Form/Extension/Core/EventListener/ObjectFactoryListener.php

@@ -0,0 +1,66 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Form\Extension\Core\EventListener;
+
+use Symfony\Component\Form\Event\FilterDataEvent;
+use Symfony\Component\Form\FormEvents;
+use Symfony\Component\Form\Util\PropertyPath;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Based on scalar values, this class instanciates object and hydrate them.
+ *
+ * @author Marc Weistroff <marc.weistroff@sensio.com>
+ */
+class ObjectFactoryListener implements EventSubscriberInterface
+{
+    private $class;
+
+    /**
+     * __construct
+     *
+     * @param string $class FQCN class
+     */
+    public function __construct($class)
+    {
+        $this->class = $class;
+    }
+
+    static public function getSubscribedEvents()
+    {
+        return array(
+            FormEvents::BIND_NORM_DATA => 'onBindNormData',
+        );
+    }
+
+    public function onBindNormData(FilterDataEvent $event)
+    {
+        $data = $event->getData();
+
+        foreach ($data as $k => $array) {
+            if (!is_array($array)) {
+                continue;
+            }
+
+            $object = new $this->class();
+            foreach ($array as $key => $value) {
+                $path = new PropertyPath($key);
+                $path->setValue($object, $value);
+            }
+
+            $data[$k] = $object;
+        }
+
+        $event->setData($data);
+    }
+}
+

+ 9 - 0
src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php

@@ -16,6 +16,7 @@ use Symfony\Component\Form\FormBuilder;
 use Symfony\Component\Form\FormView;
 use Symfony\Component\Form\FormInterface;
 use Symfony\Component\Form\Extension\Core\EventListener\ResizeFormListener;
+use Symfony\Component\Form\Extension\Core\EventListener\ObjectFactoryListener;
 
 class CollectionType extends AbstractType
 {
@@ -29,6 +30,13 @@ class CollectionType extends AbstractType
             $builder->setAttribute('prototype', $prototype);
         }
 
+        $dataClass = isset($options['options']['data_class']) ? $options['options']['data_class'] : null;
+        if ($dataClass || $options['class']) {
+            $class = $dataClass ? $dataClass : $options['class'];
+            $listener = new ObjectFactoryListener($class);
+            $builder->addEventSubscriber($listener);
+        }
+
         $listener = new ResizeFormListener(
             $builder->getFormFactory(),
             $options['type'],
@@ -70,6 +78,7 @@ class CollectionType extends AbstractType
             'prototype'     => true,
             'type'          => 'text',
             'options'       => array(),
+            'class'         => null,
         );
     }
 

+ 37 - 0
tests/Symfony/Tests/Component/Form/Extension/Core/Type/CollectionTypeTest.php

@@ -13,6 +13,7 @@ namespace Symfony\Tests\Component\Form\Extension\Core\Type;
 
 use Symfony\Component\Form\CollectionForm;
 use Symfony\Component\Form\Form;
+use Symfony\Tests\Component\Form\Fixtures\AuthorType;
 
 class CollectionFormTest extends TypeTestCase
 {
@@ -141,4 +142,40 @@ class CollectionFormTest extends TypeTestCase
 
         $this->assertTrue($form->createView()->get('multipart'));
     }
+
+    public function testObjectsAreCreated()
+    {
+        $form = $this->factory
+            ->create('collection', null, array(
+                'type'      => new AuthorType(),
+                'allow_add' => true,
+                'class'     => 'Symfony\Tests\Component\Form\Fixtures\Author',
+            ))
+        ;
+
+        $data = array(array('last_name' => 'Foo'), array('last_name' => 'Bar'));
+        $form->bind($data);
+        $bound = $form->getData();
+        $this->assertEquals(2, count($bound));
+        $this->assertInstanceOf('Symfony\Tests\Component\Form\Fixtures\Author', $bound[0]);
+        $this->assertInstanceOf('Symfony\Tests\Component\Form\Fixtures\Author', $bound[1]);
+        $this->assertEquals('Foo', $bound[0]->getLastName());
+        $this->assertEquals('Bar', $bound[1]->getLastName());
+    }
+
+    public function testObjectsAreCreatedWithDataClassOption()
+    {
+        $form = $this->factory
+            ->create('collection', null, array(
+                'type'      => new AuthorType(),
+                'allow_add' => true,
+                'options'   => array('data_class' => 'Symfony\Tests\Component\Form\Fixtures\Author')
+            ))
+        ;
+
+        $data = array(array('last_name' => 'Foo'), array('last_name' => 'Bar'));
+        $form->bind($data);
+        $bound = $form->getData();
+        $this->assertInstanceOf('Symfony\Tests\Component\Form\Fixtures\Author', $bound[0]);
+    }
 }

+ 24 - 0
tests/Symfony/Tests/Component/Form/Fixtures/AuthorType.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace Symfony\Tests\Component\Form\Fixtures;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormBuilder;
+use Symfony\Component\Form\FormFactoryInterface;
+use Symfony\Component\EventDispatcher\EventDispatcher;
+
+class AuthorType extends AbstractType
+{
+    public function buildForm(FormBuilder $builder, array $options)
+    {
+        $builder
+            ->add('last_name', 'text')
+        ;
+    }
+
+    public function getName()
+    {
+        return 'author';
+    }
+}
+