Skip to content

Commit

Permalink
[Form] Compound forms now always need a data mapper. Otherwise an exc…
Browse files Browse the repository at this point in the history
…eption is thrown.
  • Loading branch information
webmozart committed Jul 6, 2012
1 parent 5758119 commit 9bf6e8b
Show file tree
Hide file tree
Showing 12 changed files with 1,578 additions and 1,399 deletions.
1 change: 1 addition & 0 deletions src/Symfony/Component/Form/CHANGELOG.md
Expand Up @@ -139,3 +139,4 @@ CHANGELOG
* deprecated `getChildren` in Form and FormBuilder in favor of `all`
* deprecated `hasChildren` in Form and FormBuilder in favor of `count`
* FormBuilder now implements \IteratorAggregate
* [BC BREAK] compound forms now always need a data mapper
Expand Up @@ -44,7 +44,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
->setVirtual($options['virtual'])
->setCompound($options['compound'])
->setData($options['data'])
->setDataMapper(new PropertyPathMapper())
->setDataMapper($options['compound'] ? new PropertyPathMapper() : null)
;

if ($options['trim']) {
Expand Down
29 changes: 16 additions & 13 deletions src/Symfony/Component/Form/Form.php
Expand Up @@ -130,6 +130,13 @@ public function __construct(FormConfigInterface $config)
$config = new UnmodifiableFormConfig($config);
}

// Compound forms always need a data mapper, otherwise calls to
// `setData` and `add` will not lead to the correct population of
// the child forms.
if ($config->getCompound() && !$config->getDataMapper()) {
throw new FormException('Compound forms need a data mapper');
}

$this->config = $config;

$this->setData($config->getData());
Expand Down Expand Up @@ -378,7 +385,7 @@ public function setData($modelData)
$this->viewData = $viewData;
$this->synchronized = true;

if ($this->config->getCompound() && $this->config->getDataMapper()) {
if ($this->config->getCompound()) {
// Update child forms from the data
$this->config->getDataMapper()->mapDataToForms($viewData, $this->children);
}
Expand Down Expand Up @@ -477,6 +484,9 @@ public function bind($submittedData)
$this->config->getEventDispatcher()->dispatch(FormEvents::BIND_CLIENT_DATA, $event);
$submittedData = $event->getData();

// By default, the submitted data is also the data in view format
$viewData = $submittedData;

// Check whether the form is compound.
// This check is preferrable over checking the number of children,
// since forms without children may also be compound.
Expand All @@ -503,15 +513,10 @@ public function bind($submittedData)
$extraData[$name] = $value;
}
}
}

// By default, the submitted data is also the data in view format
$viewData = $submittedData;

// If the form is compound, the default data in view format
// is reused. The data of the children is merged into this
// default data using the data mapper.
if ($this->config->getCompound() && $this->config->getDataMapper()) {
// If the form is compound, the default data in view format
// is reused. The data of the children is merged into this
// default data using the data mapper.
$viewData = $this->getViewData();
}

Expand All @@ -527,7 +532,7 @@ public function bind($submittedData)
}

// Merge form data from children into existing view data
if ($this->config->getCompound() && $this->config->getDataMapper() && null !== $viewData) {
if ($this->config->getCompound() && null !== $viewData) {
$this->config->getDataMapper()->mapFormsToData($this->children, $viewData);
}

Expand Down Expand Up @@ -853,9 +858,7 @@ public function add(FormInterface $child)

$child->setParent($this);

if ($this->config->getDataMapper()) {
$this->config->getDataMapper()->mapDataToForms($this->getViewData(), array($child));
}
$this->config->getDataMapper()->mapDataToForms($this->getViewData(), array($child));

return $this;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Component/Form/FormConfig.php
Expand Up @@ -56,7 +56,7 @@ class FormConfig implements FormConfigEditorInterface
/**
* @var Boolean
*/
private $compound = true;
private $compound = false;

/**
* @var array
Expand Down
141 changes: 141 additions & 0 deletions src/Symfony/Component/Form/Tests/AbstractFormTest.php
@@ -0,0 +1,141 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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\FormError;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

abstract class AbstractFormTest extends \PHPUnit_Framework_TestCase
{
/**
* @var EventDispatcherInterface
*/
protected $dispatcher;

/**
* @var \Symfony\Component\Form\FormFactoryInterface
*/
protected $factory;

/**
* @var \Symfony\Component\Form\FormInterface
*/
protected $form;

protected function setUp()
{
if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
$this->markTestSkipped('The "EventDispatcher" component is not available');
}

$this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
$this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
$this->form = $this->createForm();
}

protected function tearDown()
{
$this->dispatcher = null;
$this->factory = null;
$this->form = null;
}

/**
* @return \Symfony\Component\Form\FormInterface
*/
abstract protected function createForm();

/**
* @param string $name
* @param EventDispatcherInterface $dispatcher
* @param string $dataClass
*
* @return FormBuilder
*/
protected function getBuilder($name = 'name', EventDispatcherInterface $dispatcher = null, $dataClass = null)
{
return new FormBuilder($name, $dataClass, $dispatcher ?: $this->dispatcher, $this->factory);
}

/**
* @param string $name
*
* @return \PHPUnit_Framework_MockObject_MockObject
*/
protected function getMockForm($name = 'name')
{
$form = $this->getMock('Symfony\Component\Form\Tests\FormInterface');

$form->expects($this->any())
->method('getName')
->will($this->returnValue($name));

return $form;
}

/**
* @param string $name
*
* @return \PHPUnit_Framework_MockObject_MockObject
*/
protected function getValidForm($name)
{
$form = $this->getMockForm($name);

$form->expects($this->any())
->method('isValid')
->will($this->returnValue(true));

return $form;
}

/**
* @param string $name
*
* @return \PHPUnit_Framework_MockObject_MockObject
*/
protected function getInvalidForm($name)
{
$form = $this->getMockForm($name);

$form->expects($this->any())
->method('isValid')
->will($this->returnValue(false));

return $form;
}

/**
* @return \PHPUnit_Framework_MockObject_MockObject
*/
protected function getDataMapper()
{
return $this->getMock('Symfony\Component\Form\DataMapperInterface');
}

/**
* @return \PHPUnit_Framework_MockObject_MockObject
*/
protected function getDataTransformer()
{
return $this->getMock('Symfony\Component\Form\DataTransformerInterface');
}

/**
* @return \PHPUnit_Framework_MockObject_MockObject
*/
protected function getFormValidator()
{
return $this->getMock('Symfony\Component\Form\FormValidatorInterface');
}
}

0 comments on commit 9bf6e8b

Please sign in to comment.