-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Form] Introduce validation events for forms #37641
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,28 @@ | ||||||
<?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\Extension\Validator\Event; | ||||||
|
||||||
use Symfony\Component\Form\FormEvent; | ||||||
|
||||||
/** | ||||||
* This event is dispatched after validation completes. | ||||||
* | ||||||
* In this stage, the form will return a correct value to Form::isValid() and allow for | ||||||
* further working with the form data. | ||||||
*/ | ||||||
final class PostValidateEvent extends FormEvent | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just asking, why not
Suggested change
? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You've got a point. I'm not entirely convinced by "validate" either, but I'm open for ideas. Any opinions or objections to the suggested wording? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. first i see the listener is called validationListener, thus suggest using validationEvent (i have in mind the workflow event logic, where event are named after the method) :) |
||||||
{ | ||||||
public function isFormValid(): bool | ||||||
{ | ||||||
return $this->getForm()->isValid(); | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?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\Extension\Validator\Event; | ||
|
||
use Symfony\Component\Form\FormEvent; | ||
|
||
/** | ||
* This event is dispatched before validation begins. | ||
* | ||
* In this stage the model and view data may have been denormalized. Otherwise the form | ||
* is desynchronized because transformation failed during submission. | ||
* | ||
* It can be used to fetch data after denormalization. | ||
* | ||
* The event attaches the current view data. To know whether this is the renormalized data | ||
* or the invalid request data, call Form::isSynchronized() first. | ||
*/ | ||
final class PreValidateEvent extends FormEvent | ||
{ | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -11,8 +11,12 @@ | |||||
|
||||||
namespace Symfony\Component\Form\Extension\Validator\EventListener; | ||||||
|
||||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||||||
use Symfony\Component\Form\Extension\Validator\Constraints\Form; | ||||||
use Symfony\Component\Form\Extension\Validator\Event\PostValidateEvent; | ||||||
use Symfony\Component\Form\Extension\Validator\Event\PreValidateEvent; | ||||||
use Symfony\Component\Form\Extension\Validator\FormValidationEvents; | ||||||
use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapperInterface; | ||||||
use Symfony\Component\Form\FormEvent; | ||||||
use Symfony\Component\Form\FormEvents; | ||||||
|
@@ -27,6 +31,8 @@ class ValidationListener implements EventSubscriberInterface | |||||
|
||||||
private $violationMapper; | ||||||
|
||||||
private $eventDispatcher; | ||||||
|
||||||
/** | ||||||
* {@inheritdoc} | ||||||
*/ | ||||||
|
@@ -35,17 +41,27 @@ public static function getSubscribedEvents() | |||||
return [FormEvents::POST_SUBMIT => 'validateForm']; | ||||||
} | ||||||
|
||||||
public function __construct(ValidatorInterface $validator, ViolationMapperInterface $violationMapper) | ||||||
public function __construct(ValidatorInterface $validator, ViolationMapperInterface $violationMapper, ?EventDispatcherInterface $eventDispatcher = null) | ||||||
{ | ||||||
$this->validator = $validator; | ||||||
$this->violationMapper = $violationMapper; | ||||||
|
||||||
if (!$this->eventDispatcher) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be the following?
Suggested change
|
||||||
@trigger_error(sprintf('The "$eventDispatcher" argument to the "%s" constructor will be required in Symfony 6.0.', self::class)); | ||||||
} | ||||||
|
||||||
$this->eventDispatcher = $eventDispatcher; | ||||||
} | ||||||
|
||||||
public function validateForm(FormEvent $event) | ||||||
{ | ||||||
$form = $event->getForm(); | ||||||
|
||||||
if ($form->isRoot()) { | ||||||
if ($this->eventDispatcher) { | ||||||
$this->eventDispatcher->dispatch(new PreValidateEvent($event->getForm(), $event->getData()), FormValidationEvents::PRE_VALIDATE); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is there any reason for these events to be root-only? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Validation is only triggered for root forms, hence the checks here. The validator then traverses the form and its data. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. given i have a custom form type listening to VALIDATE events now, im nesting this form type somewhere else ...all of a sudden the listener isnt called anymore on the child type. Im not sure that's expected, given validator service maps violations back to underlying form types, so each type has a PRE/POST validation knowledge imho. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, the issue is that this is form validation. Form validation is only triggered on root forms. You always have to attach validation listeners to the form that is being validated. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. form validation bubbles down. put different, why shouldnt i be able to listen to POST_VALIDATE in a child form to check for some synchronized errors? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Form validation does not bubble down. Validation does, in that the form validation metadata contains a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hm yes, i agree. Im a bit worried the difference is too subtle, compared to current post-submit with prio >0. Is there any reason to prefer the new events actually? other then cosmetics. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am kind of interested in this discussion - because my Bundle does exactly this. It works quite nicely. The most important parts for me - and my project - were - it has to bubble down - because I want to be able to run code inside of child forms whenever the whole form was successfully validated. And inside of the $event variable, you have to be able to access the current form (current child) and the root form. Otherwise, it would not be possible to detect what data to use for some action like uploading an image or persisting an entity etc. Like I said. My bundle works like a charm. I like to see this inside the Symfony core (form component). Anyways. I like to see that you guys put effort into this. |
||||||
} | ||||||
|
||||||
// Form groups are validated internally (FormValidator). Here we don't set groups as they are retrieved into the validator. | ||||||
foreach ($this->validator->validate($form) as $violation) { | ||||||
// Allow the "invalid" constraint to be put onto | ||||||
|
@@ -54,6 +70,10 @@ public function validateForm(FormEvent $event) | |||||
|
||||||
$this->violationMapper->mapViolation($violation, $form, $allowNonSynchronized); | ||||||
} | ||||||
|
||||||
if ($this->eventDispatcher) { | ||||||
$this->eventDispatcher->dispatch(new PostValidateEvent($event->getForm(), $event->getData()), FormValidationEvents::POST_VALIDATE); | ||||||
} | ||||||
} | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?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\Extension\Validator; | ||
|
||
final class FormValidationEvents | ||
{ | ||
/** | ||
* @see Event\PreValidateEvent | ||
* @Event(Event\PreValidateEvent::class) | ||
*/ | ||
const PRE_VALIDATE = 'form.pre_validate'; | ||
|
||
/** | ||
* This event is dispatched after validation completes. | ||
* | ||
* In this stage, the form will return a correct value to Form::isValid() and allow for | ||
* further working with the form data. | ||
* | ||
* @see Event\PostValidateEvent | ||
* @Event(Event\PostValidateEvent::class) | ||
*/ | ||
const POST_VALIDATE = 'form.post_validate'; | ||
} |
Uh oh!
There was an error while loading. Please reload this page.