refactor(Validator): improve rule argument parsing
This commit is contained in:
@@ -66,6 +66,30 @@ class Validator
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits a single rule string into its name and its raw argument string.
|
||||
*
|
||||
* The rule name is everything before the first ':'. The remainder is
|
||||
* returned verbatim (it is NOT split further here) so that rules whose
|
||||
* arguments legitimately contain ':' or ',' - such as regex or mimes -
|
||||
* are preserved intact. The caller decides how to split the arguments.
|
||||
*
|
||||
* @param string $rule The rule to parse. Ex: "regex:/^a,b$/" or "enum:a,b".
|
||||
*
|
||||
* @return array A two element array: [name, rawArguments]. When the rule
|
||||
* has no parameters, rawArguments is an empty string.
|
||||
*/
|
||||
public static function parseRule(string $rule): array
|
||||
{
|
||||
$separator = strpos($rule, ':');
|
||||
|
||||
if ($separator === false) {
|
||||
return [$rule, ''];
|
||||
}
|
||||
|
||||
return [substr($rule, 0, $separator), substr($rule, $separator + 1)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a rule is met.
|
||||
*
|
||||
@@ -77,15 +101,46 @@ class Validator
|
||||
*/
|
||||
public static function checkRule(mixed $subject, string $rule): bool
|
||||
{
|
||||
$arguments = preg_split('/[:,]/', $rule);
|
||||
$rule = [static::class, $arguments[0]];
|
||||
$arguments[0] = $subject;
|
||||
[$name, $rawArguments] = static::parseRule($rule);
|
||||
|
||||
if (is_callable($rule)) {
|
||||
return call_user_func_array($rule, $arguments);
|
||||
$method = [static::class, $name];
|
||||
$arguments = array_merge([$subject], static::splitArguments($name, $rawArguments));
|
||||
|
||||
if (is_callable($method)) {
|
||||
return call_user_func_array($method, $arguments);
|
||||
}
|
||||
|
||||
throw new Exception('Bad rule: "' . preg_split('/::/', $rule)[1] . '"');
|
||||
throw new Exception('Bad rule: "' . $name . '"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits a rule's raw argument string into the arguments to pass to the
|
||||
* rule's method (the subject is not included).
|
||||
*
|
||||
* Most rules take a comma-separated list of values (e.g. "enum:a,b").
|
||||
* A few rules receive an argument that must be kept intact because it can
|
||||
* legitimately contain commas or colons: "regex" (a pattern) and "not"
|
||||
* (a sub-rule that is itself parsed recursively). An empty argument string
|
||||
* yields no extra arguments.
|
||||
*
|
||||
* @param string $name The rule name.
|
||||
* @param string $raw The raw argument string as returned by parseRule().
|
||||
*
|
||||
* @return array The list of arguments to pass after the subject.
|
||||
*/
|
||||
private static function splitArguments(string $name, string $raw): array
|
||||
{
|
||||
if ($raw === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$intactRules = ['regex', 'not'];
|
||||
|
||||
if (in_array($name, $intactRules, true)) {
|
||||
return [$raw];
|
||||
}
|
||||
|
||||
return explode(',', $raw);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user