mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Form action validation excempts
Thanks to @kinglozzer for doing the majority of work on this. See #2493.
This commit is contained in:
parent
f17d594141
commit
5d1c355cad
@ -9,24 +9,6 @@
|
|||||||
*/
|
*/
|
||||||
class CMSForm extends Form {
|
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() {
|
|
||||||
$buttonClicked = $this->buttonClicked();
|
|
||||||
return (
|
|
||||||
($buttonClicked && in_array($buttonClicked->actionName(), $this->getValidationExemptActions()))
|
|
||||||
|| parent::validate()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Route validation error responses through response negotiator,
|
* Route validation error responses through response negotiator,
|
||||||
* so they return the correct markup as expected by the requesting client.
|
* so they return the correct markup as expected by the requesting client.
|
||||||
@ -49,25 +31,6 @@ 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
|
* Sets the response negotiator
|
||||||
* @param ResponseNegotiator $negotiator The response negotiator to use
|
* @param ResponseNegotiator $negotiator The response negotiator to use
|
||||||
|
@ -1,127 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package framework
|
|
||||||
* @subpackage tests
|
|
||||||
*/
|
|
||||||
class CMSFormTest extends FunctionalTest {
|
|
||||||
|
|
||||||
public function testValidationExemptActions() {
|
|
||||||
$response = $this->get('CMSFormTest_Controller');
|
|
||||||
|
|
||||||
$response = $this->submitForm(
|
|
||||||
'CMSForm_Form',
|
|
||||||
'action_doSubmit',
|
|
||||||
array(
|
|
||||||
'Email' => 'test@test.com'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Firstly, assert that required fields still work when not using an exempt action
|
|
||||||
$this->assertPartialMatchBySelector(
|
|
||||||
'#CMSForm_Form_SomeRequiredField_Holder 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(
|
|
||||||
'CMSForm_Form',
|
|
||||||
'action_doSubmitValidationExempt',
|
|
||||||
array(
|
|
||||||
'Email' => 'test@test.com'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// The required message should be empty if validation was skipped
|
|
||||||
$items = $this->cssParser()->getBySelector('#CMSForm_Form_SomeRequiredField_Holder span.required');
|
|
||||||
$this->assertEmpty($items);
|
|
||||||
|
|
||||||
// And the session message should show up is submitted successfully
|
|
||||||
$this->assertPartialMatchBySelector(
|
|
||||||
'#CMSForm_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');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -152,6 +152,11 @@ class Form extends RequestHandler {
|
|||||||
*/
|
*/
|
||||||
protected $attributes = array();
|
protected $attributes = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $validationExemptActions = array();
|
||||||
|
|
||||||
private static $allowed_actions = array(
|
private static $allowed_actions = array(
|
||||||
'handleField',
|
'handleField',
|
||||||
'httpSubmission',
|
'httpSubmission',
|
||||||
@ -581,6 +586,25 @@ class Form extends RequestHandler {
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert this form to another format.
|
* Convert this form to another format.
|
||||||
*/
|
*/
|
||||||
@ -1188,6 +1212,7 @@ class Form extends RequestHandler {
|
|||||||
*
|
*
|
||||||
* This includes form validation, if it fails, we redirect back
|
* This includes form validation, if it fails, we redirect back
|
||||||
* to the form with appropriate error messages.
|
* to the form with appropriate error messages.
|
||||||
|
* Always return true if the current form action is exempt from validation
|
||||||
*
|
*
|
||||||
* Triggered through {@link httpSubmission()}.
|
* Triggered through {@link httpSubmission()}.
|
||||||
*
|
*
|
||||||
@ -1197,6 +1222,11 @@ class Form extends RequestHandler {
|
|||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function validate(){
|
public function validate(){
|
||||||
|
$buttonClicked = $this->buttonClicked();
|
||||||
|
if($buttonClicked && in_array($buttonClicked->actionName(), $this->getValidationExemptActions())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if($this->validator){
|
if($this->validator){
|
||||||
$errors = $this->validator->validate();
|
$errors = $this->validator->validate();
|
||||||
|
|
||||||
@ -1535,7 +1565,10 @@ class Form extends RequestHandler {
|
|||||||
* @return FormAction
|
* @return FormAction
|
||||||
*/
|
*/
|
||||||
public function buttonClicked() {
|
public function buttonClicked() {
|
||||||
foreach($this->actions->dataFields() as $action) {
|
$actions = $this->actions->dataFields();
|
||||||
|
if(!$actions) return;
|
||||||
|
|
||||||
|
foreach($actions as $action) {
|
||||||
if($action->hasMethod('actionname') && $this->buttonClickedFunc == $action->actionName()) {
|
if($action->hasMethod('actionname') && $this->buttonClickedFunc == $action->actionName()) {
|
||||||
return $action;
|
return $action;
|
||||||
}
|
}
|
||||||
|
@ -228,6 +228,47 @@ class FormTest extends FunctionalTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testValidationExemptActions() {
|
||||||
|
$response = $this->get('FormTest_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(
|
||||||
|
'#Form_Form_SomeRequiredField_Holder .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('#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 skipped'
|
||||||
|
),
|
||||||
|
'Form->sessionMessage() shows up after reloading the form'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function testSessionValidationMessage() {
|
public function testSessionValidationMessage() {
|
||||||
$this->get('FormTest_Controller');
|
$this->get('FormTest_Controller');
|
||||||
|
|
||||||
@ -634,13 +675,15 @@ class FormTest_Controller extends Controller implements TestOnly {
|
|||||||
new CheckboxSetField('Boxes', null, array('1'=>'one','2'=>'two'))
|
new CheckboxSetField('Boxes', null, array('1'=>'one','2'=>'two'))
|
||||||
),
|
),
|
||||||
new FieldList(
|
new FieldList(
|
||||||
new FormAction('doSubmit')
|
new FormAction('doSubmit'),
|
||||||
|
new FormAction('doSubmitValidationExempt')
|
||||||
),
|
),
|
||||||
new RequiredFields(
|
new RequiredFields(
|
||||||
'Email',
|
'Email',
|
||||||
'SomeRequiredField'
|
'SomeRequiredField'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
$form->setValidationExemptActions(array('doSubmitValidationExempt'));
|
||||||
$form->disableSecurityToken(); // Disable CSRF protection for easier form submission handling
|
$form->disableSecurityToken(); // Disable CSRF protection for easier form submission handling
|
||||||
|
|
||||||
return $form;
|
return $form;
|
||||||
@ -651,6 +694,11 @@ class FormTest_Controller extends Controller implements TestOnly {
|
|||||||
return $this->redirectBack();
|
return $this->redirectBack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function doSubmitValidationExempt($data, $form, $request) {
|
||||||
|
$form->sessionMessage('Validation skipped', 'good');
|
||||||
|
return $this->redirectBack();
|
||||||
|
}
|
||||||
|
|
||||||
public function getViewer($action = null) {
|
public function getViewer($action = null) {
|
||||||
return new SSViewer('BlankPage');
|
return new SSViewer('BlankPage');
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user