4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Form\Tests
;
14 use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler
;
15 use Symfony\Component\Form\FormError
;
16 use Symfony\Component\HttpFoundation\Request
;
17 use Symfony\Component\HttpFoundation\File\UploadedFile
;
18 use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer
;
20 class CompoundFormTest
extends AbstractFormTest
22 public function testValidIfAllChildrenAreValid()
24 $this->form
->add($this->getValidForm('firstName'));
25 $this->form
->add($this->getValidForm('lastName'));
27 $this->form
->submit(array(
28 'firstName' => 'Bernhard',
29 'lastName' => 'Schussek',
32 $this->assertTrue($this->form
->isValid());
35 public function testInvalidIfChildIsInvalid()
37 $this->form
->add($this->getValidForm('firstName'));
38 $this->form
->add($this->getInvalidForm('lastName'));
40 $this->form
->submit(array(
41 'firstName' => 'Bernhard',
42 'lastName' => 'Schussek',
45 $this->assertFalse($this->form
->isValid());
48 public function testSubmitForwardsNullIfValueIsMissing()
50 $child = $this->getMockForm('firstName');
52 $this->form
->add($child);
54 $child->expects($this->once())
56 ->with($this->equalTo(null));
58 $this->form
->submit(array());
61 public function testSubmitDoesNotForwardNullIfNotClearMissing()
63 $child = $this->getMockForm('firstName');
65 $this->form
->add($child);
67 $child->expects($this->never())
70 $this->form
->submit(array(), false);
73 public function testClearMissingFlagIsForwarded()
75 $child = $this->getMockForm('firstName');
77 $this->form
->add($child);
79 $child->expects($this->once())
81 ->with($this->equalTo('foo'), false);
83 $this->form
->submit(array('firstName' => 'foo'), false);
86 public function testCloneChildren()
88 $child = $this->getBuilder('child')->getForm();
89 $this->form
->add($child);
91 $clone = clone $this->form
;
93 $this->assertNotSame($this->form
, $clone);
94 $this->assertNotSame($child, $clone['child']);
97 public function testNotEmptyIfChildNotEmpty()
99 $child = $this->getMockForm();
100 $child->expects($this->once())
102 ->will($this->returnValue(false));
104 $this->form
->setData(null);
105 $this->form
->add($child);
107 $this->assertFalse($this->form
->isEmpty());
110 public function testValidIfSubmittedAndDisabledWithChildren()
112 $this->factory
->expects($this->once())
113 ->method('createNamedBuilder')
114 ->with('name', 'text', null, array())
115 ->will($this->returnValue($this->getBuilder('name')));
117 $form = $this->getBuilder('person')
120 ->setDataMapper($this->getDataMapper())
121 ->add('name', 'text')
123 $form->submit(array('name' => 'Jacques Doe'));
125 $this->assertTrue($form->isValid());
128 public function testNotValidIfChildNotValid()
130 $child = $this->getMockForm();
131 $child->expects($this->once())
133 ->will($this->returnValue(false));
135 $this->form
->add($child);
136 $this->form
->submit(array());
138 $this->assertFalse($this->form
->isValid());
141 public function testAdd()
143 $child = $this->getBuilder('foo')->getForm();
144 $this->form
->add($child);
146 $this->assertTrue($this->form
->has('foo'));
147 $this->assertSame($this->form
, $child->getParent());
148 $this->assertSame(array('foo' => $child), $this->form
->all());
151 public function testAddUsingNameAndType()
153 $child = $this->getBuilder('foo')->getForm();
155 $this->factory
->expects($this->once())
156 ->method('createNamed')
157 ->with('foo', 'text', null, array(
159 'auto_initialize' => false,
161 ->will($this->returnValue($child));
163 $this->form
->add('foo', 'text', array('bar' => 'baz'));
165 $this->assertTrue($this->form
->has('foo'));
166 $this->assertSame($this->form
, $child->getParent());
167 $this->assertSame(array('foo' => $child), $this->form
->all());
170 public function testAddUsingIntegerNameAndType()
172 $child = $this->getBuilder(0)->getForm();
174 $this->factory
->expects($this->once())
175 ->method('createNamed')
176 ->with('0', 'text', null, array(
178 'auto_initialize' => false,
180 ->will($this->returnValue($child));
182 // in order to make casting unnecessary
183 $this->form
->add(0, 'text', array('bar' => 'baz'));
185 $this->assertTrue($this->form
->has(0));
186 $this->assertSame($this->form
, $child->getParent());
187 $this->assertSame(array(0 => $child), $this->form
->all());
190 public function testAddUsingNameButNoType()
192 $this->form
= $this->getBuilder('name', null, '\stdClass')
194 ->setDataMapper($this->getDataMapper())
197 $child = $this->getBuilder('foo')->getForm();
199 $this->factory
->expects($this->once())
200 ->method('createForProperty')
201 ->with('\stdClass', 'foo')
202 ->will($this->returnValue($child));
204 $this->form
->add('foo');
206 $this->assertTrue($this->form
->has('foo'));
207 $this->assertSame($this->form
, $child->getParent());
208 $this->assertSame(array('foo' => $child), $this->form
->all());
211 public function testAddUsingNameButNoTypeAndOptions()
213 $this->form
= $this->getBuilder('name', null, '\stdClass')
215 ->setDataMapper($this->getDataMapper())
218 $child = $this->getBuilder('foo')->getForm();
220 $this->factory
->expects($this->once())
221 ->method('createForProperty')
222 ->with('\stdClass', 'foo', null, array(
224 'auto_initialize' => false,
226 ->will($this->returnValue($child));
228 $this->form
->add('foo', null, array('bar' => 'baz'));
230 $this->assertTrue($this->form
->has('foo'));
231 $this->assertSame($this->form
, $child->getParent());
232 $this->assertSame(array('foo' => $child), $this->form
->all());
236 * @expectedException \Symfony\Component\Form\Exception\AlreadySubmittedException
238 public function testAddThrowsExceptionIfAlreadySubmitted()
240 $this->form
->submit(array());
241 $this->form
->add($this->getBuilder('foo')->getForm());
244 public function testRemove()
246 $child = $this->getBuilder('foo')->getForm();
247 $this->form
->add($child);
248 $this->form
->remove('foo');
250 $this->assertNull($child->getParent());
251 $this->assertCount(0, $this->form
);
255 * @expectedException \Symfony\Component\Form\Exception\AlreadySubmittedException
257 public function testRemoveThrowsExceptionIfAlreadySubmitted()
259 $this->form
->add($this->getBuilder('foo')->setCompound(false)->getForm());
260 $this->form
->submit(array('foo' => 'bar'));
261 $this->form
->remove('foo');
264 public function testRemoveIgnoresUnknownName()
266 $this->form
->remove('notexisting');
269 public function testArrayAccess()
271 $child = $this->getBuilder('foo')->getForm();
273 $this->form
[] = $child;
275 $this->assertTrue(isset($this->form
['foo']));
276 $this->assertSame($child, $this->form
['foo']);
278 unset($this->form
['foo']);
280 $this->assertFalse(isset($this->form
['foo']));
283 public function testCountable()
285 $this->form
->add($this->getBuilder('foo')->getForm());
286 $this->form
->add($this->getBuilder('bar')->getForm());
288 $this->assertCount(2, $this->form
);
291 public function testIterator()
293 $this->form
->add($this->getBuilder('foo')->getForm());
294 $this->form
->add($this->getBuilder('bar')->getForm());
296 $this->assertSame($this->form
->all(), iterator_to_array($this->form
));
299 public function testAddMapsViewDataToFormIfInitialized()
302 $mapper = $this->getDataMapper();
303 $form = $this->getBuilder()
305 ->setDataMapper($mapper)
306 ->addViewTransformer(new FixedDataTransformer(array(
313 $child = $this->getBuilder()->getForm();
314 $mapper->expects($this->once())
315 ->method('mapDataToForms')
316 ->with('bar', $this->isInstanceOf('\RecursiveIteratorIterator'))
317 ->will($this->returnCallback(function ($data, \RecursiveIteratorIterator
$iterator) use ($child, $test) {
318 $test->assertInstanceOf('Symfony\Component\Form\Util\InheritDataAwareIterator', $iterator->getInnerIterator());
319 $test->assertSame(array($child), iterator_to_array($iterator));
326 public function testAddDoesNotMapViewDataToFormIfNotInitialized()
328 $mapper = $this->getDataMapper();
329 $form = $this->getBuilder()
331 ->setDataMapper($mapper)
334 $child = $this->getBuilder()->getForm();
335 $mapper->expects($this->never())
336 ->method('mapDataToForms');
341 public function testAddDoesNotMapViewDataToFormIfInheritData()
343 $mapper = $this->getDataMapper();
344 $form = $this->getBuilder()
346 ->setDataMapper($mapper)
347 ->setInheritData(true)
350 $child = $this->getBuilder()->getForm();
351 $mapper->expects($this->never())
352 ->method('mapDataToForms');
358 public function testSetDataMapsViewDataToChildren()
361 $mapper = $this->getDataMapper();
362 $form = $this->getBuilder()
364 ->setDataMapper($mapper)
365 ->addViewTransformer(new FixedDataTransformer(array(
371 $form->add($child1 = $this->getBuilder('firstName')->getForm());
372 $form->add($child2 = $this->getBuilder('lastName')->getForm());
374 $mapper->expects($this->once())
375 ->method('mapDataToForms')
376 ->with('bar', $this->isInstanceOf('\RecursiveIteratorIterator'))
377 ->will($this->returnCallback(function ($data, \RecursiveIteratorIterator
$iterator) use ($child1, $child2, $test) {
378 $test->assertInstanceOf('Symfony\Component\Form\Util\InheritDataAwareIterator', $iterator->getInnerIterator());
379 $test->assertSame(array('firstName' => $child1, 'lastName' => $child2), iterator_to_array($iterator));
382 $form->setData('foo');
385 public function testSubmitMapsSubmittedChildrenOntoExistingViewData()
388 $mapper = $this->getDataMapper();
389 $form = $this->getBuilder()
391 ->setDataMapper($mapper)
392 ->addViewTransformer(new FixedDataTransformer(array(
399 $form->add($child1 = $this->getBuilder('firstName')->setCompound(false)->getForm());
400 $form->add($child2 = $this->getBuilder('lastName')->setCompound(false)->getForm());
402 $mapper->expects($this->once())
403 ->method('mapFormsToData')
404 ->with($this->isInstanceOf('\RecursiveIteratorIterator'), 'bar')
405 ->will($this->returnCallback(function (\RecursiveIteratorIterator
$iterator) use ($child1, $child2, $test) {
406 $test->assertInstanceOf('Symfony\Component\Form\Util\InheritDataAwareIterator', $iterator->getInnerIterator());
407 $test->assertSame(array('firstName' => $child1, 'lastName' => $child2), iterator_to_array($iterator));
408 $test->assertEquals('Bernhard', $child1->getData());
409 $test->assertEquals('Schussek', $child2->getData());
413 'firstName' => 'Bernhard',
414 'lastName' => 'Schussek',
418 public function testMapFormsToDataIsNotInvokedIfInheritData()
420 $mapper = $this->getDataMapper();
421 $form = $this->getBuilder()
423 ->setDataMapper($mapper)
424 ->setInheritData(true)
425 ->addViewTransformer(new FixedDataTransformer(array(
431 $form->add($child1 = $this->getBuilder('firstName')->setCompound(false)->getForm());
432 $form->add($child2 = $this->getBuilder('lastName')->setCompound(false)->getForm());
434 $mapper->expects($this->never())
435 ->method('mapFormsToData');
438 'firstName' => 'Bernhard',
439 'lastName' => 'Schussek',
444 * https://github.com/symfony/symfony/issues/4480
446 public function testSubmitRestoresViewDataIfCompoundAndEmpty()
448 $mapper = $this->getDataMapper();
449 $object = new \
stdClass();
450 $form = $this->getBuilder('name', null, 'stdClass')
452 ->setDataMapper($mapper)
456 $form->submit(array());
458 $this->assertSame($object, $form->getData());
461 public function testSubmitMapsSubmittedChildrenOntoEmptyData()
464 $mapper = $this->getDataMapper();
465 $object = new \
stdClass();
466 $form = $this->getBuilder()
468 ->setDataMapper($mapper)
469 ->setEmptyData($object)
473 $form->add($child = $this->getBuilder('name')->setCompound(false)->getForm());
475 $mapper->expects($this->once())
476 ->method('mapFormsToData')
477 ->with($this->isInstanceOf('\RecursiveIteratorIterator'), $object)
478 ->will($this->returnCallback(function (\RecursiveIteratorIterator
$iterator) use ($child, $test) {
479 $test->assertInstanceOf('Symfony\Component\Form\Util\InheritDataAwareIterator', $iterator->getInnerIterator());
480 $test->assertSame(array('name' => $child), iterator_to_array($iterator));
484 'name' => 'Bernhard',
488 public function requestMethodProvider()
499 * @dataProvider requestMethodProvider
501 public function testSubmitPostOrPutRequest($method)
503 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
504 $this->markTestSkipped('The "HttpFoundation" component is not available');
507 $path = tempnam(sys_get_temp_dir(), 'sf2');
512 'name' => 'Bernhard',
513 'image' => array('filename' => 'foobar.png'),
519 'error' => array('image' => UPLOAD_ERR_OK
),
520 'name' => array('image' => 'upload.png'),
521 'size' => array('image' => 123),
522 'tmp_name' => array('image' => $path),
523 'type' => array('image' => 'image/png'),
527 $request = new Request(array(), $values, array(), array(), $files, array(
528 'REQUEST_METHOD' => $method,
531 $form = $this->getBuilder('author')
534 ->setDataMapper($this->getDataMapper())
535 ->setRequestHandler(new HttpFoundationRequestHandler())
537 $form->add($this->getBuilder('name')->getForm());
538 $form->add($this->getBuilder('image')->getForm());
540 $form->handleRequest($request);
542 $file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK
);
544 $this->assertEquals('Bernhard', $form['name']->getData());
545 $this->assertEquals($file, $form['image']->getData());
551 * @dataProvider requestMethodProvider
553 public function testSubmitPostOrPutRequestWithEmptyRootFormName($method)
555 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
556 $this->markTestSkipped('The "HttpFoundation" component is not available');
559 $path = tempnam(sys_get_temp_dir(), 'sf2');
563 'name' => 'Bernhard',
569 'error' => UPLOAD_ERR_OK
,
570 'name' => 'upload.png',
573 'type' => 'image/png',
577 $request = new Request(array(), $values, array(), array(), $files, array(
578 'REQUEST_METHOD' => $method,
581 $form = $this->getBuilder('')
584 ->setDataMapper($this->getDataMapper())
585 ->setRequestHandler(new HttpFoundationRequestHandler())
587 $form->add($this->getBuilder('name')->getForm());
588 $form->add($this->getBuilder('image')->getForm());
590 $form->handleRequest($request);
592 $file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK
);
594 $this->assertEquals('Bernhard', $form['name']->getData());
595 $this->assertEquals($file, $form['image']->getData());
596 $this->assertEquals(array('extra' => 'data'), $form->getExtraData());
602 * @dataProvider requestMethodProvider
604 public function testSubmitPostOrPutRequestWithSingleChildForm($method)
606 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
607 $this->markTestSkipped('The "HttpFoundation" component is not available');
610 $path = tempnam(sys_get_temp_dir(), 'sf2');
615 'error' => UPLOAD_ERR_OK
,
616 'name' => 'upload.png',
619 'type' => 'image/png',
623 $request = new Request(array(), array(), array(), array(), $files, array(
624 'REQUEST_METHOD' => $method,
627 $form = $this->getBuilder('image')
629 ->setRequestHandler(new HttpFoundationRequestHandler())
632 $form->handleRequest($request);
634 $file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK
);
636 $this->assertEquals($file, $form->getData());
642 * @dataProvider requestMethodProvider
644 public function testSubmitPostOrPutRequestWithSingleChildFormUploadedFile($method)
646 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
647 $this->markTestSkipped('The "HttpFoundation" component is not available');
650 $path = tempnam(sys_get_temp_dir(), 'sf2');
654 'name' => 'Bernhard',
657 $request = new Request(array(), $values, array(), array(), array(), array(
658 'REQUEST_METHOD' => $method,
661 $form = $this->getBuilder('name')
663 ->setRequestHandler(new HttpFoundationRequestHandler())
666 $form->handleRequest($request);
668 $this->assertEquals('Bernhard', $form->getData());
673 public function testSubmitGetRequest()
675 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
676 $this->markTestSkipped('The "HttpFoundation" component is not available');
681 'firstName' => 'Bernhard',
682 'lastName' => 'Schussek',
686 $request = new Request($values, array(), array(), array(), array(), array(
687 'REQUEST_METHOD' => 'GET',
690 $form = $this->getBuilder('author')
693 ->setDataMapper($this->getDataMapper())
694 ->setRequestHandler(new HttpFoundationRequestHandler())
696 $form->add($this->getBuilder('firstName')->getForm());
697 $form->add($this->getBuilder('lastName')->getForm());
699 $form->handleRequest($request);
701 $this->assertEquals('Bernhard', $form['firstName']->getData());
702 $this->assertEquals('Schussek', $form['lastName']->getData());
705 public function testSubmitGetRequestWithEmptyRootFormName()
707 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
708 $this->markTestSkipped('The "HttpFoundation" component is not available');
712 'firstName' => 'Bernhard',
713 'lastName' => 'Schussek',
717 $request = new Request($values, array(), array(), array(), array(), array(
718 'REQUEST_METHOD' => 'GET',
721 $form = $this->getBuilder('')
724 ->setDataMapper($this->getDataMapper())
725 ->setRequestHandler(new HttpFoundationRequestHandler())
727 $form->add($this->getBuilder('firstName')->getForm());
728 $form->add($this->getBuilder('lastName')->getForm());
730 $form->handleRequest($request);
732 $this->assertEquals('Bernhard', $form['firstName']->getData());
733 $this->assertEquals('Schussek', $form['lastName']->getData());
734 $this->assertEquals(array('extra' => 'data'), $form->getExtraData());
737 public function testGetErrorsAsStringDeep()
739 $parent = $this->getBuilder()
741 ->setDataMapper($this->getDataMapper())
744 $this->form
->addError(new FormError('Error!'));
746 $parent->add($this->form
);
747 $parent->add($this->getBuilder('foo')->getForm());
749 $this->assertEquals("name:\n ERROR: Error!\nfoo:\n No errors\n", $parent->getErrorsAsString());
752 protected function createForm()
754 return $this->getBuilder()
756 ->setDataMapper($this->getDataMapper())