* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Tests; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormView; use Symfony\Component\Form\FormError; use Symfony\Component\Form\Extension\Core\EventListener\BindRequestListener; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer; class CompoundFormTest extends AbstractFormTest { public function testValidIfAllChildrenAreValid() { $this->form->add($this->getValidForm('firstName')); $this->form->add($this->getValidForm('lastName')); $this->form->bind(array( 'firstName' => 'Bernhard', 'lastName' => 'Schussek', )); $this->assertTrue($this->form->isValid()); } public function testInvalidIfChildrenIsInvalid() { $this->form->add($this->getValidForm('firstName')); $this->form->add($this->getInvalidForm('lastName')); $this->form->bind(array( 'firstName' => 'Bernhard', 'lastName' => 'Schussek', )); $this->assertFalse($this->form->isValid()); } public function testBindForwardsNullIfValueIsMissing() { $child = $this->getMockForm('firstName'); $this->form->add($child); $child->expects($this->once()) ->method('bind') ->with($this->equalTo(null)); $this->form->bind(array()); } public function testCloneChildren() { $child = $this->getBuilder('child')->getForm(); $this->form->add($child); $clone = clone $this->form; $this->assertNotSame($this->form, $clone); $this->assertNotSame($child, $clone['child']); } public function testNotEmptyIfChildNotEmpty() { $child = $this->getMockForm(); $child->expects($this->once()) ->method('isEmpty') ->will($this->returnValue(false)); $this->form->setData(null); $this->form->add($child); $this->assertFalse($this->form->isEmpty()); } public function testValidIfBoundAndDisabledWithChildren() { $this->factory->expects($this->once()) ->method('createNamedBuilder') ->with('name', 'text', null, array()) ->will($this->returnValue($this->getBuilder('name'))); $form = $this->getBuilder('person') ->setDisabled(true) ->setCompound(true) ->setDataMapper($this->getDataMapper()) ->add('name', 'text') ->getForm(); $form->bind(array('name' => 'Jacques Doe')); $this->assertTrue($form->isValid()); } public function testNotValidIfChildNotValid() { $child = $this->getMockForm(); $child->expects($this->once()) ->method('isValid') ->will($this->returnValue(false)); $this->form->add($child); $this->form->bind(array()); $this->assertFalse($this->form->isValid()); } public function testHasChildren() { $this->form->add($this->getBuilder()->getForm()); $this->assertTrue($this->form->hasChildren()); } public function testHasNoChildren() { $this->assertFalse($this->form->hasChildren()); } public function testAdd() { $child = $this->getBuilder('foo')->getForm(); $this->form->add($child); $this->assertSame($this->form, $child->getParent()); $this->assertSame(array('foo' => $child), $this->form->all()); } /** * @expectedException Symfony\Component\Form\Exception\AlreadyBoundException */ public function testAddThrowsExceptionIfAlreadyBound() { $this->form->bind(array()); $this->form->add($this->getBuilder('foo')->getForm()); } public function testRemove() { $child = $this->getBuilder('foo')->getForm(); $this->form->add($child); $this->form->remove('foo'); $this->assertNull($child->getParent()); $this->assertFalse($this->form->hasChildren()); } /** * @expectedException Symfony\Component\Form\Exception\AlreadyBoundException */ public function testRemoveThrowsExceptionIfAlreadyBound() { $this->form->add($this->getBuilder('foo')->setCompound(false)->getForm()); $this->form->bind(array('foo' => 'bar')); $this->form->remove('foo'); } public function testRemoveIgnoresUnknownName() { $this->form->remove('notexisting'); } public function testArrayAccess() { $child = $this->getBuilder('foo')->getForm(); $this->form[] = $child; $this->assertTrue(isset($this->form['foo'])); $this->assertSame($child, $this->form['foo']); unset($this->form['foo']); $this->assertFalse(isset($this->form['foo'])); } public function testCountable() { $this->form->add($this->getBuilder('foo')->getForm()); $this->form->add($this->getBuilder('bar')->getForm()); $this->assertCount(2, $this->form); } public function testIterator() { $this->form->add($this->getBuilder('foo')->getForm()); $this->form->add($this->getBuilder('bar')->getForm()); $this->assertSame($this->form->all(), iterator_to_array($this->form)); } public function testAddMapsViewDataToForm() { $mapper = $this->getDataMapper(); $form = $this->getBuilder() ->setCompound(true) ->setDataMapper($mapper) ->addViewTransformer(new FixedDataTransformer(array( '' => '', 'foo' => 'bar', ))) ->setData('foo') ->getForm(); $child = $this->getBuilder()->getForm(); $mapper->expects($this->once()) ->method('mapDataToForms') ->with('bar', array($child)); $form->add($child); } public function testSetDataMapsViewDataToChildren() { $mapper = $this->getDataMapper(); $form = $this->getBuilder() ->setCompound(true) ->setDataMapper($mapper) ->addViewTransformer(new FixedDataTransformer(array( '' => '', 'foo' => 'bar', ))) ->getForm(); $form->add($child1 = $this->getBuilder('firstName')->getForm()); $form->add($child2 = $this->getBuilder('lastName')->getForm()); $mapper->expects($this->once()) ->method('mapDataToForms') ->with('bar', array('firstName' => $child1, 'lastName' => $child2)); $form->setData('foo'); } public function testBindMapsBoundChildrenOntoExistingViewData() { $test = $this; $mapper = $this->getDataMapper(); $form = $this->getBuilder() ->setCompound(true) ->setDataMapper($mapper) ->addViewTransformer(new FixedDataTransformer(array( '' => '', 'foo' => 'bar', ))) ->setData('foo') ->getForm(); $form->add($child1 = $this->getBuilder('firstName')->setCompound(false)->getForm()); $form->add($child2 = $this->getBuilder('lastName')->setCompound(false)->getForm()); $mapper->expects($this->once()) ->method('mapFormsToData') ->with(array('firstName' => $child1, 'lastName' => $child2), 'bar') ->will($this->returnCallback(function ($children, $bar) use ($test) { $test->assertEquals('Bernhard', $children['firstName']->getData()); $test->assertEquals('Schussek', $children['lastName']->getData()); })); $form->bind(array( 'firstName' => 'Bernhard', 'lastName' => 'Schussek', )); } /* * https://github.com/symfony/symfony/issues/4480 */ public function testBindRestoresViewDataIfCompoundAndEmpty() { $mapper = $this->getDataMapper(); $object = new \stdClass(); $form = $this->getBuilder('name', null, 'stdClass') ->setCompound(true) ->setDataMapper($mapper) ->setData($object) ->getForm(); $form->bind(array()); $this->assertSame($object, $form->getData()); } public function testBindMapsBoundChildrenOntoEmptyData() { $mapper = $this->getDataMapper(); $object = new \stdClass(); $form = $this->getBuilder() ->setCompound(true) ->setDataMapper($mapper) ->setEmptyData($object) ->setData(null) ->getForm(); $form->add($child = $this->getBuilder('name')->setCompound(false)->getForm()); $mapper->expects($this->once()) ->method('mapFormsToData') ->with(array('name' => $child), $object); $form->bind(array( 'name' => 'Bernhard', )); } public function requestMethodProvider() { return array( array('POST'), array('PUT'), array('DELETE'), array('PATCH'), ); } /** * @dataProvider requestMethodProvider */ public function testBindPostOrPutRequest($method) { if (!class_exists('Symfony\Component\HttpFoundation\Request')) { $this->markTestSkipped('The "HttpFoundation" component is not available'); } $path = tempnam(sys_get_temp_dir(), 'sf2'); touch($path); $values = array( 'author' => array( 'name' => 'Bernhard', 'image' => array('filename' => 'foobar.png'), ), ); $files = array( 'author' => array( 'error' => array('image' => UPLOAD_ERR_OK), 'name' => array('image' => 'upload.png'), 'size' => array('image' => 123), 'tmp_name' => array('image' => $path), 'type' => array('image' => 'image/png'), ), ); $request = new Request(array(), $values, array(), array(), $files, array( 'REQUEST_METHOD' => $method, )); $form = $this->getBuilder('author') ->setCompound(true) ->setDataMapper($this->getDataMapper()) ->addEventSubscriber(new BindRequestListener()) ->getForm(); $form->add($this->getBuilder('name')->getForm()); $form->add($this->getBuilder('image')->getForm()); $form->bindRequest($request); $file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK); $this->assertEquals('Bernhard', $form['name']->getData()); $this->assertEquals($file, $form['image']->getData()); unlink($path); } /** * @dataProvider requestMethodProvider */ public function testBindPostOrPutRequestWithEmptyRootFormName($method) { if (!class_exists('Symfony\Component\HttpFoundation\Request')) { $this->markTestSkipped('The "HttpFoundation" component is not available'); } $path = tempnam(sys_get_temp_dir(), 'sf2'); touch($path); $values = array( 'name' => 'Bernhard', 'extra' => 'data', ); $files = array( 'image' => array( 'error' => UPLOAD_ERR_OK, 'name' => 'upload.png', 'size' => 123, 'tmp_name' => $path, 'type' => 'image/png', ), ); $request = new Request(array(), $values, array(), array(), $files, array( 'REQUEST_METHOD' => $method, )); $form = $this->getBuilder('') ->setCompound(true) ->setDataMapper($this->getDataMapper()) ->addEventSubscriber(new BindRequestListener()) ->getForm(); $form->add($this->getBuilder('name')->getForm()); $form->add($this->getBuilder('image')->getForm()); $form->bindRequest($request); $file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK); $this->assertEquals('Bernhard', $form['name']->getData()); $this->assertEquals($file, $form['image']->getData()); $this->assertEquals(array('extra' => 'data'), $form->getExtraData()); unlink($path); } /** * @dataProvider requestMethodProvider */ public function testBindPostOrPutRequestWithSingleChildForm($method) { if (!class_exists('Symfony\Component\HttpFoundation\Request')) { $this->markTestSkipped('The "HttpFoundation" component is not available'); } $path = tempnam(sys_get_temp_dir(), 'sf2'); touch($path); $files = array( 'image' => array( 'error' => UPLOAD_ERR_OK, 'name' => 'upload.png', 'size' => 123, 'tmp_name' => $path, 'type' => 'image/png', ), ); $request = new Request(array(), array(), array(), array(), $files, array( 'REQUEST_METHOD' => $method, )); $form = $this->getBuilder('image') ->addEventSubscriber(new BindRequestListener()) ->getForm(); $form->bindRequest($request); $file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK); $this->assertEquals($file, $form->getData()); unlink($path); } /** * @dataProvider requestMethodProvider */ public function testBindPostOrPutRequestWithSingleChildFormUploadedFile($method) { if (!class_exists('Symfony\Component\HttpFoundation\Request')) { $this->markTestSkipped('The "HttpFoundation" component is not available'); } $path = tempnam(sys_get_temp_dir(), 'sf2'); touch($path); $values = array( 'name' => 'Bernhard', ); $request = new Request(array(), $values, array(), array(), array(), array( 'REQUEST_METHOD' => $method, )); $form = $this->getBuilder('name') ->addEventSubscriber(new BindRequestListener()) ->getForm(); $form->bindRequest($request); $this->assertEquals('Bernhard', $form->getData()); unlink($path); } public function testBindGetRequest() { if (!class_exists('Symfony\Component\HttpFoundation\Request')) { $this->markTestSkipped('The "HttpFoundation" component is not available'); } $values = array( 'author' => array( 'firstName' => 'Bernhard', 'lastName' => 'Schussek', ), ); $request = new Request($values, array(), array(), array(), array(), array( 'REQUEST_METHOD' => 'GET', )); $form = $this->getBuilder('author') ->setCompound(true) ->setDataMapper($this->getDataMapper()) ->addEventSubscriber(new BindRequestListener()) ->getForm(); $form->add($this->getBuilder('firstName')->getForm()); $form->add($this->getBuilder('lastName')->getForm()); $form->bindRequest($request); $this->assertEquals('Bernhard', $form['firstName']->getData()); $this->assertEquals('Schussek', $form['lastName']->getData()); } public function testBindGetRequestWithEmptyRootFormName() { if (!class_exists('Symfony\Component\HttpFoundation\Request')) { $this->markTestSkipped('The "HttpFoundation" component is not available'); } $values = array( 'firstName' => 'Bernhard', 'lastName' => 'Schussek', 'extra' => 'data' ); $request = new Request($values, array(), array(), array(), array(), array( 'REQUEST_METHOD' => 'GET', )); $form = $this->getBuilder('') ->setCompound(true) ->setDataMapper($this->getDataMapper()) ->addEventSubscriber(new BindRequestListener()) ->getForm(); $form->add($this->getBuilder('firstName')->getForm()); $form->add($this->getBuilder('lastName')->getForm()); $form->bindRequest($request); $this->assertEquals('Bernhard', $form['firstName']->getData()); $this->assertEquals('Schussek', $form['lastName']->getData()); $this->assertEquals(array('extra' => 'data'), $form->getExtraData()); } public function testGetErrorsAsStringDeep() { $parent = $this->getBuilder() ->setCompound(true) ->setDataMapper($this->getDataMapper()) ->getForm(); $this->form->addError(new FormError('Error!')); $parent->add($this->form); $parent->add($this->getBuilder('foo')->getForm()); $this->assertEquals("name:\n ERROR: Error!\nfoo:\n No errors\n", $parent->getErrorsAsString()); } protected function createForm() { return $this->getBuilder() ->setCompound(true) ->setDataMapper($this->getDataMapper()) ->getForm(); } }