diff --git a/src/Rules.php b/src/Rules.php index 9be2f19..3958ec6 100644 --- a/src/Rules.php +++ b/src/Rules.php @@ -2,14 +2,10 @@ namespace ReflectRules; - use \victorwesterlund\xEnum; - use \ReflectRules\Scope; // Supported types for is_type() enum Type { - use xEnum; - case NULL; case ENUM; case ARRAY; diff --git a/src/Ruleset.php b/src/Ruleset.php index 44515c9..054b8cd 100644 --- a/src/Ruleset.php +++ b/src/Ruleset.php @@ -13,61 +13,33 @@ } enum Error { - case UNKNOWN_PROPERTY_NAME; - case MISSING_REQUIRED_PROPERTY; - case INVALID_PROPERTY_TYPE; case VALUE_MIN_ERROR; case VALUE_MAX_ERROR; + case INVALID_PROPERTY_TYPE; + case INVALID_PROPERTY_VALUE; + case MISSING_REQUIRED_PROPERTY; } class Ruleset { // Array of arrays with failed constraints private array $errors = []; - // Aggregated rules for GET and POST - private array $rules_get = []; - private array $rules_post = []; - public function __construct() {} - // Return property names for all Rules in array - private static function get_property_names(array $rules): array { - return array_map(fn(Rules $rule): string => $rule->get_property_name(), $rules); - } - - // ---- - // Append an error to the array of errors - private function add_error(Error $error, Scope $scope, string $name, string $message): void { + private function add_error(Error $error, Scope $scope, string $property, mixed $expected): void { // Create sub array if this is the first error in this scope if (!array_key_exists($scope->name, $this->errors)) { $this->errors[$scope->name] = []; } // Create sub array if this is the first error for this property - if (!array_key_exists($name, $this->errors[$scope->name])) { - $this->errors[$scope->name][$name] = []; + if (!array_key_exists($property, $this->errors[$scope->name])) { + $this->errors[$scope->name][$property] = []; } - $this->errors[$scope->name][$name][] = [ - "scope" => $scope->name, - "property_name" => $name, - "error_code" => $error->name, - "error_message" => $message - ]; - } - - private function eval_property_name_diff(array $rules, Scope $scope): void { - // Get array keys from superglobal - $keys = array_keys($GLOBALS[$scope->value]); - - // Get property names that aren't defiend in the ruleset - $invalid_names = array_diff($keys, self::get_property_names($rules)); - - // Add error for each invalid property name - foreach ($invalid_names as $invalid_name) { - $this->add_error(Error::UNKNOWN_PROPERTY_NAME, $scope, $invalid_name, "Unknown property name '{$invalid_name}'"); - } + // Set expected value value for property in scope + $this->errors[$scope->name][$property][$error->name] = $expected; } // Evaluate Rules against a given value @@ -82,7 +54,7 @@ return; } - $this->add_error(Error::MISSING_REQUIRED_PROPERTY, $scope, $name, "Value can not be empty"); + $this->add_error(Error::MISSING_REQUIRED_PROPERTY, $scope, $name, $name); } // Get value from scope for the current property @@ -93,59 +65,48 @@ The error messages will be returned */ + // Value is not of the correct type or enum value if ($rules->types && !$rules->eval_type($value, $scope)) { - // List names of each allowed type - $types = implode(" or ", array_map(fn($type): string => $type->name, $rules->types)); + if (!$rules->enum) { + // Get type names from enum + $types = array_map(fn(Type $type): string => $type->name, $rules->types); - // List allowed enum values - if ($rules->enum) { - $values = implode(" or ", array_map(fn($value): string => "'{$value}'", $rules->enum)); - $this->add_error(Error::INVALID_PROPERTY_TYPE, $scope, $name, "Value must be exactly: {$values}"); + $this->add_error(Error::INVALID_PROPERTY_TYPE, $scope, $name, $types); + } else { + $this->add_error(Error::INVALID_PROPERTY_VALUE, $scope, $name, $rules->enum); } - - $this->add_error(Error::INVALID_PROPERTY_TYPE, $scope, $name, "Value must be of type {$types}"); } if ($rules->min && !$rules->eval_min($value, $scope)) { - $this->add_error(Error::VALUE_MIN_ERROR, $scope, $name, "Value must be larger or equal to {$rules->min}"); + $this->add_error(Error::VALUE_MIN_ERROR, $scope, $name, $rules->min); } if ($rules->max && !$rules->eval_max($value, $scope)) { - $this->add_error(Error::VALUE_MAX_ERROR, $scope, $name, "Value must be smaller or equal to {$rules->max}"); + $this->add_error(Error::VALUE_MAX_ERROR, $scope, $name, $rules->max); } } - // Evaluate all Rules in this Ruleset against values in scope and return true if no errors were found - private function eval_all_rules(array $rules, Scope $scope): bool { - foreach ($rules as $rule) { - $this->eval_rules($rule, $scope); - } - - return empty($this->errors); - } - // ---- // Perform request processing on GET properties (search parameters) public function GET(array $rules): void { - array_merge($this->rules_get, $rules); + foreach ($rules as $rule) { + $this->eval_rules($rule, Scope::GET); + } } // Perform request processing on POST properties (request body) public function POST(array $rules): void { - array_merge($this->rules_post, $rules); + foreach ($rules as $rule) { + $this->eval_rules($rule, Scope::POST); + } } - // Evaluate all aggrgated rules - public function eval(): true|array { - $this->eval_property_name_diff($this->rules_get, Scope::GET); - $this->eval_property_name_diff($this->rules_post, Scope::POST); + public function is_valid(): bool { + return empty($this->errors); + } - $is_valid_get = $this->eval_all_rules($this->rules_get, Scope::GET); - $is_valid_post = $this->eval_all_rules($this->rules_post, Scope::POST); - - $is_valid = $is_valid_get && $is_valid_post; - - return $is_valid ? true : $this->errors; + public function get_errors(): array { + return $this->errors; } } \ No newline at end of file