mirror of
https://codeberg.org/reflect/reflect-rules-plugin.git
synced 2025-09-14 08:53:42 +02:00
feat: coerce primitive boolean from strings for GET rules (#3)
* feat: coerce bool primitive from strings * fix(doc): GitHub md highliting
This commit is contained in:
parent
d14d4bca6a
commit
7fc27ff89c
3 changed files with 68 additions and 23 deletions
|
@ -114,7 +114,7 @@ Value|Coerced to
|
||||||
|
|
||||||
Any other value will cause the `type()` rule to fail.
|
Any other value will cause the `type()` rule to fail.
|
||||||
|
|
||||||
> **Note**
|
> [!IMPORTANT]
|
||||||
> This coercion is only applies for `Ruleset->GET()`. `Ruleset->POST()` will enforce real `true` and `type` values since it's JSON
|
> This coercion is only applies for `Ruleset->GET()`. `Ruleset->POST()` will enforce real `true` and `type` values since it's JSON
|
||||||
|
|
||||||
#### Null coercion from string for search parameters
|
#### Null coercion from string for search parameters
|
||||||
|
@ -122,7 +122,7 @@ Search parameters are read as strings, a null value is therefor coerced from an
|
||||||
|
|
||||||
Any value that isn't an empty string will cause the `type()` rule to fail.
|
Any value that isn't an empty string will cause the `type()` rule to fail.
|
||||||
|
|
||||||
> **Note**
|
> [!IMPORTANT]
|
||||||
> This coercion is only applies for `Ruleset->GET()`. `Ruleset->POST()` will enforce the real `null` value since it's JSON
|
> This coercion is only applies for `Ruleset->GET()`. `Ruleset->POST()` will enforce the real `null` value since it's JSON
|
||||||
|
|
||||||
## `min()`
|
## `min()`
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
use \victorwesterlund\xEnum;
|
use \victorwesterlund\xEnum;
|
||||||
|
|
||||||
|
use \ReflectRules\Scope;
|
||||||
|
|
||||||
// Supported types for is_type()
|
// Supported types for is_type()
|
||||||
enum Type {
|
enum Type {
|
||||||
use xEnum;
|
use xEnum;
|
||||||
|
@ -80,17 +82,60 @@
|
||||||
Methods are not called until all rules have been defined.
|
Methods are not called until all rules have been defined.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public function eval_required(array $scope): bool {
|
private function eval_type_boolean(mixed $value, Scope $scope): bool {
|
||||||
return array_key_exists($this->property, $scope);
|
// Coerce $value to bool primitive from string for GET parameters
|
||||||
|
if ($scope === Scope::GET) {
|
||||||
|
switch ($value) {
|
||||||
|
case "true":
|
||||||
|
case "1":
|
||||||
|
case "on":
|
||||||
|
case "yes":
|
||||||
|
$value = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "false":
|
||||||
|
case "0":
|
||||||
|
case "off":
|
||||||
|
case "no":
|
||||||
|
$value = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mutate value on superglobal from string to primitive
|
||||||
|
$GLOBALS[$scope->value][$this->property] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_bool($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function eval_type(mixed $value): bool {
|
/*
|
||||||
|
## Public eval methods
|
||||||
|
These are the entry-point eval methods that in turn can call other
|
||||||
|
helper methods for fine-graned validation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function eval_required(Scope $scope): bool {
|
||||||
|
$scope_data = &$GLOBALS[$scope->value];
|
||||||
|
|
||||||
|
if (array_key_exists($this->property, $scope_data)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Property does not exist in scope, create nulled superglobal for it
|
||||||
|
$scope_data[$this->property] = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function eval_type(mixed $value, Scope $scope): bool {
|
||||||
return match($this->type) {
|
return match($this->type) {
|
||||||
Type::NUMBER => is_numeric($value),
|
Type::NUMBER => is_numeric($value),
|
||||||
Type::STRING => is_string($value),
|
Type::STRING => is_string($value),
|
||||||
Type::BOOLEAN => is_bool($value),
|
Type::BOOLEAN => $this->eval_type_boolean($value, $scope),
|
||||||
Type::ARRAY => is_array($value),
|
Type::ARRAY,
|
||||||
Type::OBJECT => $this->eval_object($value),
|
Type::OBJECT => is_array($value),
|
||||||
Type::NULL => is_null($value),
|
Type::NULL => is_null($value),
|
||||||
default => true
|
default => true
|
||||||
};
|
};
|
||||||
|
@ -115,9 +160,4 @@
|
||||||
default => true
|
default => true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Recursive Rules eval of multidimensional object
|
|
||||||
public function eval_object(mixed $object): bool {
|
|
||||||
return is_array($object);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -11,6 +11,12 @@
|
||||||
|
|
||||||
require_once "Rules.php";
|
require_once "Rules.php";
|
||||||
|
|
||||||
|
// Available superglobal scopes
|
||||||
|
enum Scope: string {
|
||||||
|
case GET = "_GET";
|
||||||
|
case POST = "_POST";
|
||||||
|
}
|
||||||
|
|
||||||
class Ruleset {
|
class Ruleset {
|
||||||
// This plugin will return exit with a Reflect\Response if errors are found
|
// This plugin will return exit with a Reflect\Response if errors are found
|
||||||
private bool $exit_on_errors;
|
private bool $exit_on_errors;
|
||||||
|
@ -52,14 +58,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate Rules against a given value
|
// Evaluate Rules against a given value
|
||||||
private function eval_rules(Rules $rules, array &$scope): void {
|
private function eval_rules(Rules $rules, Scope $scope): void {
|
||||||
|
// Get the name of the current property being evaluated
|
||||||
$name = $rules->get_property_name();
|
$name = $rules->get_property_name();
|
||||||
|
|
||||||
// Check if property name exists in scope
|
// Check if property name exists in scope
|
||||||
if (!$rules->eval_required($scope)) {
|
if (!$rules->eval_required($scope)) {
|
||||||
// Set property name value on superglobal to null if not defined
|
|
||||||
$scope[$name] = null;
|
|
||||||
|
|
||||||
// Don't perform further processing if the property is optional and not provided
|
// Don't perform further processing if the property is optional and not provided
|
||||||
if (!$rules->required) {
|
if (!$rules->required) {
|
||||||
return;
|
return;
|
||||||
|
@ -68,14 +72,15 @@
|
||||||
$this->add_error($name, "Value can not be empty");
|
$this->add_error($name, "Value can not be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
$value = $scope[$name];
|
// Get value from scope for the current property
|
||||||
|
$value = $GLOBALS[$scope->value][$name];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Eval each rule that has been set.
|
Eval each rule that has been set.
|
||||||
The error messages will be returned
|
The error messages will be returned
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ($rules->type && !$rules->eval_type($value)) {
|
if ($rules->type && !$rules->eval_type($value, $scope)) {
|
||||||
$this->add_error($name, "Value must be of type '{$rules->type->name}'");
|
$this->add_error($name, "Value must be of type '{$rules->type->name}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +94,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate all Rules in this Ruleset against values in scope and return true if no errors were found
|
// 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, array &$scope): bool {
|
private function eval_all_rules(array $rules, Scope $scope): bool {
|
||||||
foreach ($rules as $rule) {
|
foreach ($rules as $rule) {
|
||||||
$this->eval_rules($rule, $scope);
|
$this->eval_rules($rule, $scope);
|
||||||
}
|
}
|
||||||
|
@ -103,7 +108,7 @@
|
||||||
public function GET(array $rules): true|array|Response {
|
public function GET(array $rules): true|array|Response {
|
||||||
$this->eval_property_name_diff($rules, array_keys($_GET));
|
$this->eval_property_name_diff($rules, array_keys($_GET));
|
||||||
|
|
||||||
$is_valid = $this->eval_all_rules($rules, $_GET);
|
$is_valid = $this->eval_all_rules($rules, Scope::GET);
|
||||||
|
|
||||||
// Return errors as a Reflect\Response
|
// Return errors as a Reflect\Response
|
||||||
if (!$is_valid && $this->exit_on_errors) {
|
if (!$is_valid && $this->exit_on_errors) {
|
||||||
|
@ -117,7 +122,7 @@
|
||||||
public function POST(array $rules): true|array|Response {
|
public function POST(array $rules): true|array|Response {
|
||||||
$this->eval_property_name_diff($rules, array_keys($_POST));
|
$this->eval_property_name_diff($rules, array_keys($_POST));
|
||||||
|
|
||||||
$is_valid = $this->eval_all_rules($rules, $_POST);
|
$is_valid = $this->eval_all_rules($rules, Scope::POST);
|
||||||
|
|
||||||
// Return errors as a Reflect\Response
|
// Return errors as a Reflect\Response
|
||||||
if (!$is_valid && $this->exit_on_errors) {
|
if (!$is_valid && $this->exit_on_errors) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue