diff --git a/admin/code/CMSForm.php b/admin/code/CMSForm.php index 2cc33807e..52dcda0d1 100644 --- a/admin/code/CMSForm.php +++ b/admin/code/CMSForm.php @@ -3,6 +3,23 @@ * Deals with special form handling in CMS, mainly around {@link PjaxResponseNegotiator} */ class CMSForm extends Form { + + /** + * @var array + */ + protected $validationExemptActions = array(); + + /** + * Always return true if the current form action is exempt from validation + * + * @return boolean + */ + public function validate() { + return ( + in_array($this->buttonClicked()->actionName(), $this->getValidationExemptActions()) + || parent::validate() + ); + } /** * Route validation error responses through response negotiator, @@ -19,6 +36,25 @@ class CMSForm extends Form { } } + /** + * Set actions that are exempt from validation + * + * @param array + */ + public function setValidationExemptActions($actions) { + $this->validationExemptActions = $actions; + return $this; + } + + /** + * Get a list of actions that are exempt from validation + * + * @return array + */ + public function getValidationExemptActions() { + return $this->validationExemptActions; + } + /** * Sets the response negotiator * @param ResponseNegotiator $negotiator The response negotiator to use diff --git a/admin/tests/CMSFormTest.php b/admin/tests/CMSFormTest.php new file mode 100644 index 000000000..6eb6767f1 --- /dev/null +++ b/admin/tests/CMSFormTest.php @@ -0,0 +1,127 @@ +get('CMSFormTest_Controller'); + + $response = $this->submitForm( + 'Form_Form', + 'action_doSubmit', + array( + 'Email' => 'test@test.com' + ) + ); + + // Firstly, assert that required fields still work when not using an exempt action + $this->assertPartialMatchBySelector( + '#SomeRequiredField span.required', + array( + '"Some Required Field" is required' + ), + 'Required fields show a notification on field when left blank' + ); + + // Re-submit the form using validation-exempt button + $response = $this->submitForm( + 'Form_Form', + 'action_doSubmitValidationExempt', + array( + 'Email' => 'test@test.com' + ) + ); + + // The required message should be empty if validation was skipped + $items = $this->cssParser()->getBySelector('#SomeRequiredField span.required'); + $this->assertEmpty($items); + + // And the session message should show up is submitted successfully + $this->assertPartialMatchBySelector( + '#Form_Form_error', + array( + 'Validation skipped' + ), + 'Form->sessionMessage() shows up after reloading the form' + ); + } + + public function testSetValidationExemptActions() { + $form = $this->getStubForm(); + + $form->setValidationExemptActions(array('exemptaction')); + $exemptActions = $form->getValidationExemptActions(); + $this->assertEquals('exemptaction', $exemptActions[0]); + } + + protected function getStubForm() { + $form = new CMSForm( + new CMSFormTest_Controller(), + 'CMSForm', + new FieldList(), + new FieldList() + ); + + return $form; + } + +} + +class CMSFormTest_Controller extends Controller implements TestOnly { + + private static $allowed_actions = array('Form'); + + private static $url_handlers = array( + '$Action//$ID/$OtherID' => "handleAction", + ); + + protected $template = 'BlankPage'; + + public function Link($action = null) { + return Controller::join_links('CMSFormTest_Controller', $this->request->latestParam('Action'), + $this->request->latestParam('ID'), $action); + } + + public function Form() { + $form = new CMSForm( + $this, + 'Form', + new FieldList( + new EmailField('Email'), + new TextField('SomeRequiredField'), + new CheckboxSetField('Boxes', null, array('1'=>'one','2'=>'two')) + ), + new FieldList( + new FormAction('doSubmit'), + new FormAction('doSubmitValidationExempt') + ), + new RequiredFields( + 'Email', + 'SomeRequiredField' + ) + ); + $form->setValidationExemptActions(array('doSubmitValidationExempt')); + $form->setResponseNegotiator('foo'); // We aren't testing AJAX responses, so just set anything + $form->disableSecurityToken(); // Disable CSRF protection for easier form submission handling + + return $form; + } + + public function doSubmit($data, $form, $request) { + $form->sessionMessage('Test save was successful', 'good'); + return $this->redirectBack(); + } + + public function doSubmitValidationExempt($data, $form, $request) { + $form->sessionMessage('Validation skipped', 'good'); + return $this->redirectBack(); + } + + public function getViewer($action = null) { + return new SSViewer('BlankPage'); + } + +} \ No newline at end of file diff --git a/forms/Form.php b/forms/Form.php index 2047a1160..537b36fd5 100644 --- a/forms/Form.php +++ b/forms/Form.php @@ -1380,8 +1380,10 @@ class Form extends RequestHandler { } public function buttonClicked() { - foreach($this->actions as $action) { - if($this->buttonClickedFunc == $action->actionName()) return $action; + foreach($this->actions->dataFields() as $action) { + if($action->hasMethod('actionname') && $this->buttonClickedFunc == $action->actionName()) { + return $action; + } } }