📜 ⬆️ ⬇️

AMatch, part 2. Error codes, own errors, new callback format

In this article I will talk about some of the innovations that have appeared in the AMatch project since the writing of the first article .

Let me remind you that AMatch is a class with which the validation of input parameters from a large set of if-s turns into a convenient, concise record. For example:

Example: simple
$match = AMatch::runMatch($params) ->doc_id(0, '<') //    ->subject_id(0, '!=') //    ; $result = $match->stopMatch(); if (!$result) { die(var_export($match->matchComments(), true)); //    } 

')

Input data


In the following examples, we will check the array in “good” and “bad” form:

Example: input data
 $params = array( 'subject_id' => '64', 'parent_id' => -32, 'delimeter' => '-4.645E+32', 'title' => 'New document', 'links' => array(13, '-16', 24), 'email' => 'someuser@mail.dom', ); $params_bad = array( 'subject_id' => '64.43', 'parent_id' => array(), 'delimeter' => '-4.x6E.32', 'title' => new stdClass(), 'links' => array(0, array(0, array(0)), 0), 'email' => 'someuser!@mail.dom', ); 


To check the test results, we write the function:

Example: result function
 function result(AMatch $match) { echo PHP_EOL; echo $match->stopMatch() ? 'Dance!' : 'Cry!' ; echo PHP_EOL; var_export($match->matchResults()); echo PHP_EOL; var_export($match->matchComments()); echo PHP_EOL; var_export($match->matchCommentsConditions()); } 


Bug work


In the first version, errors were given by string constants. This is quite enough to make your own mapping, but it was ugly. At the moment, errors made in a separate class AMatchStatus . This allowed us to do the following nice things:

Getting error codes

Let's make a simple condition of validation and send there consistently good and bad arrays.

Example: bad and good policeman
 $match = AMatch::runMatch($params, AMatch::FLAG_SHOW_GOOD_COMMENTS)->delimeter('', 'float'); //     result($match); $match = AMatch::runMatch($params_bad, AMatch::FLAG_SHOW_GOOD_COMMENTS)->delimeter('', 'float'); result($match); 

As a result, we get the following answer
 //   Dance! array ( 'delimeter' => 103, ) array ( 'delimeter' => 'OK. Expected parameter type is valid', ) array ( 'delimeter' => array ( 0 => '', 1 => 'float', ), ) //   Cry! array ( 'delimeter' => 3, ) array ( 'delimeter' => 'Expected parameter type is not valid', ) array ( 'delimeter' => array ( 0 => 'float', 1 => 'float', ), ) 


As can be seen from the example:
- matchResults () will return error codes,
- matchComments () - comments,
- matchCommentsConditions () - validation condition and additional information.

Additional information about float in AMatch
Note that float is not checked via is_float
// Valid float values:
1, -1, 1.0, -1.0, '1', '-1', '1.0', '-1.0', '2.1', '0', 0, '0', '0.1', '-0.0' , -0.0, 3., '-3.', '.27', .27, '-0', '+4', '1e2', '+1353.0316547', '13213.032468e-13465', '-8E +3 ',' -1354.98879e + 37436 '

// Valid values:
false, true, '', '-', '.a', '-1.a', '.a', '.', '-.', '1+', '1.3+', 'a1' , 'e.e', '-e-4', 'e2', '8e', '3.25', '1.1.1'


Mapping errors

Let's try to write a function that will make the output of errors "out" in accordance with some accepted standard within the existing code.

