/** * validate * Run all the validation rules we have defined against a (hopefully * normalized) DonationInterface data set. * @param GatewayType $gateway * @param array $data Normalized donation data. * @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). * @throws BadMethodCallException * @return array An array of errors in a format ready for any derivative 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()) { //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. /** * We need to run the validation in an order that makes sense. * * 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). * * How about we build an array of shit to do, * look at it to make sure it's complete, and in order... * ...and do it. */ // Define all default validations. $validations = array('not_empty' => array('country', 'currency_code', 'gateway'), 'valid_type' => array('_cache_' => 'validate_boolean', 'account_number' => 'validate_numeric', 'anonymous' => 'validate_boolean', 'contribution_tracking_id' => 'validate_numeric', 'currency_code' => 'validate_alphanumeric', 'gateway' => 'validate_alphanumeric', 'numAttempt' => 'validate_numeric', 'optout' => 'validate_boolean', 'posted' => 'validate_boolean', 'recurring' => 'validate_boolean'), 'calculated' => array('gateway' => 'validate_gateway', 'address' => 'validate_address', 'city' => 'validate_address', 'country' => 'validate_country_allowed', 'email' => 'validate_email', 'street' => 'validate_address', 'currency_code' => 'validate_currency_code', 'fname' => 'validate_name', 'lname' => 'validate_name', 'name' => 'validate_name')); // 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(); $language = DataValidator::guessLanguage($data); if (empty($data['country'])) { $country = null; } else { $country = $data['country']; } foreach ($validations as $phase => $fields) { foreach ($fields as $key => $custom) { // Here we decode list vs map elements. if (is_numeric($key)) { $field = $custom; $validation_function = "validate_{$phase}"; } else { $field = $key; $validation_function = $custom; } if (!isset($data[$field])) { if ($phase !== 'not_empty') { // Skip if not required and nothing to validate. continue; } else { // Stuff with nothing. $data[$field] = null; } } // Skip if we've already determined this field group is invalid. $errorToken = self::getErrorToken($field); if (array_key_exists($errorToken, $errors)) { continue; } // Prepare to call the thing. $callable = array('DataValidator', $validation_function); if (!is_callable($callable)) { throw new BadMethodCallException(__FUNCTION__ . " BAD PROGRAMMER. No function {$validation_function} for {$field}"); } $result = null; // Handle special cases. switch ($validation_function) { case 'validate_currency_code': $result = call_user_func($callable, $data[$field], $gateway->getCurrencies($data)); break; default: $result = call_user_func($callable, $data[$field]); break; } // Store results. $results[$phase][$field] = $result; if ($result === false) { // We did the check, and it failed. $errors[$errorToken] = self::getErrorMessage($field, $phase, $language, $country); } } } return $errors; }