mirror of
https://codeberg.org/reflect/reflect-rules-plugin.git
synced 2025-09-14 00:43:42 +02:00
feat: eval whole ruleset and return error enum name
This commit is contained in:
parent
69d5fff1c2
commit
dee16f7fbb
2 changed files with 29 additions and 72 deletions
|
@ -2,14 +2,10 @@
|
||||||
|
|
||||||
namespace ReflectRules;
|
namespace ReflectRules;
|
||||||
|
|
||||||
use \victorwesterlund\xEnum;
|
|
||||||
|
|
||||||
use \ReflectRules\Scope;
|
use \ReflectRules\Scope;
|
||||||
|
|
||||||
// Supported types for is_type()
|
// Supported types for is_type()
|
||||||
enum Type {
|
enum Type {
|
||||||
use xEnum;
|
|
||||||
|
|
||||||
case NULL;
|
case NULL;
|
||||||
case ENUM;
|
case ENUM;
|
||||||
case ARRAY;
|
case ARRAY;
|
||||||
|
|
|
@ -13,61 +13,33 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Error {
|
enum Error {
|
||||||
case UNKNOWN_PROPERTY_NAME;
|
|
||||||
case MISSING_REQUIRED_PROPERTY;
|
|
||||||
case INVALID_PROPERTY_TYPE;
|
|
||||||
case VALUE_MIN_ERROR;
|
case VALUE_MIN_ERROR;
|
||||||
case VALUE_MAX_ERROR;
|
case VALUE_MAX_ERROR;
|
||||||
|
case INVALID_PROPERTY_TYPE;
|
||||||
|
case INVALID_PROPERTY_VALUE;
|
||||||
|
case MISSING_REQUIRED_PROPERTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Ruleset {
|
class Ruleset {
|
||||||
// Array of arrays with failed constraints
|
// Array of arrays with failed constraints
|
||||||
private array $errors = [];
|
private array $errors = [];
|
||||||
|
|
||||||
// Aggregated rules for GET and POST
|
|
||||||
private array $rules_get = [];
|
|
||||||
private array $rules_post = [];
|
|
||||||
|
|
||||||
public function __construct() {}
|
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
|
// 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
|
// Create sub array if this is the first error in this scope
|
||||||
if (!array_key_exists($scope->name, $this->errors)) {
|
if (!array_key_exists($scope->name, $this->errors)) {
|
||||||
$this->errors[$scope->name] = [];
|
$this->errors[$scope->name] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create sub array if this is the first error for this property
|
// Create sub array if this is the first error for this property
|
||||||
if (!array_key_exists($name, $this->errors[$scope->name])) {
|
if (!array_key_exists($property, $this->errors[$scope->name])) {
|
||||||
$this->errors[$scope->name][$name] = [];
|
$this->errors[$scope->name][$property] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->errors[$scope->name][$name][] = [
|
// Set expected value value for property in scope
|
||||||
"scope" => $scope->name,
|
$this->errors[$scope->name][$property][$error->name] = $expected;
|
||||||
"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}'");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate Rules against a given value
|
// Evaluate Rules against a given value
|
||||||
|
@ -82,7 +54,7 @@
|
||||||
return;
|
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
|
// Get value from scope for the current property
|
||||||
|
@ -93,59 +65,48 @@
|
||||||
The error messages will be returned
|
The error messages will be returned
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Value is not of the correct type or enum value
|
||||||
if ($rules->types && !$rules->eval_type($value, $scope)) {
|
if ($rules->types && !$rules->eval_type($value, $scope)) {
|
||||||
// List names of each allowed type
|
if (!$rules->enum) {
|
||||||
$types = implode(" or ", array_map(fn($type): string => $type->name, $rules->types));
|
// Get type names from enum
|
||||||
|
$types = array_map(fn(Type $type): string => $type->name, $rules->types);
|
||||||
|
|
||||||
// List allowed enum values
|
$this->add_error(Error::INVALID_PROPERTY_TYPE, $scope, $name, $types);
|
||||||
if ($rules->enum) {
|
} else {
|
||||||
$values = implode(" or ", array_map(fn($value): string => "'{$value}'", $rules->enum));
|
$this->add_error(Error::INVALID_PROPERTY_VALUE, $scope, $name, $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, "Value must be of type {$types}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($rules->min && !$rules->eval_min($value, $scope)) {
|
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)) {
|
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)
|
// Perform request processing on GET properties (search parameters)
|
||||||
public function GET(array $rules): void {
|
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)
|
// Perform request processing on POST properties (request body)
|
||||||
public function POST(array $rules): void {
|
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 is_valid(): bool {
|
||||||
public function eval(): true|array {
|
return empty($this->errors);
|
||||||
$this->eval_property_name_diff($this->rules_get, Scope::GET);
|
}
|
||||||
$this->eval_property_name_diff($this->rules_post, Scope::POST);
|
|
||||||
|
|
||||||
$is_valid_get = $this->eval_all_rules($this->rules_get, Scope::GET);
|
public function get_errors(): array {
|
||||||
$is_valid_post = $this->eval_all_rules($this->rules_post, Scope::POST);
|
return $this->errors;
|
||||||
|
|
||||||
$is_valid = $is_valid_get && $is_valid_post;
|
|
||||||
|
|
||||||
return $is_valid ? true : $this->errors;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue