Skip to content

Commit

Permalink
[Form] Deprecated FormValidatorInterface and moved implementations to…
Browse files Browse the repository at this point in the history
… event listeners
  • Loading branch information
webmozart committed Apr 13, 2012
1 parent 4631141 commit 6df7a72
Show file tree
Hide file tree
Showing 13 changed files with 201 additions and 139 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG-2.1.md
Expand Up @@ -267,6 +267,8 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c
in their name anymore. Their names terminate with "[]" now.
* [BC BREAK] FormType::getDefaultOptions() and FormType::getAllowedOptionValues()
don't receive an options array anymore.
* Deprecated FormValidatorInterface and substituted its implementations
by event subscribers

### HttpFoundation

Expand Down
9 changes: 9 additions & 0 deletions UPGRADE-2.1.md
Expand Up @@ -417,6 +417,14 @@
`FormEvents::PRE_BIND`, `FormEvents::BIND_CLIENT_DATA` or
`FormEvents::BIND_NORM_DATA`.

* The interface FormValidatorInterface was deprecated and will be removed
in Symfony 2.3.

If you implemented custom validators using this interface, you can
substitute them by event listeners listening to the FormEvents::POST_BIND
(or any other of the BIND events). In case you used the CallbackValidator
class, you should now pass the callback directly to `addEventListener`.

### Session

