Replace CMSForm use with new setValidationResponseCallback() API

Preparing for form schema API, see https://github.com/silverstripe/silverstripe-framework/issues/4938
This commit is contained in:
Ingo Schommer 2016-03-01 16:15:15 +13:00
parent 404ac4ae43
commit 746322a9f1
5 changed files with 56 additions and 62 deletions

View File

@ -1,52 +0,0 @@
<?php
/**
* Deals with special form handling in CMS, mainly around
* {@link PjaxResponseNegotiator}
*
* @package framework
* @subpackage admin
*/
class CMSForm extends Form {
/**
* Route validation error responses through response negotiator,
* so they return the correct markup as expected by the requesting client.
*/
protected function getValidationErrorResponse() {
$request = $this->getRequest();
$negotiator = $this->getResponseNegotiator();
if($request->isAjax() && $negotiator) {
$this->setupFormErrors();
$result = $this->forTemplate();
return $negotiator->respond($request, array(
'CurrentForm' => function() use($result) {
return $result;
}
));
} else {
return parent::getValidationErrorResponse();
}
}
/**
* Sets the response negotiator
* @param ResponseNegotiator $negotiator The response negotiator to use
* @return Form The current form
*/
public function setResponseNegotiator($negotiator) {
$this->responseNegotiator = $negotiator;
return $this;
}
/**
* Gets the current response negotiator
* @return ResponseNegotiator|null
*/
public function getResponseNegotiator() {
return $this->responseNegotiator;
}
}

View File

