[Form] The form is now validated seperatedly from its data. The form is validated in group "Default", the data in the group set in option "validation_groups"
This commit is contained in:
parent
c923af2879
commit
5e3fab214e
21
src/Symfony/Component/Form/DataError.php
Normal file
21
src/Symfony/Component/Form/DataError.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form;
|
||||
|
||||
/**
|
||||
* Wraps errors in the form data
|
||||
*
|
||||
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
|
||||
*/
|
||||
class DataError extends Error
|
||||
{
|
||||
}
|
65
src/Symfony/Component/Form/Error.php
Normal file
65
src/Symfony/Component/Form/Error.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form;
|
||||
|
||||
/**
|
||||
* Wraps errors in forms
|
||||
*
|
||||
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
|
||||
*/
|
||||
class Error
|
||||
{
|
||||
/**
|
||||
* The template for the error message
|
||||
* @var string
|
||||
*/
|
||||
protected $messageTemplate;
|
||||
|
||||
/**
|
||||
* The parameters that should be substituted in the message template
|
||||
* @var array
|
||||
*/
|
||||
protected $messageParameters;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $messageTemplate The template for the error message
|
||||
* @param array $messageParameters The parameters that should be
|
||||
* substituted in the message template.
|
||||
*/
|
||||
public function __construct($messageTemplate, array $messageParameters = array())
|
||||
{
|
||||
$this->messageTemplate = $messageTemplate;
|
||||
$this->messageParameters = $messageParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error message template
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMessageTemplate()
|
||||
{
|
||||
return $this->messageTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameters to be inserted in the message template
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMessageParameters()
|
||||
{
|
||||
return $this->messageParameters;
|
||||
}
|
||||
}
|
@ -358,7 +358,7 @@ class Field extends Configurable implements FieldInterface
|
||||
*
|
||||
* @see FieldInterface
|
||||
*/
|
||||
public function addError(FieldError $error, PropertyPathIterator $pathIterator = null, $type = null)
|
||||
public function addError(Error $error, PropertyPathIterator $pathIterator = null)
|
||||
{
|
||||
$this->errors[] = $error;
|
||||
}
|
||||
|
@ -16,42 +16,6 @@ namespace Symfony\Component\Form;
|
||||
*
|
||||
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
|
||||
*/
|
||||
class FieldError
|
||||
class FieldError extends Error
|
||||
{
|
||||
protected $messageTemplate;
|
||||
|
||||
protected $messageParameters;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $messageTemplate The template for the error message
|
||||
* @param array $messageParameters The parameters that should be
|
||||
* substituted in the message template.
|
||||
*/
|
||||
public function __construct($messageTemplate, array $messageParameters = array())
|
||||
{
|
||||
$this->messageTemplate = $messageTemplate;
|
||||
$this->messageParameters = $messageParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error message template
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMessageTemplate()
|
||||
{
|
||||
return $this->messageTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameters to be inserted in the message template
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMessageParameters()
|
||||
{
|
||||
return $this->messageParameters;
|
||||
}
|
||||
}
|
@ -154,11 +154,10 @@ interface FieldInterface
|
||||
* ...
|
||||
* </code>
|
||||
*
|
||||
* @param FieldError $error
|
||||
* @param Error $error
|
||||
* @param PropertyPathIterator $pathIterator
|
||||
* @param ConstraintViolation$violation
|
||||
*/
|
||||
function addError(FieldError $error, PropertyPathIterator $pathIterator = null, $type = null);
|
||||
function addError(Error $error, PropertyPathIterator $pathIterator = null);
|
||||
|
||||
/**
|
||||
* Returns whether the field is valid.
|
||||
|
@ -516,10 +516,10 @@ class Form extends Field implements \IteratorAggregate, FormInterface
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function addError(FieldError $error, PropertyPathIterator $pathIterator = null, $type = null)
|
||||
public function addError(Error $error, PropertyPathIterator $pathIterator = null)
|
||||
{
|
||||
if (null !== $pathIterator) {
|
||||
if ($type === self::FIELD_ERROR && $pathIterator->hasNext()) {
|
||||
if ($error instanceof FieldError && $pathIterator->hasNext()) {
|
||||
$pathIterator->next();
|
||||
|
||||
if ($pathIterator->isProperty() && $pathIterator->current() === 'fields') {
|
||||
@ -527,11 +527,11 @@ class Form extends Field implements \IteratorAggregate, FormInterface
|
||||
}
|
||||
|
||||
if ($this->has($pathIterator->current()) && !$this->get($pathIterator->current())->isHidden()) {
|
||||
$this->get($pathIterator->current())->addError($error, $pathIterator, $type);
|
||||
$this->get($pathIterator->current())->addError($error, $pathIterator);
|
||||
|
||||
return;
|
||||
}
|
||||
} else if ($type === self::DATA_ERROR) {
|
||||
} else if ($error instanceof DataError) {
|
||||
$iterator = new RecursiveFieldIterator($this);
|
||||
$iterator = new \RecursiveIteratorIterator($iterator);
|
||||
|
||||
@ -542,7 +542,7 @@ class Form extends Field implements \IteratorAggregate, FormInterface
|
||||
$pathIterator->next();
|
||||
}
|
||||
|
||||
$field->addError($error, $pathIterator, $type);
|
||||
$field->addError($error, $pathIterator);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -729,25 +729,34 @@ class Form extends Field implements \IteratorAggregate, FormInterface
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
if (null === $this->getOption('validator')) {
|
||||
$validator = $this->getOption('validator');
|
||||
$groups = $this->getOption('validation_groups');
|
||||
|
||||
if (null === $validator) {
|
||||
throw new MissingOptionsException('The option "validator" is required for validating', array('validator'));
|
||||
}
|
||||
|
||||
// Validate the submitted data
|
||||
if ($violations = $this->getOption('validator')->validate($this, $this->getOption('validation_groups'))) {
|
||||
// TODO: test me
|
||||
// Validate the submitted data in the domain object in the sets
|
||||
// validation group(s)
|
||||
if ($violations = $validator->validate($this->getData(), $groups)) {
|
||||
foreach ($violations as $violation) {
|
||||
$propertyPath = new PropertyPath($violation->getPropertyPath());
|
||||
$iterator = $propertyPath->getIterator();
|
||||
$iterator->next(); // point at the first data element
|
||||
$error = new DataError($violation->getMessageTemplate(), $violation->getMessageParameters());
|
||||
|
||||
if ($iterator->current() == 'data') {
|
||||
$type = self::DATA_ERROR;
|
||||
$iterator->next(); // point at the first data element
|
||||
} else {
|
||||
$type = self::FIELD_ERROR;
|
||||
}
|
||||
$this->addError($error, $iterator);
|
||||
}
|
||||
}
|
||||
|
||||
$this->addError(new FieldError($violation->getMessageTemplate(), $violation->getMessageParameters()), $iterator, $type);
|
||||
// Validate the submitted data in the fields in group "Default"
|
||||
if ($violations = $validator->validate($this)) {
|
||||
foreach ($violations as $violation) {
|
||||
$propertyPath = new PropertyPath($violation->getPropertyPath());
|
||||
$iterator = $propertyPath->getIterator();
|
||||
$error = new FieldError($violation->getMessageTemplate(), $violation->getMessageParameters());
|
||||
|
||||
$this->addError($error, $iterator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,9 +16,6 @@
|
||||
<property name="fields">
|
||||
<constraint name="Valid" />
|
||||
</property>
|
||||
<getter property="data">
|
||||
<constraint name="Valid" />
|
||||
</getter>
|
||||
<getter property="submittedWithExtraFields">
|
||||
<constraint name="AssertFalse">
|
||||
<option name="message">This form should not contain extra fields</option>
|
||||
|
@ -19,6 +19,7 @@ use Symfony\Component\Form\Form;
|
||||
use Symfony\Component\Form\FormContext;
|
||||
use Symfony\Component\Form\Field;
|
||||
use Symfony\Component\Form\FieldError;
|
||||
use Symfony\Component\Form\DataError;
|
||||
use Symfony\Component\Form\HiddenField;
|
||||
use Symfony\Component\Form\PropertyPath;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
@ -206,9 +207,19 @@ class FormTest extends \PHPUnit_Framework_TestCase
|
||||
));
|
||||
$form->add($field);
|
||||
|
||||
$this->validator->expects($this->once())
|
||||
->method('validate')
|
||||
->with($this->equalTo($form), $this->equalTo(array('group')));
|
||||
$this->validator->expects($this->exactly(2))
|
||||
->method('validate');
|
||||
|
||||
// PHPUnit limitation here
|
||||
// // form data is validated in custom group
|
||||
// $this->validator->expects($this->once())
|
||||
// ->method('validate')
|
||||
// ->with($this->equalTo($form->getData()), $this->equalTo(array('group')));
|
||||
//
|
||||
// // form itself is validated in group "Default"
|
||||
// $this->validator->expects($this->once())
|
||||
// ->method('validate')
|
||||
// ->with($this->equalTo($form));
|
||||
|
||||
// data is irrelevant
|
||||
$form->bind($this->createPostRequest());
|
||||
@ -453,7 +464,7 @@ class FormTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$path = new PropertyPath('fields[firstName].data');
|
||||
|
||||
$form->addError($error, $path->getIterator(), Form::FIELD_ERROR);
|
||||
$form->addError(new FieldError('Message'), $path->getIterator());
|
||||
}
|
||||
|
||||
public function testAddErrorMapsFieldValidationErrorsOntoFieldsWithinNestedForms()
|
||||
@ -472,13 +483,11 @@ class FormTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$path = new PropertyPath('fields[names].fields[firstName].data');
|
||||
|
||||
$form->addError($error, $path->getIterator(), Form::FIELD_ERROR);
|
||||
$form->addError(new FieldError('Message'), $path->getIterator());
|
||||
}
|
||||
|
||||
public function testAddErrorKeepsFieldValidationErrorsIfFieldNotFound()
|
||||
{
|
||||
$error = new FieldError('Message');
|
||||
|
||||
$field = $this->createMockField('foo');
|
||||
$field->expects($this->never())
|
||||
->method('addError');
|
||||
@ -488,15 +497,13 @@ class FormTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$path = new PropertyPath('fields[bar].data');
|
||||
|
||||
$form->addError($error, $path->getIterator(), Form::FIELD_ERROR);
|
||||
$form->addError(new FieldError('Message'), $path->getIterator());
|
||||
|
||||
$this->assertEquals(array($error), $form->getErrors());
|
||||
$this->assertEquals(array(new FieldError('Message')), $form->getErrors());
|
||||
}
|
||||
|
||||
public function testAddErrorKeepsFieldValidationErrorsIfFieldIsHidden()
|
||||
{
|
||||
$error = new FieldError('Message');
|
||||
|
||||
$field = $this->createMockField('firstName');
|
||||
$field->expects($this->any())
|
||||
->method('isHidden')
|
||||
@ -509,14 +516,14 @@ class FormTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$path = new PropertyPath('fields[firstName].data');
|
||||
|
||||
$form->addError($error, $path->getIterator(), Form::FIELD_ERROR);
|
||||
$form->addError(new FieldError('Message'), $path->getIterator());
|
||||
|
||||
$this->assertEquals(array($error), $form->getErrors());
|
||||
$this->assertEquals(array(new FieldError('Message')), $form->getErrors());
|
||||
}
|
||||
|
||||
public function testAddErrorMapsDataValidationErrorsOntoFields()
|
||||
{
|
||||
$error = new FieldError('Message');
|
||||
$error = new DataError('Message');
|
||||
|
||||
// path is expected to point at "firstName"
|
||||
$expectedPath = new PropertyPath('firstName');
|
||||
@ -528,20 +535,18 @@ class FormTest extends \PHPUnit_Framework_TestCase
|
||||
->will($this->returnValue(new PropertyPath('firstName')));
|
||||
$field->expects($this->once())
|
||||
->method('addError')
|
||||
->with($this->equalTo($error), $this->equalTo($expectedPathIterator), $this->equalTo(Form::DATA_ERROR));
|
||||
->with($this->equalTo($error), $this->equalTo($expectedPathIterator));
|
||||
|
||||
$form = new Form('author');
|
||||
$form->add($field);
|
||||
|
||||
$path = new PropertyPath('firstName');
|
||||
|
||||
$form->addError($error, $path->getIterator(), Form::DATA_ERROR);
|
||||
$form->addError($error, $path->getIterator());
|
||||
}
|
||||
|
||||
public function testAddErrorKeepsDataValidationErrorsIfFieldNotFound()
|
||||
{
|
||||
$error = new FieldError('Message');
|
||||
|
||||
$field = $this->createMockField('foo');
|
||||
$field->expects($this->any())
|
||||
->method('getPropertyPath')
|
||||
@ -554,13 +559,11 @@ class FormTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$path = new PropertyPath('bar');
|
||||
|
||||
$form->addError($error, $path->getIterator(), Form::DATA_ERROR);
|
||||
$form->addError(new DataError('Message'), $path->getIterator());
|
||||
}
|
||||
|
||||
public function testAddErrorKeepsDataValidationErrorsIfFieldIsHidden()
|
||||
{
|
||||
$error = new FieldError('Message');
|
||||
|
||||
$field = $this->createMockField('firstName');
|
||||
$field->expects($this->any())
|
||||
->method('isHidden')
|
||||
@ -576,12 +579,12 @@ class FormTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$path = new PropertyPath('firstName');
|
||||
|
||||
$form->addError($error, $path->getIterator(), Form::DATA_ERROR);
|
||||
$form->addError(new DataError('Message'), $path->getIterator());
|
||||
}
|
||||
|
||||
public function testAddErrorMapsDataValidationErrorsOntoNestedFields()
|
||||
{
|
||||
$error = new FieldError('Message');
|
||||
$error = new DataError('Message');
|
||||
|
||||
// path is expected to point at "street"
|
||||
$expectedPath = new PropertyPath('address.street');
|
||||
@ -594,19 +597,19 @@ class FormTest extends \PHPUnit_Framework_TestCase
|
||||
->will($this->returnValue(new PropertyPath('address')));
|
||||
$field->expects($this->once())
|
||||
->method('addError')
|
||||
->with($this->equalTo($error), $this->equalTo($expectedPathIterator), $this->equalTo(Form::DATA_ERROR));
|
||||
->with($this->equalTo($error), $this->equalTo($expectedPathIterator));
|
||||
|
||||
$form = new Form('author');
|
||||
$form->add($field);
|
||||
|
||||
$path = new PropertyPath('address.street');
|
||||
|
||||
$form->addError($error, $path->getIterator(), Form::DATA_ERROR);
|
||||
$form->addError($error, $path->getIterator());
|
||||
}
|
||||
|
||||
public function testAddErrorMapsErrorsOntoFieldsInVirtualGroups()
|
||||
{
|
||||
$error = new FieldError('Message');
|
||||
$error = new DataError('Message');
|
||||
|
||||
// path is expected to point at "address"
|
||||
$expectedPath = new PropertyPath('address');
|
||||
@ -618,7 +621,7 @@ class FormTest extends \PHPUnit_Framework_TestCase
|
||||
->will($this->returnValue(new PropertyPath('address')));
|
||||
$field->expects($this->once())
|
||||
->method('addError')
|
||||
->with($this->equalTo($error), $this->equalTo($expectedPathIterator), $this->equalTo(Form::DATA_ERROR));
|
||||
->with($this->equalTo($error), $this->equalTo($expectedPathIterator));
|
||||
|
||||
$form = new Form('author');
|
||||
$nestedForm = new Form('nested', array('virtual' => true));
|
||||
@ -627,7 +630,7 @@ class FormTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$path = new PropertyPath('address');
|
||||
|
||||
$form->addError($error, $path->getIterator(), Form::DATA_ERROR);
|
||||
$form->addError($error, $path->getIterator());
|
||||
}
|
||||
|
||||
public function testAddThrowsExceptionIfAlreadySubmitted()
|
||||
|
Reference in New Issue
Block a user