From 969a95eff7d218fdf399b838dd77b3edf9d8583a Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Thu, 12 Mar 2009 16:47:29 +0000 Subject: [PATCH] BUGFIX Removed hardcoded field value removals in Form->validate() for creditcard info ENHANCEMENT Optionally returning JSON data or HTML form representations from Form submissions if Form->validate() fails (if HTTP Accept is set to 'application/json') ENHANCEMENT Limiting usage of prototype-validation responses in Form->validate() to form instances with $javascriptValidationHandler=='prototype' (which is the default setting). This enables us to return richer JSON data on validation errors without making assumptions about javascript methods on clientside through eval'ed responses (specifically Validator.js->validationError()) API CHANGE Deprecated Validator->getError() and Validator->getCombinedError(), use getErrors() instead git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@72979 467b73ca-7a2a-4603-9d3b-597d59a354a9 --- forms/Form.php | 31 +++++++++++++++++++------------ forms/Validator.php | 28 +++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/forms/Form.php b/forms/Form.php index 58fd3a639..a2adef1f5 100644 --- a/forms/Form.php +++ b/forms/Form.php @@ -195,7 +195,24 @@ class Form extends RequestHandler { // Validate the form if(!$this->validate()) { if(Director::is_ajax()) { - return FormResponse::respond(); + // Special case for legacy Validator.js implementation (assumes eval'ed javascript collected through FormResponse) + if($this->validator->getJavascriptValidationHandler() == 'prototype') { + return FormResponse::respond(); + } else { + $acceptType = $request->getHeader('Accept'); + if(strpos($acceptType, 'application/json') !== FALSE) { + // Send validation errors back as JSON with a flag at the start + $response = new HTTPResponse(Convert::array2json($this->validator->getErrors())); + $response->addHeader('Content-Type', 'application/json'); + } else { + $this->setupFormErrors(); + // Send the newly rendered form tag as HTML + $response = new HTTPResponse($this->forTemplate()); + $response->addHeader('Content-Type', 'text/html'); + } + + return $response; + } } else { Director::redirectBack(); return; @@ -760,18 +777,13 @@ class Form extends RequestHandler { * This includes form validation, if it fails, we redirect back * to the form with appropriate error messages. * Triggered through {@link httpSubmission()} which is triggered - * @usedby Form->httpSubmission() - * - * @todo Replace hardcoded exclude fields like CreditCardNumber with hook to specify sensitive fields in model */ function validate(){ if($this->validator){ $errors = $this->validator->validate(); if($errors){ - if(Director::is_ajax()) { - // Send validation errors back as JSON with a flag at the start - //echo "VALIDATIONERROR:" . Convert::array2json($errors); + if(Director::is_ajax() && $this->validator->getJavascriptValidationHandler() == 'prototype') { FormResponse::status_message(_t('Form.VALIDATIONFAILED', 'Validation failed'), 'bad'); foreach($errors as $error) { FormResponse::add(sprintf( @@ -781,14 +793,9 @@ class Form extends RequestHandler { Convert::raw2js($error['messageType']) )); } - return false; } else { $data = $this->getData(); - // People will get worried if you leave credit card information in session.. - if(isset($data['CreditCardNumber'])) unset($data['CreditCardNumber']); - if(isset($data['DateExpiry'])) unset($data['Expiry']); - // Load errors into session and post back Session::set("FormInfo.{$this->FormName()}", array( 'errors' => $errors, diff --git a/forms/Validator.php b/forms/Validator.php index 76c0aa61c..3cd447edd 100755 --- a/forms/Validator.php +++ b/forms/Validator.php @@ -113,9 +113,9 @@ abstract class Validator extends Object { * * @param $fieldName name of the field * @param $message error message to display - * @param $messageType optional parameter, gets loaded into the HTML class attribute in the rendered output + * @param $messageType optional parameter, gets loaded into the HTML class attribute in the rendered output. See {@link getErrors()} for details. */ - function validationError($fieldName,$message,$messageType=''){ + function validationError($fieldName, $message, $messageType='') { $this->errors[] = array( 'fieldName' => $fieldName, 'message' => $message, @@ -124,12 +124,15 @@ abstract class Validator extends Object { } /** - * @deprecated 2.4 Use Validator->getCombinedError() and custom code + * @deprecated 2.4 Use Validator->getErrors() and custom code */ function showError() { Debug::show($this->errors); } + /** + * @deprecated 2.4 Use custom code + */ function getCombinedError(){ if($this->errors) { foreach($this->errors as $error){ @@ -140,7 +143,26 @@ abstract class Validator extends Object { return $ret; } } + + /** + * @deprecated 2.4 Use getErrors() + */ function getError(){ + return $this->getErrors(); + } + + /** + * Returns all errors found by a previous call to {@link validate()}. + * The array contains the following keys for each error: + * - 'fieldName': the name of the FormField instance + * - 'message': Validation message (optionally localized) + * - 'messageType': Arbitrary type of the message which is rendered as a CSS class in the FormField template, + * e.g. . Usually "bad|message|validation|required", which renders differently + * if sapphire/css/Form.css is included. + * + * @return array + */ + function getErrors() { return $this->errors; }