Awight has uploaded a new change for review. https://gerrit.wikimedia.org/r/281084
Change subject: [WIP] Explore encapsulating validation along with transformations ...................................................................... [WIP] Explore encapsulating validation along with transformations I'm not sure which is more egregious, but this approach gives us several easy ways to modify the validations, even subclassing an existing validation. Change-Id: I011f094981510accdb7fb66d3b4292f6c9ae4de9 --- M gateway_common/DataValidator.php M gateway_common/DonationData.php M gateway_common/FiscalNumber.php A gateway_common/ValidationHelper.php M gateway_common/gateway.adapter.php M tests/DataValidatorTest.php 6 files changed, 103 insertions(+), 93 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/DonationInterface refs/changes/84/281084/1 diff --git a/gateway_common/DataValidator.php b/gateway_common/DataValidator.php index a6e2457..100b380 100644 --- a/gateway_common/DataValidator.php +++ b/gateway_common/DataValidator.php @@ -13,13 +13,6 @@ */ class DataValidator { - // because of the hacky way we test for translation existence in getErrorMessage, - // we need to explicitly specify which fields we want to try to get country- - // specific names for. - protected static $countrySpecificFields = array( - 'fiscal_number', - ); - /** * getErrorToken, intended to be used by classes that exist relatively close * to the form classes, returns the error token (defined on the forms) that @@ -43,7 +36,6 @@ case 'card_num': case 'card_type': case 'cvv': - case 'fiscal_number': case 'fname': case 'lname': case 'city': @@ -62,6 +54,7 @@ /** * getEmptyErrorArray + * @deprecated * This only exists anymore, to make badly-coded forms happy when they start * pulling keys all over the place without checking to see if they're set or * not. @@ -120,7 +113,7 @@ $error_message_field_key = 'donate_interface-error-msg-' . $message_field; - if ( $country !== null && in_array( $message_field, self::$countrySpecificFields ) ) { + if ( $country !== null ) { $translated_field_name = MessageUtils::getCountrySpecificMessage( $error_message_field_key, $country, $language ); } else if ( WmfFramework::messageExists( $error_message_field_key, $language ) ) { $translated_field_name = WmfFramework::formatMessage( $error_message_field_key ); @@ -181,17 +174,13 @@ * Run all the validation rules we have defined against a (hopefully * normalized) DonationInterface data set. * @param GatewayType $gateway - * @param array $data The DonationInterface data set, or a subset thereof. - * @param array $check_not_empty An array of fields to do empty validation - * on. If this is not populated, no fields will throw errors for being empty, - * UNLESS they are required for a field that uses them for more complex - * validation (the 'calculated' phase). + * @param array $data Normalized donation data. * @throws BadMethodCallException * @return array An array of errors in a format ready for any derivitive of * the main DonationInterface Form class to display. The array will be empty * if no errors were generated and everything passed OK. */ - public static function validate( GatewayType $gateway, $data, $check_not_empty = array() ){ + public static function validate( GatewayType $gateway, $data ) { //return the array of errors that should be generated on validate. //just the same way you'd do it if you were a form passing the error array around. @@ -201,12 +190,7 @@ * First: If we need to validate that some things are not empty, do that. * Second: Do regular data type validation on things that are not empty. * Third: Do validation that depends on multiple fields (making sure you - * validated that all the required fields exist on step 1, regardless of - * $check_not_empty) - * - * $check_not_empty should contain an array of values that need to be populated. - * One likely candidate for a source there, is the required stomp fields as defined in DonationData. - * Although, a lot of those don't have to have any data in them either. Boo. + * validated that all the required fields exist on step 1). * * How about we build an array of shit to do, * look at it to make sure it's complete, and in order... @@ -251,18 +235,8 @@ // Depends on currency_code and gateway. 'amount' => 'validate_amount', - - // Depends on country - 'fiscal_number' => 'validate_fiscal_number', ), ); - - // Additional fields we should check for emptiness. - if ( $check_not_empty ) { - $validations['not_empty'] = array_unique( array_merge( - $check_not_empty, $validations['not_empty'] - ) ); - } $errors = array(); $results = array(); @@ -318,9 +292,6 @@ break; case 'validate_currency_code': $result = call_user_func( $callable, $data[$field], $gateway->getCurrencies( $data ) ); - break; - case 'validate_fiscal_number': - $result = call_user_func( $callable, $data[$field], $data['country'] ); break; default: $result = call_user_func( $callable, $data[$field] ); @@ -595,61 +566,6 @@ ) { return false; } - return true; - } - - /** - * Rudimentary tests of fiscal number format for different countries - * @param string $value The alleged fiscal number - * @param array $country The country whose format we care about - * @return boolean True if the $value is a valid fiscal number, false otherwise - */ - public static function validate_fiscal_number( $value, $country ) { - $countryRules = array( - 'AR' => array( - 'numeric' => true, - 'min' => 8, - 'max' => 8, - ), - 'BR' => array( - 'numeric' => true, - 'min' => 11, - 'max' => 14, - ), - 'CO' => array( - 'numeric' => true, - 'min' => 11, - 'max' => 14, - ), - 'CL' => array( - 'min' => 8, - 'max' => 9, - ), - 'UY' => array( - 'numeric' => true, - 'min' => 6, - 'max' => 8, - ), - ); - - if ( !isset( $countryRules[$country] ) ) { - return true; - } - - $rules = $countryRules[$country]; - $unpunctuated = preg_replace( '/[^A-Za-z0-9]/', '', $value ); - - if ( !empty( $rules['numeric'] ) ) { - if ( !is_numeric( $unpunctuated ) ) { - return false; - } - } - - $length = strlen( $unpunctuated ); - if ( $length < $rules['min'] || $length > $rules['max'] ) { - return false; - } - return true; } diff --git a/gateway_common/DonationData.php b/gateway_common/DonationData.php index b426952..8171ba5 100644 --- a/gateway_common/DonationData.php +++ b/gateway_common/DonationData.php @@ -31,7 +31,7 @@ * places in the request, or 'false' to gather the data the usual way. * Default is false. */ - function __construct( $gateway, $data = false ) { + function __construct( GatewayType $gateway, $data = false ) { $this->gateway = $gateway; $this->gatewayID = $this->gateway->getIdentifier(); $this->logger = DonationLoggerFactory::getLogger( $gateway, '', $this ); @@ -958,9 +958,18 @@ * If it is not, it will return an array of errors ready for any * DonationInterface form class derivitive to display. */ - public function getValidationErrors( $recalculate = false, $check_not_empty = array() ){ + public function getValidationErrors( $recalculate = false ) { if ( is_null( $this->validationErrors ) || $recalculate ) { - $this->validationErrors = DataValidator::validate( $this->gateway, $this->normalized, $check_not_empty ); + // Run legacy validations + $this->validationErrors = DataValidator::validate( $this->gateway, $this->normalized ); + + // Run modular validations. FIXME: Move this... somewhere. + $transformers = $this->gateway->getDataTransformers(); + foreach ( $transformers as $transformer ) { + if ( $transformer instanceof ValidationHelper ) { + $transformer->validate( $this->normalized, $this->validationErrors ); + } + } } return $this->validationErrors; } diff --git a/gateway_common/FiscalNumber.php b/gateway_common/FiscalNumber.php index 3fe8cec..cfd616e 100644 --- a/gateway_common/FiscalNumber.php +++ b/gateway_common/FiscalNumber.php @@ -18,4 +18,69 @@ $stagedData['fiscal_number'] = preg_replace( '/[^a-zA-Z0-9]/', '', $unstagedData['fiscal_number'] ); } } + + /** + * Rudimentary tests of fiscal number format for different countries + * @param string $value The alleged fiscal number + * @param array $country The country whose format we care about + * @return boolean True if the $value is a valid fiscal number, false otherwise + */ + public function validate( $normalized, &$errors ) { + if ( !isset( $normalized['country'] ) ) { + return; + } + $value = $normalized['fiscal_number']; + $country = $normalized['country']; + $has_error = false; + + $countryRules = array( + 'AR' => array( + 'numeric' => true, + 'min' => 8, + 'max' => 8, + ), + 'BR' => array( + 'numeric' => true, + 'min' => 11, + 'max' => 14, + ), + 'CO' => array( + 'numeric' => true, + 'min' => 11, + 'max' => 14, + ), + 'CL' => array( + 'min' => 8, + 'max' => 9, + ), + 'UY' => array( + 'numeric' => true, + 'min' => 6, + 'max' => 8, + ), + ); + + if ( !isset( $countryRules[$country] ) ) { + return; + } + + $rules = $countryRules[$country]; + $unpunctuated = preg_replace( '/[^A-Za-z0-9]/', '', $value ); + + if ( !empty( $rules['numeric'] ) ) { + if ( !is_numeric( $unpunctuated ) ) { + $has_error = true; + } + } + + $length = strlen( $unpunctuated ); + if ( $length < $rules['min'] || $length > $rules['max'] ) { + $has_error = true; + } + + if ( $has_error ) { + // This looks bad. + $errors['fiscal_number'] = DataValidator::getErrorMessage( 'fiscal_number', 'calculated', $normalized['language'], $country ); + } + } } diff --git a/gateway_common/ValidationHelper.php b/gateway_common/ValidationHelper.php new file mode 100644 index 0000000..8926315 --- /dev/null +++ b/gateway_common/ValidationHelper.php @@ -0,0 +1,9 @@ +<?php + +interface ValidationHelper { + /** + * Run validation on whatever normalized data we're responsible for, + * and set errors per field, or under the "general" key. + */ + function validate( $normalized, &$errors ); +} diff --git a/gateway_common/gateway.adapter.php b/gateway_common/gateway.adapter.php index 5bbb267..f902667 100644 --- a/gateway_common/gateway.adapter.php +++ b/gateway_common/gateway.adapter.php @@ -362,6 +362,11 @@ } } + // FIXME: Not convinced we need this. + public function getDataTransformers() { + return $this->data_transformers; + } + /** * Determine which account to use for this session */ diff --git a/tests/DataValidatorTest.php b/tests/DataValidatorTest.php index c106ac7..651444e 100644 --- a/tests/DataValidatorTest.php +++ b/tests/DataValidatorTest.php @@ -132,6 +132,12 @@ * @dataProvider fiscalNumberProvider */ public function testValidateFiscalNumber( $country, $value, $valid ) { - $this->assertEquals( $valid, DataValidator::validate_fiscal_number( $value, $country ) ); + $validator = new FiscalNumber(); + $errors = array(); + $validator->validate( + array( 'country' => $country, 'fiscal_number' => $value, 'language' => 'en' ), + $errors + ); + $this->assertEquals( $valid, empty( $errors['fiscal_number'] ) ); } } -- To view, visit https://gerrit.wikimedia.org/r/281084 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I011f094981510accdb7fb66d3b4292f6c9ae4de9 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/DonationInterface Gerrit-Branch: master Gerrit-Owner: Awight <awi...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits