Przeglądaj źródła

[Form] Fixed reference handling in forms. Sometimes data wasn't written into the domain object, resulting in failed validation.

Bernhard Schussek 14 lat temu
rodzic
commit
7dbc09ed8b

+ 11 - 5
src/Symfony/Component/Form/Form.php

@@ -911,12 +911,18 @@ class Form extends Field implements \IteratorAggregate, FormInterface
      */
     public function writeProperty(&$objectOrArray)
     {
-        $data = $this->getData();
+        $isReference = false;
 
-        // Don't update parent if data is a composite type (object or array)
-        // and "by_reference" option is true, because then we expect that
-        // we are working with a reference to the parent's data
-        if (!is_object($data) || !is_object($objectOrArray) || !$this->getOption('by_reference')) {
+        // If the data is identical to the value in $objectOrArray, we are
+        // dealing with a reference
+        if ($this->getPropertyPath() !== null) {
+            $isReference = $this->getData() === $this->getPropertyPath()->getValue($objectOrArray);
+        }
+
+        // Don't write into $objectOrArray if $objectOrArray is an object,
+        // $isReference is true (see above) and the option "by_reference" is
+        // true as well
+        if (!is_object($objectOrArray) || !$isReference || !$this->getOption('by_reference')) {
             parent::writeProperty($objectOrArray);
         }
     }

+ 26 - 0
tests/Symfony/Tests/Component/Form/FormTest.php

@@ -1246,6 +1246,32 @@ class FormTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals('Foo', $author->getReference()->firstName);
     }
 
+    public function testSubformCallsSettersIfTheObjectChanged()
+    {
+        // no reference
+        $author = new FormTest_AuthorWithoutRefSetter(null);
+        $newReference = new Author();
+
+        $form = new Form('author', array('validator' => $this->createMockValidator()));
+        $form->setData($author);
+        $refForm = new Form('referenceCopy');
+        $refForm->add(new TestField('firstName'));
+        $form->add($refForm);
+
+        $refForm->setData($newReference); // new author object
+
+        $form->bind($this->createPostRequest(array(
+            'author' => array(
+                // referenceCopy has a getter that returns a copy
+                'referenceCopy' => array(
+                    'firstName' => 'Foo',
+                )
+            )
+        )));
+
+        $this->assertEquals('Foo', $author->getReferenceCopy()->firstName);
+    }
+
     public function testSubformCallsSettersIfByReferenceIsFalse()
     {
         $author = new FormTest_AuthorWithoutRefSetter(new Author());