From 28e7aabc69c1c4dcf694540130c66186dc3af2af Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Tue, 1 Mar 2016 16:15:15 +1300 Subject: [PATCH] Replace CMSForm use with new setValidationResponseCallback() API Preparing for form schema API, see https://github.com/silverstripe/silverstripe-framework/issues/4938 --- admin/code/CMSForm.php | 52 ------------------------------------ admin/code/LeftAndMain.php | 24 +++++++++++++---- admin/code/ModelAdmin.php | 3 +-- admin/code/SecurityAdmin.php | 3 +-- forms/Form.php | 36 ++++++++++++++++++++++++- 5 files changed, 56 insertions(+), 62 deletions(-) delete mode 100644 admin/code/CMSForm.php diff --git a/admin/code/CMSForm.php b/admin/code/CMSForm.php deleted file mode 100644 index 563a2d82121..00000000000 --- a/admin/code/CMSForm.php +++ /dev/null @@ -1,52 +0,0 @@ -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; - } - -} diff --git a/admin/code/LeftAndMain.php b/admin/code/LeftAndMain.php index a64dac490e5..f20e5acebde 100644 --- a/admin/code/LeftAndMain.php +++ b/admin/code/LeftAndMain.php @@ -13,6 +13,8 @@ * * This is essentially an abstract class which should be subclassed. * See {@link CMSMain} for a good example. + * + * @property FormSchema $schema */ class LeftAndMain extends Controller implements PermissionProvider { @@ -197,7 +199,7 @@ public function schema() { } // 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( 'Invalid request. Check you\'ve set a "X-Formschema-Request" header with "schema" or "state" values.', 400 @@ -1312,14 +1314,27 @@ public function getEditForm($id = null, $fields = null) { $actionsFlattened = $actions->dataFields(); if($actionsFlattened) foreach($actionsFlattened as $action) $action->setUseButtonTag(true); - $form = CMSForm::create( + $negotiator = $this->getResponseNegotiator(); + $form = Form::create( $this, "EditForm", $fields, $actions )->setHTMLID('Form_EditForm'); - $form->setResponseNegotiator($this->getResponseNegotiator()); $form->addExtraClass('cms-edit-form'); $form->loadDataFrom($record); $form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); $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. if(in_array('CMSPreviewable', class_implements($record))) { @@ -1368,7 +1383,7 @@ public function getEditForm($id = null, $fields = null) { * @return Form */ public function EmptyForm() { - $form = CMSForm::create( + $form = Form::create( $this, "EditForm", new FieldList( @@ -1387,7 +1402,6 @@ public function EmptyForm() { ), new FieldList() )->setHTMLID('Form_EditForm'); - $form->setResponseNegotiator($this->getResponseNegotiator()); $form->unsetValidator(); $form->addExtraClass('cms-edit-form'); $form->addExtraClass('root-form'); diff --git a/admin/code/ModelAdmin.php b/admin/code/ModelAdmin.php index cc41d7bce93..3ff8ef89c84 100644 --- a/admin/code/ModelAdmin.php +++ b/admin/code/ModelAdmin.php @@ -138,13 +138,12 @@ public function getEditForm($id = null, $fields = null) { $listField->getConfig()->getComponentByType('GridFieldDetailForm')->setValidator($detailValidator); } - $form = CMSForm::create( + $form = Form::create( $this, 'EditForm', new FieldList($listField), new FieldList() )->setHTMLID('Form_EditForm'); - $form->setResponseNegotiator($this->getResponseNegotiator()); $form->addExtraClass('cms-edit-form cms-panel-padded center'); $form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); $editFormAction = Controller::join_links($this->Link($this->sanitiseClassName($this->modelClass)), 'EditForm'); diff --git a/admin/code/SecurityAdmin.php b/admin/code/SecurityAdmin.php index cfbf4fe3dc0..923f9d4f9e8 100755 --- a/admin/code/SecurityAdmin.php +++ b/admin/code/SecurityAdmin.php @@ -177,13 +177,12 @@ public function getEditForm($id = null, $fields = null) { $actions = new FieldList(); - $form = CMSForm::create( + $form = Form::create( $this, 'EditForm', $fields, $actions )->setHTMLID('Form_EditForm'); - $form->setResponseNegotiator($this->getResponseNegotiator()); $form->addExtraClass('cms-edit-form'); $form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); // Tab nav in CMS is rendered through separate template diff --git a/forms/Form.php b/forms/Form.php index 112d8b3b703..0523c14a479 100644 --- a/forms/Form.php +++ b/forms/Form.php @@ -79,6 +79,11 @@ class Form extends RequestHandler { */ protected $validator; + /** + * @var callable {@see setValidationResponseCallback()} + */ + protected $validationResponseCallback; + /** * @var string */ @@ -479,16 +484,45 @@ public function checkAccessAction($action) { ); } + /** + * @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 * if {@link validate()} fails (which is checked prior to executing any form actions). * By default, returns different views for ajax/non-ajax request, and * 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 */ protected function getValidationErrorResponse() { + $callback = $this->getValidationResponseCallback(); + if($callback && $callbackResponse = $callback()) { + return $callbackResponse; + } + $request = $this->getRequest(); if($request->isAjax()) { // Special case for legacy Validator.js implementation