diff --git a/docs/en/02_Developer_Guides/03_Forms/01_Validation.md b/docs/en/02_Developer_Guides/03_Forms/01_Validation.md index 82ad5abd0..8d5321506 100644 --- a/docs/en/02_Developer_Guides/03_Forms/01_Validation.md +++ b/docs/en/02_Developer_Guides/03_Forms/01_Validation.md @@ -158,6 +158,27 @@ reusable and would not be possible within the `CMS` or other automated `UI` but return $this->redirectBack(); } } + +## Exempt validation actions + +In some cases you might need to disable validation for specific actions. E.g. actions which discard submitted +data may not need to check the validity of the posted content. + +You can disable validation on individual using one of two methods: + + + :::php + $actions = new FieldList( + $action = FormAction::create('doSubmitForm', 'Submit') + ); + $form = new Form($controller, 'MyForm', $fields, $actions); + + // Disable actions on the form action themselves + $action->setValidationExempt(true); + + // Alternatively, you can whitelist individual actions on the form object by name + $form->setValidationExemptActions(['doSubmitForm']); + ## Server-side validation messages diff --git a/docs/en/04_Changelogs/4.0.0.md b/docs/en/04_Changelogs/4.0.0.md index 199e18499..9b1ea7b71 100644 --- a/docs/en/04_Changelogs/4.0.0.md +++ b/docs/en/04_Changelogs/4.0.0.md @@ -89,6 +89,7 @@ * `hasStages` is addded to check if an object has a given stage. * `stageTable` is added to get the table for a given class and stage. * `ChangeSet` and `ChangeSetItem` have been added for batch publishing of versioned dataobjects. + * `FormAction::setValidationExempt` can be used to turn on or off form validation for individual actions ### Front-end build tooling for CMS interface diff --git a/forms/Form.php b/forms/Form.php index 0be639164..735222bcd 100644 --- a/forms/Form.php +++ b/forms/Form.php @@ -712,6 +712,22 @@ class Form extends RequestHandler { return $this->validationExemptActions; } + /** + * Passed a FormAction, returns true if that action is exempt from Form validation + * + * @param FormAction $action + * @return bool + */ + public function actionIsValidationExempt($action) { + if ($action->getValidationExempt()) { + return true; + } + if (in_array($action->actionName(), $this->getValidationExemptActions())) { + return true; + } + return false; + } + /** * Convert this form to another format. * @param FormTransformation $format @@ -1342,8 +1358,8 @@ class Form extends RequestHandler { * @return boolean */ public function validate(){ - $buttonClicked = $this->buttonClicked(); - if($buttonClicked && in_array($buttonClicked->actionName(), $this->getValidationExemptActions())) { + $action = $this->buttonClicked(); + if($action && $this->actionIsValidationExempt($action)) { return true; } diff --git a/forms/FormAction.php b/forms/FormAction.php index 2824e6624..091f1c438 100644 --- a/forms/FormAction.php +++ b/forms/FormAction.php @@ -39,6 +39,13 @@ class FormAction extends FormField { */ protected $buttonContent = null; + /** + * Should validation be skipped when performing this action? + * + * @var bool + */ + protected $validationExempt = false; + /** * Create a new action button. * @@ -173,6 +180,26 @@ class FormAction extends FormField { return $this->useButtonTag; } + /** + * Set whether this action can be performed without validating the data + * + * @param bool $exempt + * @return $this + */ + public function setValidationExempt($exempt = true) { + $this->validationExempt = $exempt; + return $this; + } + + /** + * Get whether this action can be performed without vaidating the data + * + * @return bool + */ + public function getValidationExempt() { + return $this->validationExempt; + } + /** * Does not transform to readonly by purpose. * Globally disabled buttons would break the CMS. diff --git a/tests/forms/FormTest.php b/tests/forms/FormTest.php index d7ef14ddc..9ddf84a48 100644 --- a/tests/forms/FormTest.php +++ b/tests/forms/FormTest.php @@ -298,6 +298,28 @@ class FormTest extends FunctionalTest { ), 'Form->sessionMessage() shows up after reloading the form' ); + + // Test this same behaviour, but with a form-action exempted via instance + $response = $this->submitForm( + 'Form_Form', + 'action_doSubmitActionExempt', + array( + 'Email' => 'test@test.com' + ) + ); + + // The required message should be empty if validation was skipped + $items = $this->cssParser()->getBySelector('#Form_Form_SomeRequiredField_Holder .required'); + $this->assertEmpty($items); + + // And the session message should show up is submitted successfully + $this->assertPartialMatchBySelector( + '#Form_Form_error', + array( + 'Validation bypassed!' + ), + 'Form->sessionMessage() shows up after reloading the form' + ); } public function testSessionValidationMessage() { @@ -773,8 +795,10 @@ class FormTest_Controller extends Controller implements TestOnly { new NumericField('Number') ), new FieldList( - new FormAction('doSubmit'), - new FormAction('doSubmitValidationExempt') + FormAction::create('doSubmit'), + FormAction::create('doSubmitValidationExempt'), + FormAction::create('doSubmitActionExempt') + ->setValidationExempt(true) ), new RequiredFields( 'Email', @@ -797,6 +821,11 @@ class FormTest_Controller extends Controller implements TestOnly { return $this->redirectBack(); } + public function doSubmitActionExempt($data, $form, $request) { + $form->sessionMessage('Validation bypassed!', 'good'); + return $this->redirectBack(); + } + public function getViewer($action = null) { return new SSViewer('BlankPage'); }