@ -13,6 +13,8 @@ use SilverStripe\Forms\Schema\FormSchema;
* *
* This is essentially an abstract class which should be subclassed. * This is essentially an abstract class which should be subclassed.
* See {@link CMSMain} for a good example. * See {@link CMSMain} for a good example.
*
* @property FormSchema $schema
*/ */
class LeftAndMain extends Controller implements PermissionProvider { class LeftAndMain extends Controller implements PermissionProvider {
@ -197,7 +199,7 @@ class LeftAndMain extends Controller implements PermissionProvider {
} }
// Make sure it's an AJAX GET request with a valid "X-Formschema-Request" header value. // Make sure it's an AJAX GET request with a valid "X-Formschema-Request" header value.
if (!$req->isAjax() || !$req->isGET() || !count($schemaParts)) { if (!$req->isGET() || !count($schemaParts)) {
throw new SS_HTTPResponse_Exception( throw new SS_HTTPResponse_Exception(
'Invalid request. Check you\'ve set a "X-Formschema-Request" header with "schema" or "state" values.', 'Invalid request. Check you\'ve set a "X-Formschema-Request" header with "schema" or "state" values.',
400 400
@ -1312,14 +1314,27 @@ class LeftAndMain extends Controller implements PermissionProvider {
$actionsFlattened = $actions->dataFields(); $actionsFlattened = $actions->dataFields();
if($actionsFlattened) foreach($actionsFlattened as $action) $action->setUseButtonTag(true); if($actionsFlattened) foreach($actionsFlattened as $action) $action->setUseButtonTag(true);
$form = CMSForm::create( $negotiator = $this->getResponseNegotiator();
$form = Form::create(
$this, "EditForm", $fields, $actions $this, "EditForm", $fields, $actions
)->setHTMLID('Form_EditForm'); )->setHTMLID('Form_EditForm');
$form->setResponseNegotiator($this->getResponseNegotiator());
$form->addExtraClass('cms-edit-form'); $form->addExtraClass('cms-edit-form');
$form->loadDataFrom($record); $form->loadDataFrom($record);
$form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); $form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
$form->setAttribute('data-pjax-fragment', 'CurrentForm'); $form->setAttribute('data-pjax-fragment', 'CurrentForm');
$form->setValidationResponseCallback(function() use ($negotiator, $form) {
$request = $this->getRequest();
if($request->isAjax() && $negotiator) {
$form->setupFormErrors();
$result = $form->forTemplate();
return $negotiator->respond($request, array(
'CurrentForm' => function() use($result) {
return $result;
}
));
}
});
// Announce the capability so the frontend can decide whether to allow preview or not. // Announce the capability so the frontend can decide whether to allow preview or not.
if(in_array('CMSPreviewable', class_implements($record))) { if(in_array('CMSPreviewable', class_implements($record))) {
@ -1368,7 +1383,7 @@ class LeftAndMain extends Controller implements PermissionProvider {
* @return Form * @return Form
*/ */
public function EmptyForm() { public function EmptyForm() {
$form = CMSForm::create( $form = Form::create(
$this, $this,
"EditForm", "EditForm",
new FieldList( new FieldList(
@ -1387,7 +1402,6 @@ class LeftAndMain extends Controller implements PermissionProvider {
), ),
new FieldList() new FieldList()
)->setHTMLID('Form_EditForm'); )->setHTMLID('Form_EditForm');
$form->setResponseNegotiator($this->getResponseNegotiator());
$form->unsetValidator(); $form->unsetValidator();
$form->addExtraClass('cms-edit-form'); $form->addExtraClass('cms-edit-form');
$form->addExtraClass('root-form'); $form->addExtraClass('root-form');

View File

@ -138,13 +138,12 @@ abstract class ModelAdmin extends LeftAndMain {
$listField->getConfig()->getComponentByType('GridFieldDetailForm')->setValidator($detailValidator); $listField->getConfig()->getComponentByType('GridFieldDetailForm')->setValidator($detailValidator);
} }
$form = CMSForm::create( $form = Form::create(
$this, $this,
'EditForm', 'EditForm',
new FieldList($listField), new FieldList($listField),
new FieldList() new FieldList()
)->setHTMLID('Form_EditForm'); )->setHTMLID('Form_EditForm');
$form->setResponseNegotiator($this->getResponseNegotiator());
$form->addExtraClass('cms-edit-form cms-panel-padded center'); $form->addExtraClass('cms-edit-form cms-panel-padded center');
$form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); $form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
$editFormAction = Controller::join_links($this->Link($this->sanitiseClassName($this->modelClass)), 'EditForm'); $editFormAction = Controller::join_links($this->Link($this->sanitiseClassName($this->modelClass)), 'EditForm');

View File

@ -177,13 +177,12 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider {
$actions = new FieldList(); $actions = new FieldList();
$form = CMSForm::create( $form = Form::create(
$this, $this,
'EditForm', 'EditForm',
$fields, $fields,
$actions $actions
)->setHTMLID('Form_EditForm'); )->setHTMLID('Form_EditForm');
$form->setResponseNegotiator($this->getResponseNegotiator());
$form->addExtraClass('cms-edit-form'); $form->addExtraClass('cms-edit-form');
$form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); $form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
// Tab nav in CMS is rendered through separate template // Tab nav in CMS is rendered through separate template

View File

@ -79,6 +79,11 @@ class Form extends RequestHandler {
*/ */
protected $validator; protected $validator;
/**
* @var callable {@see setValidationResponseCallback()}
*/
protected $validationResponseCallback;
/** /**
* @var string * @var string
*/ */
@ -479,16 +484,45 @@ class Form extends RequestHandler {
); );
} }
/**
* @return callable
*/
public function getValidationResponseCallback() {
return $this->validationResponseCallback;
}
/**
* Overrules validation error behaviour in {@link httpSubmission()}
* when validation has failed. Useful for optional handling of a certain accepted content type.
*
* The callback can opt out of handling specific responses by returning NULL,
* in which case the default form behaviour will kick in.
*
* @param $callback
* @return self
*/
public function setValidationResponseCallback($callback) {
$this->validationResponseCallback = $callback;
return $this;
}
/** /**
* Returns the appropriate response up the controller chain * Returns the appropriate response up the controller chain
* if {@link validate()} fails (which is checked prior to executing any form actions). * if {@link validate()} fails (which is checked prior to executing any form actions).
* By default, returns different views for ajax/non-ajax request, and * By default, returns different views for ajax/non-ajax request, and
* handles 'application/json' requests with a JSON object containing the error messages. * handles 'application/json' requests with a JSON object containing the error messages.
* Behaviour can be influenced by setting {@link $redirectToFormOnValidationError}. * Behaviour can be influenced by setting {@link $redirectToFormOnValidationError},
* and can be overruled by setting {@link $validationResponseCallback}.
* *
* @return SS_HTTPResponse|string * @return SS_HTTPResponse|string
*/ */
protected function getValidationErrorResponse() { protected function getValidationErrorResponse() {
$callback = $this->getValidationResponseCallback();
if($callback && $callbackResponse = $callback()) {
return $callbackResponse;
}
$request = $this->getRequest(); $request = $this->getRequest();
if($request->isAjax()) { if($request->isAjax()) {
// Special case for legacy Validator.js implementation // Special case for legacy Validator.js implementation