Example: mapping
 function mapping(AMatch $match) { //   $errors_mapping = array( AMatchStatus::KEY_TYPE_NOT_VALID => 'invalid_type', AMatchStatus::KEY_CONDITION_NOT_VALID => 'invalid_data', AMatchStatus::KEY_NOT_EXISTS => 'required', ); $results = $match->matchResults(); //    $comments = $match->matchComments(); //    $comments_conditions = $match->matchCommentsConditions(); //   $output = array(); foreach ($results as $param => $result) { $error = array_key_exists($result, $errors_mapping) ? $errors_mapping[$result] : 'other_errors'; // ,      $comment = $param . ': ' . $comments[$param]; if (isset($comments_conditions[$param]) && !empty($comments_conditions[$param][0])) { $comment .= ' (' . $comments_conditions[$param][0] . ')'; //   } $output[$error][] = $comment; } var_export($output); } $match = AMatch::runMatch($params_bad, AMatch::FLAG_SHOW_GOOD_COMMENTS | AMatch::FLAG_DONT_STOP_MATCHING) ->title('', 'string') //    string ->parent_id('', 'int') //    string ->ineedkey() //    ->subject_id(1, '>') // "1"    ->delimeter('', 'blabla') //    ; mapping($match); 


As a result of the execution of this code, an array will be obtained with the structure of errors that is usual for the code written earlier.

Result of the example "mapping"
 array ( 'invalid_type' => array ( 0 => 'title: Expected parameter type is not valid (string)', 1 => 'parent_id: Expected parameter type is not valid (int)', ), 'required' => array ( 0 => 'ineedkey: Expected parameter does not exist in the array of parameters', ), 'invalid_data' => array ( 0 => 'subject_id: Condition is not valid (1)', ), 'other_errors' => array ( 0 => 'delimeter: Condition is unknown', ), ) 



Own decoding of errors for any condition

In order for any condition to get its own error in the comments (in the case of failure of this condition), it is enough to pass the text to the third parameter. Add in the example described above (“mapping”) your text to the error:

Example: unique errors
 ... ->title('', 'string', 'Incorrect document title. Please, read FAQ.') ... 


And execute it again
 array ( 'other_errors' => array ( 0 => 'title: Incorrect document title. Please, read FAQ. (string)', 1 => 'delimeter: Condition is unknown', ), 


But to replace every condition is not always necessary. Sometimes you need to replace all comments.

Class substitution with errors (including i18n)

Let's go back to the mapping example again. To fully replace all the necessary errors, we will write a class-successor from AMatchStatus. Inside it is necessary to overload the _fillComments () method, not forgetting to call the parent. You need to create an object of this class and pass it to AMatch :: runMatch (); third parameter.

Example: russian
 class AMatchRussian extends AMatchStatus { protected function _fillComments() { parent::_fillComments(); //     ,         $this->_result_comments[self::KEY_NOT_EXISTS] = ',  .  '; $this->_result_comments[self::KEY_CONDITION_NOT_VALID] = '   ,   '; $this->_result_comments[self::CONDITION_IS_UNKNOWN] = ''; } } $match = AMatch::runMatch($params_bad, AMatch::FLAG_SHOW_GOOD_COMMENTS | AMatch::FLAG_DONT_STOP_MATCHING, new AMatchRussian()) // ...   ,     mapping ; mapping($match); 


The answer will contain translated constructions along with those that do not have a translation.
The result of the example "russian"
 array ( 'other_errors' => array ( 0 => 'title: Incorrect document title. Please, read FAQ. (string)', 1 => 'delimeter: ', ), 'invalid_type' => array ( 0 => 'parent_id: Expected parameter type is not valid (int)', ), 'required' => array ( 0 => 'ineedkey: ,  .  ', ), 'invalid_data' => array ( 0 => 'subject_id:    (1)', ), ) 



New callback features


In addition to tracking errors, work with user-defined functions has been somewhat improved. Let me remind you that earlier they could be called as follows:

 $match->data(array($this, 'callbackMethod'), 'callback'); 

Currently, callback support has been expanded, and now you can call as follows:

Example: callback
 // param([mixed $callback_argument], [callable|callable $callback]) //  // param([callable|string $callback], 'callback') // : ->param($callback_property, 'MyClass::myFunc') ->param($callback_property, 'MyClass->myFunc') ->param($callback_property, array($my_obj, 'myFunc')) ->param($callback_property, array('MyClass', 'myFunc')) 


Embedded callback plugins


Together with the library AMatch are examples of ready-made classes with methods that can be used as a user call. These are two classes:
  1. class AMatchArray
  2. class AMatchString

Consider usage examples:

Example: plugins
 function matchCallbacks($params) { $match = AMatch::runMatch($params, AMatch::FLAG_DONT_STOP_MATCHING) ->parent_id('/^-?\d+$/', 'AMatchString::pregMatch') //     ->title(12, 'AMatchString::length') //    ->email('([\w-]+@([\w-]+\.)+[\w-]+)', 'AMatchString::isEmail') //  email   (  ) ->links(AMatchArray::FLAG_EMPTY_SOME_ELEMENT, 'AMatchArray::isNotEmpty') //     :            - ; result($match); } matchCallbacks($params); matchCallbacks($params_bad); 


Result of the example "plugins"
 //   Dance! array ( ) array ( ) array ( ) //   Cry! array ( 'parent_id' => 'str3', 'title' => 'str5', 'email' => 'str4', 'links' => 'arr8', ) array ( 'parent_id' => 'The string does not match the regular expression', 'title' => 'String required', 'email' => 'Incorrect email', 'links' => 'At least one element of the array must be non-empty', ) array ( 'parent_id' => array ( 0 => '/^-?\\d+$/', 1 => 'AMatchString::pregMatch', ), 'title' => array ( 0 => 12, 1 => 'AMatchString::length', ), 'email' => array ( 0 => 'someuser!@mail.dom', 1 => 'AMatchString::isEmail', ), 'links' => array ( 0 => NULL, 1 => 'AMatchArray::isNotEmpty', ), ) 



After letter


The general scheme for calling AMatch is as follows:

 $match = AMatch::runMatch(array $associative_array, bitmask $flags, AMatchStatus $obj) ->_([___], []) ->…; $match->stopMatch(); //    $match->matchResults(); //    (   ,  ) $match->matchComments(); //   $match->matchCommentsConditions(); //    

You can find more examples (see unittests) and download the AMatch source on the githaba , where you will find a ready-made example file for this article (examples2.php).

UPD:
Converted to Composer .

Source: https://habr.com/ru/post/150039/


All Articles