From cf1111b98d8eed0f647de6622d89bee71f799525 Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Mon, 20 Nov 2023 15:00:46 +0100 Subject: [PATCH] feat: coerce bool primitive from strings --- src/Rules.php | 62 ++++++++++++++++++++++++++++++++++++++++--------- src/Ruleset.php | 23 +++++++++++------- 2 files changed, 65 insertions(+), 20 deletions(-) diff --git a/src/Rules.php b/src/Rules.php index 6e9d180..3512ec4 100644 --- a/src/Rules.php +++ b/src/Rules.php @@ -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); - } } \ No newline at end of file diff --git a/src/Ruleset.php b/src/Ruleset.php index 897f454..87b98c1 100644 --- a/src/Ruleset.php +++ b/src/Ruleset.php @@ -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) {