8000 Merge branch 'form-submit-2.2' into form-submit-2.3 · symfony/symfony@5d60a4f · GitHub
[go: up one dir, main page]

8000
Skip to content

Commit 5d60a4f

Browse files
committed
Merge branch 'form-submit-2.2' into form-submit-2.3
Conflicts: src/Symfony/Component/Form/Form.php src/Symfony/Component/Form/Tests/AbstractFormTest.php src/Symfony/Component/Form/Tests/CompoundFormTest.php src/Symfony/Component/Form/Util/VirtualFormAwareIterator.php
2 parents 8e1cb3e + 00bc270 commit 5d60a4f

File tree

5 files changed

+227
-26
lines changed

5 files changed

+227
-26
lines changed

src/Symfony/Component/Form/Form.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,10 @@ public function submit($submittedData, $clearMissing = true)
536536
$submittedData = array();
537537
}
538538

539-
foreach ($this->children as $name => $child) {
539+
for (reset($this->children); false !== current($this->children); next($this->children)) {
540+
$child = current($this->children);
541+
$name = key($this->children);
542+
540543
if (array_key_exists($name, $submittedData) || $clearMissing) {
541544
$child->submit(isset($submittedData[$name]) ? $submittedData[$name] : null, $clearMissing);
542545
unset($submittedData[$name]);
@@ -762,7 +765,7 @@ public function getErrorsAsString($level = 0)
762765
/**
763766
* {@inheritdoc}
764767
*/
765-
public function all()
768+
public function &all()
766769
{
767770
return $this->children;
768771
}
@@ -833,7 +836,8 @@ public function add($child, $type = null, array $options = array())
833836
$child->setParent($this);
834837

835838
if (!$this->lockSetData && $this->defaultDataSet && !$this->config->getInheritData()) {
836-
$childrenIterator = new InheritDataAwareIterator(array($child));
839+
$children = array($child);
840+
$childrenIterator = new InheritDataAwareIterator($children);
837841
$childrenIterator = new \RecursiveIteratorIterator($childrenIterator);
838842
$this->config->getDataMapper()->mapDataToForms($viewData, $childrenIterator);
839843
}

src/Symfony/Component/Form/Tests/CompoundFormTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,34 @@ public function testSetDataMapsViewDataToChildren()
399399
$form->setData('foo');
400400
}
401401

402+
public function testSubmitSupportsDynamicAdditionAndRemovalOfChildren()
403+
{
404+
$child = $this->getMockForm('child');
405+
$childToBeRemoved = $this->getMockForm('removed');
406+
$childToBeAdded = $this->getMockForm('added');
407+
408+
$this->form->add($child);
409+
$this->form->add($childToBeRemoved);
410+
411+
$form = $this->form;
412+
413+
$child->expects($this->once())
414+
->method('submit')
415+
->will($this->returnCallback(function () use ($form, $childToBeAdded) {
416+
$form->remove('removed');
417+
$form->add($childToBeAdded);
418+
}));
419+
420+
$childToBeRemoved->expects($this->never())
421+
->method('submit');
422+
423+
$childToBeAdded->expects($this->once())
424+
->method('submit');
425+
426+
// pass NULL to all children
427+
$this->form->submit(array());
428+
}
429+
402430
public function testSubmitMapsSubmittedChildrenOntoExistingViewData()
403431
{
404432
$test = $this;
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Tests\Util;
13+
14+
use Symfony\Component\Form\Util\InheritDataAwareIterator;
15+
16+
/**
17+
* @author Bernhard Schussek <bschussek@gmail.com>
18+
*/
19+
class InheritDataAwareIteratorTest extends \PHPUnit_Framework_TestCase
20+
{
21+
public function testSupportDynamicModification()
22+
{
23+
$form = $this->getMockForm('form');
24+
$formToBeAdded = $this->getMockForm('added');
25+
$formToBeRemoved = $this->getMockForm('removed');
26+
27+
$forms = array('form' => $form, 'removed' => $formToBeRemoved);
28+
$iterator = new InheritDataAwareIterator($forms);
29+
30+
$iterator->rewind();
31+
$this->assertTrue($iterator->valid());
32+
$this->assertSame('form', $iterator->key());
33+
$this->assertSame($form, $iterator->current());
34+
35+
// dynamic modification
36+
unset($forms['removed']);
37+
$forms['added'] = $formToBeAdded;
38+
39+
// continue iteration
40+
$iterator->next();
41+
$this->assertTrue($iterator->valid());
42+
$this->assertSame('added', $iterator->key());
43+
$this->assertSame($formToBeAdded, $iterator->current());
44+
45+
// end of array
46+
$iterator->next();
47+
$this->assertFalse($iterator->valid());
48+
}
49+
50+
public function testSupportDynamicModificationInRecursiveCall()
51+
{
52+
$inheritingForm = $this->getMockForm('inheriting');
53+
$form = $this->getMockForm('form');
54+
$formToBeAdded = $this->getMockForm('added');
55+
$formToBeRemoved = $this->getMockForm('removed');
56+
57+
$inheritingForm->getConfig()->expects($this->any())
58+
->method('getInheritData')
59+
->will($this->returnValue(true));
60+
61+
$inheritingForm->add($form);
62+
$inheritingForm->add($formToBeRemoved);
63+
64+
$forms = array('inheriting' => $inheritingForm);
65+
$iterator = new InheritDataAwareIterator($forms);
66+
67+
$iterator->rewind();
68+
$this->assertTrue($iterator->valid());
69+
$this->assertSame('inheriting', $iterator->key());
70+
$this->assertSame($inheritingForm, $iterator->current());
71+
$this->assertTrue($iterator->hasChildren());
72+
73+
// enter nested iterator
74+
$nestedIterator = $iterator->getChildren();
75+
$this->assertSame('form', $nestedIterator->key());
76+
$this->assertSame($form, $nestedIterator->current());
77+
$this->assertFalse($nestedIterator->hasChildren());
78+
79+
// dynamic modification
80+
$inheritingForm->remove('removed');
81+
$inheritingForm->add($formToBeAdded);
82+
83+
// continue iteration - nested iterator discovers change in the form
84+
$nestedIterator->next();
85+
$this->assertTrue($nestedIterator->valid());
86+
$this->assertSame('added', $nestedIterator->key());
87+
$this->assertSame($formToBeAdded, $nestedIterator->current());
88+
89+
// end of array
90+
$nestedIterator->next();
91+
$this->assertFalse($nestedIterator->valid());
92+
}
93+
94+
/**
95+
* @param string $name
96+
*
97+
* @return \PHPUnit_Framework_MockObject_MockObject
98+
*/
99+
protected function getMockForm($name = 'name')
100+
{
101+
$config = $this->getMock('Symfony\Component\Form\FormConfigInterface');
102+
103+
$config->expects($this->any())
104+
->method('getName')
105+
->will($this->returnValue($name));
106+
$config->expects($this->any())
107+
->method('getCompound')
108+
->will($this->returnValue(true));
109+
$config->expects($this->any())
110+
->method('getDataMapper')
111+
->will($this->returnValue($this->getMock('Symfony\Component\Form\DataMapperInterface')));
112+
$config->expects($this->any())
113+
->method('getEventDispatcher')
114+
->will($this->returnValue($this->getMock('Symfony\Component\EventDispatcher\EventDispatcher')));
115+
116+
return $this->getMockBuilder('Symfony\Component\Form\Form')
117+
->setConstructorArgs(array($config))
118+
->disableArgumentCloning()
119+
->setMethods(array('getViewData'))
120+
->getMock();
121+
}
122+
}

src/Symfony/Component/Form/Util/InheritDataAwareIterator.php

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,17 @@
1212
namespace Symfony\Component\Form\Util;
1313

1414
/**
15-
* Iterator that returns only forms from a form tree that do not inherit their
16-
* parent data.
15+
* Iterator that traverses an array of forms.
1716
*
18-
* If the iterator encounters a form that inherits its parent data, it enters
19-
* the form and traverses its children as well.
17+
* Contrary to \ArrayIterator, this iterator recognizes changes in the original
18+
* array during iteration.
19+
*
20+
* You can wrap the iterator into a {@link \RecursiveIterator} in order to
21+
* enter any child form that inherits its parent's data and iterate the children
22+
* of that form as well.
2023
*
2124
* @author Bernhard Schussek <bschussek@gmail.com>
2225
*/
2326
class InheritDataAwareIterator extends VirtualFormAwareIterator
2427
{
25-
/**
26-
* Creates a new iterator.
27-
*
28-
* @param \Symfony\Component\Form\FormInterface[] $forms An array
29-
*/
30-
public function __construct(array $forms)
31-
{
32-
// Skip the deprecation error
33-
\ArrayIterator::__construct($forms);
34-
}
3528
}

src/Symfony/Component/Form/Util/VirtualFormAwareIterator.php

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,93 @@
1212
namespace Symfony\Component\Form\Util;
1313

1414
/**
15-
* Iterator that returns only forms from a form tree that do not inherit their
16-
* parent data.
15+
* Iterator that traverses an array of forms.
1716
*
18-
* If the iterator encounters a form that inherits its parent data, it enters
19-
* the form and traverses its children as well.
17+
* Contrary to \ArrayIterator, this iterator recognizes changes in the original
18+
* array during iteration.
19+
*
20+
* You can wrap the iterator into a {@link \RecursiveIterator} in order to
21+
* enter any child form that inherits its parent's data and iterate the children
22+
* of that form as well.
2023
*
2124
* @author Bernhard Schussek <bschussek@gmail.com>
2225
*
2326
* @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
2427
* {@link InheritDataAwareIterator} instead.
2528
*/
26-
class VirtualFormAwareIterator extends \ArrayIterator implements \RecursiveIterator
29+
class VirtualFormAwareIterator implements \RecursiveIterator
2730
{
31+
/**
32+
* @var \Symfony\Component\Form\FormInterface[]
33+
*/
34+
private $forms;
35+
2836
/**
2937
* Creates a new iterator.
3038
*
31-
* @param \Symfony\Component\Form\FormInterface[] $forms An array
39+
* @param \Symfony\Component\Form\FormInterface[] $forms An array of forms
3240
*/
33-
public function __construct(array $forms)
41+
public function __construct(array &$forms)
3442
{
3543
// Uncomment this as soon as the deprecation note should be shown
3644
// trigger_error('VirtualFormAwareIterator is deprecated since version 2.3 and will be removed in 3.0. Use InheritDataAwareIterator instead.', E_USER_DEPRECATED);
3745

38-
parent::__construct($forms);
46+
$this->forms = &$forms;
47+
}
48+
49+
/**
50+
*{@inheritdoc}
51+
*/
52+
public function current()
53+
{
54+
return current($this->forms);
3955
}
4056

57+
/**
58+
*{@inheritdoc}
59+
*/
60+
public function next()
61+
{
62+
next($this->forms);
63+
}
64+
65+
/**
66+
*{@inheritdoc}
67+
*/
68+
public function key()
69+
{
70+
return key($this->forms);
71+
}
72+
73+
/**
74+
*{@inheritdoc}
75+
*/
76+
public function valid()
77+
{
78+
return null !== key($this->forms);
79+
}
80+
81+
/**
82+
*{@inheritdoc}
83+
*/
84+
public function rewind()
85+
{
86+
reset($this->forms);
87+
}
88+
89+
/**
90+
*{@inheritdoc}
91+
*/
4192
public function getChildren()
4293
{
4394
return new static($this->current()->all());
4495
}
4596

97+
/**
98+
*{@inheritdoc}
99+
*/
46100
public function hasChildren()
47101
{
48-
return $this->current()->getConfig()->getInheritData();
102+
return (bool) $this->current()->getConfig()->getInheritData();
49103
}
50104
}

0 commit comments

Comments
 (0)
0