浏览代码

[Form] Moved creation of empty data to Form to clean up DataMapperInterface

Bernhard Schussek 14 年之前
父节点
当前提交
b180319371

+ 0 - 2
src/Symfony/Component/Form/DataMapper/DataMapperInterface.php

@@ -15,8 +15,6 @@ use Symfony\Component\Form\FormInterface;
 
 interface DataMapperInterface
 {
-    function createEmptyData();
-
     function mapDataToForms($data, array $forms);
 
     function mapDataToForm($data, FormInterface $form);

+ 1 - 23
src/Symfony/Component/Form/DataMapper/PropertyPathMapper.php

@@ -23,31 +23,9 @@ class PropertyPathMapper implements DataMapperInterface
      */
     private $dataClass;
 
-    /**
-     * Stores the constructor closure for creating new domain object instances
-     * @var \Closure
-     */
-    private $dataConstructor;
-
-    public function __construct($dataClass = null, $dataConstructor = null)
+    public function __construct($dataClass = null)
     {
         $this->dataClass = $dataClass;
-        $this->dataConstructor = $dataConstructor;
-    }
-
-    public function createEmptyData()
-    {
-        if ($this->dataConstructor) {
-            $constructor = $this->dataConstructor;
-
-            return $constructor();
-        } else if ($this->dataClass) {
-            $class = $this->dataClass;
-
-            return new $class();
-        }
-
-        return array();
     }
 
     public function mapDataToForms($data, array $forms)

+ 8 - 3
src/Symfony/Component/Form/Form.php

@@ -112,7 +112,7 @@ class Form implements \IteratorAggregate, FormInterface
         DataTransformerInterface $normTransformer = null,
         DataMapperInterface $dataMapper = null, array $validators = array(),
         $required = false, $readOnly = false, $errorBubbling = false,
-        array $attributes = array())
+        $emptyData = null, array $attributes = array())
     {
         foreach ($validators as $validator) {
             if (!$validator instanceof FormValidatorInterface) {
@@ -131,6 +131,7 @@ class Form implements \IteratorAggregate, FormInterface
         $this->readOnly = $readOnly;
         $this->attributes = $attributes;
         $this->errorBubbling = $errorBubbling;
+        $this->emptyData = $emptyData;
 
         $this->setData(null);
     }
@@ -256,8 +257,12 @@ class Form implements \IteratorAggregate, FormInterface
 
         // Fix data if empty
         if (!$this->clientTransformer) {
-            if (empty($appData) && !$this->normTransformer && $this->dataMapper) {
-                $appData = $this->dataMapper->createEmptyData();
+            if (null === $appData && !$this->normTransformer) {
+                $appData = $this->emptyData;
+
+                if ($appData instanceof \Closure) {
+                    $appData = $appData->__invoke();
+                }
             }
 
             // Treat data as strings unless a value transformer exists

+ 15 - 0
src/Symfony/Component/Form/FormBuilder.php

@@ -54,6 +54,8 @@ class FormBuilder
 
     private $errorBubbling = false;
 
+    private $emptyData = null;
+
     public function __construct(EventDispatcherInterface $dispatcher, $dataClass = null)
     {
         $this->dispatcher = $dispatcher;
@@ -273,6 +275,18 @@ class FormBuilder
         return $this->types;
     }
 
+    public function setEmptyData($emptyData)
+    {
+        $this->emptyData = $emptyData;
+
+        return $this;
+    }
+
+    public function getEmptyData()
+    {
+        return $this->emptyData;
+    }
+
     /**
      * Adds a new field to this group. A field must have a unique name within
      * the group. Otherwise the existing field is overwritten.
@@ -424,6 +438,7 @@ class FormBuilder
             $this->getRequired(),
             $this->getReadOnly(),
             $this->getErrorBubbling(),
+            $this->getEmptyData(),
             $this->getAttributes()
         );
 

+ 13 - 1
src/Symfony/Component/Form/Type/FieldType.php

@@ -52,6 +52,7 @@ class FieldType extends AbstractType
         $builder->setRequired($options['required'])
             ->setReadOnly($options['read_only'])
             ->setErrorBubbling($options['error_bubbling'])
+            ->setEmptyData($options['empty_data'])
             ->setAttribute('by_reference', $options['by_reference'])
             ->setAttribute('property_path', $options['property_path'])
             ->setAttribute('validation_groups', $options['validation_groups'])
@@ -94,7 +95,7 @@ class FieldType extends AbstractType
 
     public function getDefaultOptions(array $options)
     {
-        return array(
+        $defaultOptions = array(
             'data' => null,
             'data_class' => null,
             'trim' => true,
@@ -107,6 +108,17 @@ class FieldType extends AbstractType
             'error_bubbling' => false,
             'error_mapping' => array(),
         );
+
+        if (!empty($options['data_class'])) {
+            $class = $options['data_class'];
+            $defaultOptions['empty_data'] = function () use ($class) {
+                return new $class();
+            };
+        } else {
+            $defaultOptions['empty_data'] = null;
+        }
+
+        return $defaultOptions;
     }
 
     public function createBuilder(array $options)

+ 8 - 6
src/Symfony/Component/Form/Type/FormType.php

@@ -23,10 +23,7 @@ class FormType extends AbstractType
     public function buildForm(FormBuilder $builder, array $options)
     {
         $builder->setAttribute('virtual', $options['virtual'])
-            ->setDataMapper(new PropertyPathMapper(
-                $options['data_class'],
-                $options['data_constructor']
-            ));
+            ->setDataMapper(new PropertyPathMapper($options['data_class']));
 
         if ($options['csrf_protection']) {
             $csrfOptions = array('page_id' => $options['csrf_page_id']);
@@ -55,8 +52,7 @@ class FormType extends AbstractType
 
     public function getDefaultOptions(array $options)
     {
-        return array(
-            'data_constructor' => null,
+        $defaultOptions = array(
             'csrf_protection' => true,
             'csrf_field_name' => '_token',
             'csrf_provider' => null,
@@ -66,6 +62,12 @@ class FormType extends AbstractType
             // end up as global errors in the root form
             'error_bubbling' => true,
         );
+
+        if (empty($options['data_class'])) {
+            $defaultOptions['empty_data'] = array();
+        }
+
+        return $defaultOptions;
     }
 
     public function getParent(array $options)

+ 25 - 14
tests/Symfony/Tests/Component/Form/Type/FormTypeTest.php

@@ -82,7 +82,7 @@ class TestSetDataBeforeConfigureForm extends Form
     }
 }
 
-class FormTest extends TestCase
+class FormTypeTest extends TestCase
 {
     protected $form;
 
@@ -381,35 +381,46 @@ class FormTest extends TestCase
         $form = $this->factory->create('form', 'author', array(
             'data_class' => 'Symfony\Tests\Component\Form\Fixtures\Author',
         ));
+
         $form->setData(null);
 
         $this->assertEquals(new Author(), $form->getData());
     }
 
-    public function testSetDataToNullUsesDataConstructorOption()
+    /*
+     * We need something to write the field values into
+     */
+    public function testSetDataToNullStoresArrayIfNoClassAvailable()
+    {
+        $form = $this->factory->create('form', 'author');
+
+        $form->setData(null);
+
+        $this->assertSame(array(), $form->getData());
+    }
+
+    public function testSetDataToNullUsesEmptyData()
     {
         $author = new Author();
         $form = $this->factory->create('form', 'author', array(
-            'data_constructor' => function () use ($author) {
-        return $author;
-            }
-            ));
+            'empty_data' => $author,
+        ));
 
-            $form->setData(null);
+        $form->setData(null);
 
-            $this->assertSame($author, $form->getData());
+        $this->assertSame($author, $form->getData());
     }
 
-    /*
-     * We need something to write the field values into
-     */
-    public function testSetDataToNullCreatesArrayIfNoDataClassOrConstructor()
+    public function testSetDataToNullAcceptsClosureEmptyData()
     {
         $author = new Author();
-        $form = $this->factory->create('form', 'author');
+        $form = $this->factory->create('form', 'author', array(
+            'empty_data' => function () use ($author) { return $author; },
+        ));
+
         $form->setData(null);
 
-        $this->assertSame(array(), $form->getData());
+        $this->assertSame($author, $form->getData());
     }
 
     public function testSubmitUpdatesTransformedDataFromAllFields()