feat: coerce bool primitive from strings

This commit is contained in:
Victor Westerlund 2023-11-20 15:00:46 +01:00
parent d14d4bca6a
commit cf1111b98d
2 changed files with 65 additions and 20 deletions

View file

@ -4,6 +4,8 @@
use \victorwesterlund\xEnum;
use \ReflectRules\Scope;
// Supported types for is_type()
enum Type {
use xEnum;
@ -80,17 +82,60 @@
Methods are not called until all rules have been defined.
*/
public function eval_required(array $scope): bool {
return array_key_exists($this->property, $scope);
private function eval_type_boolean(mixed $value, Scope $scope): bool {
// 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) {
Type::NUMBER => is_numeric($value),
Type::STRING => is_string($value),
Type::BOOLEAN => is_bool($value),
Type::ARRAY => is_array($value),
Type::OBJECT => $this->eval_object($value),
Type::BOOLEAN => $this->eval_type_boolean($value, $scope),
Type::ARRAY,
Type::OBJECT => is_array($value),
Type::NULL => is_null($value),
default => true
};
@ -115,9 +160,4 @@
default => true
};
}
// TODO: Recursive Rules eval of multidimensional object
public function eval_object(mixed $object): bool {
return is_array($object);
}
}

View file

@ -11,6 +11,12 @@
require_once "Rules.php";
// Available superglobal scopes
enum Scope: string {
case GET = "_GET";
case POST = "_POST";
}
class Ruleset {
// This plugin will return exit with a Reflect\Response if errors are found
private bool $exit_on_errors;
@ -52,14 +58,12 @@
}
// 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();
// Check if property name exists in 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
if (!$rules->required) {
return;
@ -68,14 +72,15 @@
$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.
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}'");
}
@ -89,7 +94,7 @@
}
// 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) {
$this->eval_rules($rule, $scope);
}
@ -103,7 +108,7 @@
public function GET(array $rules): true|array|Response {
$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
if (!$is_valid && $this->exit_on_errors) {
@ -117,7 +122,7 @@
public function POST(array $rules): true|array|Response {
$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
if (!$is_valid && $this->exit_on_errors) {