* Flash messages now return an array based on their type. The old method is
Expand Down Expand Up @@ -543,6 +551,7 @@ To use mock session storage use the following. `handler_id` is irrelevant in th
session:
storage_id: session.storage.mock_file
```

### WebProfilerBundle

* You must clear old profiles after upgrading to 2.1. If you are using a
Expand Down
15 changes: 13 additions & 2 deletions src/Symfony/Component/Form/CallbackValidator.php
Expand Up @@ -11,17 +11,28 @@

namespace Symfony\Component\Form;

/**
* Deprecated. You should use FormEvents::POST_BIND event listeners instead.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
*/
class CallbackValidator implements FormValidatorInterface
{
private $callback;

/**
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
*/
public function __construct($callback)
{
// TODO validate callback

$this->callback = $callback;
}

/**
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
*/
public function validate(FormInterface $form)
{
return call_user_func($this->callback, $form);
Expand Down
Expand Up @@ -9,16 +9,30 @@
* file that was distributed with this source code.
*/

namespace Symfony\Component\Form\Extension\Core\Validator;
namespace Symfony\Component\Form\Extension\Core\EventListener;

use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormValidatorInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Event\DataEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class DefaultValidator implements FormValidatorInterface
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class ValidationListener implements EventSubscriberInterface
{
public function validate(FormInterface $form)
/**
* {@inheritdoc}
*/
static public function getSubscribedEvents()
{
return array(FormEvents::POST_BIND => 'validateForm');
}

public function validateForm(DataEvent $event)
{
$form = $event->getForm();

if (!$form->isSynchronized()) {
$form->addError(new FormError(
$form->getAttribute('invalid_message'),
Expand Down
4 changes: 2 additions & 2 deletions src/Symfony/Component/Form/Extension/Core/Type/FieldType.php
Expand Up @@ -19,7 +19,7 @@
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Extension\Core\EventListener\TrimListener;
use Symfony\Component\Form\Extension\Core\Validator\DefaultValidator;
use Symfony\Component\Form\Extension\Core\EventListener\ValidationListener;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Form\Exception\FormException;

Expand Down Expand Up @@ -60,7 +60,7 @@ public function buildForm(FormBuilder $builder, array $options)
->setAttribute('invalid_message_parameters', $options['invalid_message_parameters'])
->setAttribute('translation_domain', $options['translation_domain'])
->setData($options['data'])
->addValidator(new DefaultValidator())
->addEventSubscriber(new ValidationListener())
;

if ($options['trim']) {
Expand Down
Expand Up @@ -9,94 +9,33 @@
* file that was distributed with this source code.
*/

namespace Symfony\Component\Form\Extension\Validator\Validator;
namespace Symfony\Component\Form\Extension\Validator\EventListener;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormValidatorInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\Util\VirtualFormAwareIterator;
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;
use Symfony\Component\Validator\ExecutionContext;

class DelegatingValidator implements FormValidatorInterface
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class DelegatingValidationListener implements EventSubscriberInterface
{
private $validator;

public function __construct(ValidatorInterface $validator)
{
$this->validator = $validator;
}

/**
* Validates the form and its domain object.
*
* @param FormInterface $form A FormInterface instance
* {@inheritdoc}
*/
public function validate(FormInterface $form)
static public function getSubscribedEvents()
{
if ($form->isRoot()) {
$mapping = array();
$forms = array();

$this->buildFormPathMapping($form, $mapping);
$this->buildDataPathMapping($form, $mapping);
$this->buildNamePathMapping($form, $forms);
$this->resolveMappingPlaceholders($mapping, $forms);

// Validate the form in group "Default"
// Validation of the data in the custom group is done by validateData(),
// which is constrained by the Execute constraint
if ($form->hasAttribute('validation_constraint')) {
$violations = $this->validator->validateValue(
$form->getData(),
$form->getAttribute('validation_constraint'),
self::getFormValidationGroups($form)
);

if ($violations) {
foreach ($violations as $violation) {
$propertyPath = new PropertyPath($violation->getPropertyPath());
$template = $violation->getMessageTemplate();
$parameters = $violation->getMessageParameters();
$pluralization = $violation->getMessagePluralization();
$error = new FormError($template, $parameters, $pluralization);

$child = $form;
foreach ($propertyPath->getElements() as $element) {
$children = $child->getChildren();
if (!isset($children[$element])) {
$form->addError($error);
break;
}

$child = $children[$element];
}

$child->addError($error);
}
}
} elseif (count($violations = $this->validator->validate($form))) {
foreach ($violations as $violation) {
$propertyPath = $violation->getPropertyPath();
$template = $violation->getMessageTemplate();
$parameters = $violation->getMessageParameters();
$pluralization = $violation->getMessagePluralization();
$error = new FormError($template, $parameters, $pluralization);

foreach ($mapping as $mappedPath => $child) {
if (preg_match($mappedPath, $propertyPath)) {
$child->addError($error);
continue 2;
}
}

$form->addError($error);
}
}
}
return array(FormEvents::POST_BIND => 'validateForm');
}

/**
Expand Down Expand Up @@ -175,6 +114,82 @@ static protected function getFormValidationGroups(FormInterface $form)
return (array) $groups;
}

public function __construct(ValidatorInterface $validator)
{
$this->validator = $validator;
}

/**
* Validates the form and its domain object.
*
* @param DataEvent $event The event object
*/
public function validateForm(DataEvent $event)
{
$form = $event->getForm();

if ($form->isRoot()) {
$mapping = array();
$forms = array();

$this->buildFormPathMapping($form, $mapping);
$this->buildDataPathMapping($form, $mapping);
$this->buildNamePathMapping($form, $forms);
$this->resolveMappingPlaceholders($mapping, $forms);

// Validate the form in group "Default"
// Validation of the data in the custom group is done by validateData(),
// which is constrained by the Execute constraint
if ($form->hasAttribute('validation_constraint')) {
$violations = $this->validator->validateValue(
$form->getData(),
$form->getAttribute('validation_constraint'),
self::getFormValidationGroups($form)
);

if ($violations) {
foreach ($violations as $violation) {
$propertyPath = new PropertyPath($violation->getPropertyPath());
$template = $violation->getMessageTemplate();
$parameters = $violation->getMessageParameters();
$pluralization = $violation->getMessagePluralization();
$error = new FormError($template, $parameters, $pluralization);

$child = $form;
foreach ($propertyPath->getElements() as $element) {
$children = $child->getChildren();
if (!isset($children[$element])) {
$form->addError($error);
break;
}

$child = $children[$element];
}

$child->addError($error);
}
}
} elseif (count($violations = $this->validator->validate($form))) {
foreach ($violations as $violation) {
$propertyPath = $violation->getPropertyPath();
$template = $violation->getMessageTemplate();
$parameters = $violation->getMessageParameters();
$pluralization = $violation->getMessagePluralization();
$error = new FormError($template, $parameters, $pluralization);

foreach ($mapping as $mappedPath => $child) {
if (preg_match($mappedPath, $propertyPath)) {
$child->addError($error);
continue 2;
}
}

$form->addError($error);
}
}
}
}

private function buildFormPathMapping(FormInterface $form, array &$mapping, $formPath = 'children', $namePath = '')
{
foreach ($form->getAttribute('error_mapping') as $nestedDataPath => $nestedNamePath) {
Expand Down
Expand Up @@ -13,9 +13,12 @@

use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\Extension\Validator\Validator\DelegatingValidator;
use Symfony\Component\Form\Extension\Validator\EventListener\DelegatingValidationListener;
use Symfony\Component\Validator\ValidatorInterface;

/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class FieldTypeValidatorExtension extends AbstractTypeExtension
{
private $validator;
Expand All @@ -39,7 +42,8 @@ public function buildForm(FormBuilder $builder, array $options)
->setAttribute('validation_groups', $options['validation_groups'])
->setAttribute('validation_constraint', $options['validation_constraint'])
->setAttribute('cascade_validation', $options['cascade_validation'])
->addValidator(new DelegatingValidator($this->validator));
->addEventSubscriber(new DelegatingValidationListener($this->validator))
;
}

public function getDefaultOptions()
Expand Down
5 changes: 2 additions & 3 deletions src/Symfony/Component/Form/Form.php
Expand Up @@ -573,9 +573,6 @@ public function bind($clientData)
$validator->validate($this);
}

$event = new DataEvent($this, $clientData);
$this->dispatcher->dispatch(FormEvents::POST_VALIDATE, $event);

return $this;
}

Expand Down Expand Up @@ -808,6 +805,8 @@ public function getClientTransformers()
* Returns the Validators
*
* @return array An array of FormValidatorInterface
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
*/
public function getValidators()
{
Expand Down
7 changes: 7 additions & 0 deletions src/Symfony/Component/Form/FormBuilder.php
Expand Up @@ -17,6 +17,9 @@
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class FormBuilder
{
/**
Expand Down Expand Up @@ -261,6 +264,8 @@ public function getErrorBubbling()
* @param FormValidatorInterface $validator The validator
*
* @return FormBuilder The current builder
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
*/
public function addValidator(FormValidatorInterface $validator)
{
Expand All @@ -273,6 +278,8 @@ public function addValidator(FormValidatorInterface $validator)
* Returns the validators used by the form.
*
* @return array An array of FormValidatorInterface
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
*/
public function getValidators()
{
Expand Down
2 changes: 0 additions & 2 deletions src/Symfony/Component/Form/FormEvents.php
Expand Up @@ -29,6 +29,4 @@ final class FormEvents
const BIND_NORM_DATA = 'form.bind_norm_data';

const SET_DATA = 'form.set_data';

const POST_VALIDATE = 'form.post_validate';
}

0 comments on commit 6df7a72

Please sign in to comment.