[Form] Fixed: errors are not mapped to unsynchronized forms anymore
This commit is contained in:
parent
c8b61d576b
commit
c9c4900663
@ -73,6 +73,7 @@ CHANGELOG
|
||||
* added option "mapped" which should be used instead of setting "property_path" to false
|
||||
* "data_class" now *must* be set if a form maps to an object and should be left empty otherwise
|
||||
* improved error mapping on forms
|
||||
* errors are not mapped to unsynchronized forms anymore
|
||||
* changed Form constructor to accept a single `FormConfigInterface` object
|
||||
* changed argument order in the FormBuilder constructor
|
||||
* deprecated Form methods
|
||||
|
@ -47,6 +47,7 @@ class FormType extends AbstractType
|
||||
// BC compatibility, when "property_path" could be false
|
||||
->setPropertyPath(is_string($options['property_path']) ? $options['property_path'] : null)
|
||||
->setMapped($options['mapped'])
|
||||
->setVirtual($options['virtual'])
|
||||
->setAttribute('read_only', $options['read_only'])
|
||||
->setAttribute('by_reference', $options['by_reference'])
|
||||
->setAttribute('error_mapping', $options['error_mapping'])
|
||||
@ -58,7 +59,6 @@ class FormType extends AbstractType
|
||||
->setAttribute('invalid_message', $options['invalid_message'])
|
||||
->setAttribute('invalid_message_parameters', $options['invalid_message_parameters'])
|
||||
->setAttribute('translation_domain', $options['translation_domain'])
|
||||
->setAttribute('virtual', $options['virtual'])
|
||||
->setAttribute('single_control', $options['single_control'])
|
||||
->setData($options['data'])
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
|
@ -18,7 +18,6 @@ use Symfony\Component\Form\FormError;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
use Symfony\Component\Form\Event\DataEvent;
|
||||
use Symfony\Component\Form\Exception\FormException;
|
||||
use Symfony\Component\Form\Util\VirtualFormAwareIterator;
|
||||
use Symfony\Component\Form\Util\PropertyPath;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ValidatorInterface;
|
||||
|
@ -91,11 +91,18 @@ class ViolationMapper
|
||||
}
|
||||
}
|
||||
|
||||
$this->scope->addError(new FormError(
|
||||
$violation->getMessageTemplate(),
|
||||
$violation->getMessageParameters(),
|
||||
$violation->getMessagePluralization()
|
||||
));
|
||||
// Only add the error if the form is synchronized
|
||||
// If the form is not synchronized, it already contains an
|
||||
// error about being invalid. Further errors could be a result
|
||||
// of the failed transformation and thus should not be
|
||||
// displayed.
|
||||
if ($this->scope->isSynchronized()) {
|
||||
$this->scope->addError(new FormError(
|
||||
$violation->getMessageTemplate(),
|
||||
$violation->getMessageParameters(),
|
||||
$violation->getMessagePluralization()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -204,7 +211,7 @@ class ViolationMapper
|
||||
// Process child form
|
||||
$scope = $scope->get($it->current());
|
||||
|
||||
if ($scope->getAttribute('virtual')) {
|
||||
if ($scope->getConfig()->getVirtual()) {
|
||||
// Form is virtual
|
||||
// Cut the piece out of the property path and proceed
|
||||
$propertyPathBuilder->remove($i);
|
||||
|
@ -43,6 +43,11 @@ class FormConfig implements FormConfigInterface
|
||||
*/
|
||||
private $mapped;
|
||||
|
||||
/**
|
||||
* @var Boolean
|
||||
*/
|
||||
private $virtual;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
@ -289,6 +294,14 @@ class FormConfig implements FormConfigInterface
|
||||
return $this->mapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getVirtual()
|
||||
{
|
||||
return $this->virtual;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -537,6 +550,20 @@ class FormConfig implements FormConfigInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the form should be virtual.
|
||||
*
|
||||
* @param Boolean $virtual Whether the form should be virtual.
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function setVirtual($virtual)
|
||||
{
|
||||
$this->virtual = $virtual;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the types.
|
||||
*
|
||||
|
@ -47,6 +47,17 @@ interface FormConfigInterface
|
||||
*/
|
||||
function getMapped();
|
||||
|
||||
/**
|
||||
* Returns whether the form should be virtual.
|
||||
*
|
||||
* When mapping data to the children of a form, the data mapper
|
||||
* should ignore virtual forms and map to the children of the
|
||||
* virtual form instead.
|
||||
*
|
||||
* @return Boolean Whether the form is virtual.
|
||||
*/
|
||||
function getVirtual();
|
||||
|
||||
/**
|
||||
* Returns the form types used to construct the form.
|
||||
*
|
||||
|
@ -12,6 +12,10 @@
|
||||
namespace Symfony\Component\Form\Tests\Extension\Validator\ViolationMapper;
|
||||
|
||||
use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper;
|
||||
use Symfony\Component\Form\Exception\TransformationFailedException;
|
||||
use Symfony\Component\Form\CallbackTransformer;
|
||||
use Symfony\Component\Form\Form;
|
||||
use Symfony\Component\Form\FormConfig;
|
||||
use Symfony\Component\Form\FormError;
|
||||
use Symfony\Component\Form\Util\PropertyPath;
|
||||
use Symfony\Component\Form\FormBuilder;
|
||||
@ -35,11 +39,6 @@ class ViolationMapperTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
private $dispatcher;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
private $factory;
|
||||
|
||||
/**
|
||||
* @var ViolationMapper
|
||||
*/
|
||||
@ -62,27 +61,27 @@ class ViolationMapperTest extends \PHPUnit_Framework_TestCase
|
||||
}
|
||||
|
||||
$this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
|
||||
$this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
|
||||
$this->mapper = new ViolationMapper();
|
||||
$this->message = 'Message';
|
||||
$this->params = array('foo' => 'bar');
|
||||
}
|
||||
|
||||
protected function getBuilder($name = 'name', $propertyPath = null, $dataClass = null, $errorMapping = array(), $virtual = false)
|
||||
protected function getForm($name = 'name', $propertyPath = null, $dataClass = null, $errorMapping = array(), $virtual = false, $synchronized = true)
|
||||
{
|
||||
$builder = new FormBuilder($name, $dataClass, $this->dispatcher, $this->factory);
|
||||
$builder->setPropertyPath(new PropertyPath($propertyPath ?: $name));
|
||||
$builder->setAttribute('error_mapping', $errorMapping);
|
||||
$builder->setAttribute('virtual', $virtual);
|
||||
$builder->setErrorBubbling(false);
|
||||
$builder->setMapped(true);
|
||||
$config = new FormConfig($name, $dataClass, $this->dispatcher);
|
||||
$config->setMapped(true);
|
||||
$config->setVirtual($virtual);
|
||||
$config->setPropertyPath($propertyPath);
|
||||
$config->setAttribute('error_mapping', $errorMapping);
|
||||
|
||||
return $builder;
|
||||
}
|
||||
if (!$synchronized) {
|
||||
$config->appendClientTransformer(new CallbackTransformer(
|
||||
function ($normData) { return $normData; },
|
||||
function () { throw new TransformationFailedException(); }
|
||||
));
|
||||
}
|
||||
|
||||
protected function getForm($name = 'name', $propertyPath = null, $dataClass = null, $errorMapping = array(), $virtual = false)
|
||||
{
|
||||
return $this->getBuilder($name, $propertyPath, $dataClass, $errorMapping, $virtual)->getForm();
|
||||
return new Form($config);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1338,4 +1337,21 @@ class ViolationMapperTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName. ' should have an error, but has none');
|
||||
}
|
||||
}
|
||||
|
||||
public function testDontMapToUnsynchronizedForms()
|
||||
{
|
||||
$violation = $this->getConstraintViolation('children[address].data.street');
|
||||
$parent = $this->getForm('parent');
|
||||
$child = $this->getForm('address', 'address', null, array(), false, false);
|
||||
|
||||
$parent->add($child);
|
||||
|
||||
// bind to invoke the transformer and mark the form unsynchronized
|
||||
$parent->bind(array());
|
||||
|
||||
$this->mapper->mapViolation($violation, $parent);
|
||||
|
||||
$this->assertFalse($parent->hasErrors(), $parent->getName() . ' should not have an error, but has one');
|
||||
$this->assertFalse($child->hasErrors(), $child->getName() . ' should not have an error, but has one');
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,11 @@ class UnmodifiableFormConfig implements FormConfigInterface
|
||||
*/
|
||||
private $mapped;
|
||||
|
||||
/**
|
||||
* @var Boolean
|
||||
*/
|
||||
private $virtual;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
@ -118,6 +123,7 @@ class UnmodifiableFormConfig implements FormConfigInterface
|
||||
$this->name = $config->getName();
|
||||
$this->propertyPath = $config->getPropertyPath();
|
||||
$this->mapped = $config->getMapped();
|
||||
$this->virtual = $config->getVirtual();
|
||||
$this->types = $config->getTypes();
|
||||
$this->clientTransformers = $config->getClientTransformers();
|
||||
$this->normTransformers = $config->getNormTransformers();
|
||||
@ -164,6 +170,14 @@ class UnmodifiableFormConfig implements FormConfigInterface
|
||||
return $this->mapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getVirtual()
|
||||
{
|
||||
return $this->virtual;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -28,7 +28,6 @@ class VirtualFormAwareIterator extends \ArrayIterator implements \RecursiveItera
|
||||
|
||||
public function hasChildren()
|
||||
{
|
||||
return $this->current()->hasAttribute('virtual')
|
||||
&& $this->current()->getAttribute('virtual');
|
||||
return $this->current()->getConfig()->getVirtual();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user