main
Robert 2 months ago
parent f76f5f99eb
commit 6103aaf0d7
  1. 214
      src/classes/attributes/validators/my_validator.php
  2. 21
      src/classes/http/request.php
  3. 2
      src/classes/parameter_bag.php
  4. 15
      src/classes/traits/Macroable.php
  5. 154
      src/classes/traits/form_validator.php
  6. 138
      src/classes/validator.php

@ -0,0 +1,214 @@
<?php
declare(strict_types=1);
/**
* @author Robert Strutts <Bob_586@Yahoo.com>
* @copyright (c) 2025, Robert Strutts
* @license MIT
*/
namespace CodeHydrater\attributes\validators;
use \Attribute;
#[Attribute(Attribute::TARGET_PROPERTY)]
class Positive {}
#[Attribute(Attribute::TARGET_PROPERTY)]
class Required {}
#[Attribute(Attribute::TARGET_PROPERTY)]
class Email {}
#[Attribute(Attribute::TARGET_PROPERTY)]
class Min {
public function __construct(public int|float $value) {}
}
#[Attribute(Attribute::TARGET_PROPERTY)]
class Max {
public function __construct(public int|float $value) {}
}
#[Attribute(Attribute::TARGET_PROPERTY)]
class GreaterThan {
public function __construct(public int|float $value) {}
}
#[Attribute(Attribute::TARGET_PROPERTY)]
class LessThan {
public function __construct(public int|float $value) {}
}
#[Attribute(Attribute::TARGET_PROPERTY)]
class NumberRange {
public function __construct(
public int|float $min,
public int|float $max
) {}
}
#[Attribute(Attribute::TARGET_PROPERTY)]
class Between {
public function __construct(
public int|float $min,
public int|float $max
) {}
}
#[Attribute(Attribute::TARGET_PROPERTY)]
class Same {
public function __construct(public string $other) {}
}
#[Attribute(Attribute::TARGET_PROPERTY)]
class Alphanumeric {}
#[Attribute(Attribute::TARGET_PROPERTY)]
class Secure {}
#[Attribute(Attribute::TARGET_PROPERTY)]
class ValidEmailDomain {}
#[Attribute(Attribute::TARGET_PROPERTY)]
class ValidDomain {}
class my_validator {
use \CodeHydrater\traits\form_validator;
private array $errors = [];
private function handle_errors(string $rule_name, string $name, $value, $params = [], array $messages = []) {
// get the message rules
$rule_messages = array_filter($messages, fn($message) => is_string($message));
// overwrite the default message
$validation_errors = array_merge(self::DEFAULT_VALIDATION_ERRORS, $rule_messages);
$fn = 'is_' . $rule_name;
$field = $name;
$data[$name] = $value;
$callable = self::class . "::{$fn}";
$string_params = array_map('strval', $params);
if (is_callable($callable)) {
$pass = $callable($data, $field, ...$string_params);
if (!$pass) {
$lookfor = $messages[$field][$rule_name] ?? $validation_errors[$rule_name];
$new_params = array_values($params);
$this->errors[$field] = sprintf(
$lookfor,
$field,
...$params
);
}
}
}
public function validate(object $object, array $messages = []): void {
$handlers = [
Positive::class => function (string $name, $value, $attr, array $messages) {
$this->handle_errors("positive", $name, $value, messages: $messages);
},
Required::class => function (string $name, $value, $attr, array $messages) {
$this->handle_errors("required", $name, $value, messages: $messages);
},
Email::class => function (string $name, $value, $attr, array $messages) {
$this->handle_errors("email", $name, $value, messages: $messages);
},
GreaterThan::class => function (string $name, $value, $attr, array $messages) {
$params[] = $attr->value;
$this->handle_errors("greater_than", $name, $value, $params, $messages);
},
LessThan::class => function (string $name, $value, $attr, array $messages) {
$params[] = $attr->value;
$this->handle_errors("less_than", $name, $value, $params, $messages);
},
Min::class => function (string $name, $value, $attr, array $messages) {
$params[] = $attr->value;
$this->handle_errors("min", $name, $value, $params, $messages);
},
Max::class => function (string $name, $value, $attr, array $messages) {
$params[] = $attr->value;
$this->handle_errors("max", $name, $value, $params, $messages);
},
NumberRange::class => function (string $name, $value, $attr, array $messages) {
$params[] = $attr->min;
$params[] = $attr->max;
$this->handle_errors("number_range", $name, $value, $params, $messages);
},
Between::class => function (string $name, $value, $attr, array $messages) {
$params[] = $attr->min;
$params[] = $attr->max;
$this->handle_errors("between", $name, $value, $params, $messages);
},
Same::class => function (string $name, $value, $attr, array $messages) {
$params[] = $attr->value;
$this->handle_errors("same", $name, $value, $params, $messages);
},
Alphanumeric::class => function (string $name, $value, $attr, array $messages) {
$this->handle_errors("alphanumeric", $name, $value, messages: $messages);
},
Secure::class => function (string $name, $value, $attr, array $messages) {
$this->handle_errors("secure", $name, $value, messages: $messages);
},
ValidEmailDomain::class => function (string $name, $value, $attr, array $messages) {
$this->handle_errors("valid_email_domain", $name, $value, messages: $messages);
},
ValidDomain::class => function (string $name, $value, $attr, array $messages) {
$this->handle_errors("valid_domain", $name, $value, messages: $messages);
},
];
$ref = new \ReflectionObject($object);
foreach ($ref->getProperties() as $property) {
$name = $property->getName();
$property->setAccessible(true);
$value = $property->getValue($object);
foreach ($property->getAttributes() as $attribute) {
$class = $attribute->getName();
if (!isset($handlers[$class])) {
continue;
}
$message = $handlers[$class](
$name,
$value,
$attribute->newInstance(),
$messages
);
if ($message) {
$this->errors[$name][] = $message;
}
}
}
}
public function get_errors(): array {
return $this->errors;
}
}

@ -13,21 +13,14 @@ use CodeHydrater\parameter_bag;
class request {
use \CodeHydrater\traits\Macroable;
protected $query_params = [];
protected $post_data = [];
protected $server = [];
protected $cookies = [];
protected $files = [];
protected $headers = [];
public function __construct(
$query_params = [],
$post_data = [],
$server = [],
$cookies = [],
$files = [],
$headers = []
protected $query_params = [],
protected $post_data = [],
protected $server = [],
protected $cookies = [],
protected $files = [],
protected $headers = []
) {
$this->query_params = new parameter_bag($query_params);
$this->post_data = new parameter_bag($post_data);

@ -15,7 +15,7 @@ namespace CodeHydrater;
* @author Robert Strutts <Bob_586@Yahoo.com>
*/
class parameter_bag {
public function __construct(private array $parameters = []) { }
public function __construct(readonly private array $parameters = []) { }
public function get($key, $default = null) {
return $this->parameters[$key] ?? $default;

@ -2,31 +2,27 @@
namespace CodeHydrater\traits;
trait Macroable
{
trait Macroable {
protected static array $macros = [];
/**
* Register a custom macro.
*/
public static function macro(string $name, mixed $macro): void
{
public static function macro(string $name, mixed $macro): void {
static::$macros[$name] = $macro;
}
/**
* Checks if macro is registered.
*/
public static function hasMacro(string $name): bool
{
public static function hasMacro(string $name): bool {
return isset(static::$macros[$name]);
}
/**
* Dynamically handle calls to the class.
*/
public function __call(string $method, mixed $parameters): mixed
{
public function __call(string $method, mixed $parameters): mixed {
if (!static::hasMacro($method)) {
throw new \BadMethodCallException("Method {$method} does not exist.");
}
@ -43,8 +39,7 @@ trait Macroable
/**
* Dynamically handle static calls to the class.
*/
public static function __callStatic(string $method, mixed $parameters): mixed
{
public static function __callStatic(string $method, mixed $parameters): mixed {
if (!static::hasMacro($method)) {
throw new \BadMethodCallException("Method {$method} does not exist.");
}

@ -0,0 +1,154 @@
<?php
declare(strict_types=1);
/**
* @author Robert Strutts <Bob_586@Yahoo.com>
* @copyright (c) 2025, Robert Strutts
* @license MIT
*/
namespace CodeHydrater\traits;
use \CodeHydrater\common;
trait form_validator {
const DEFAULT_VALIDATION_ERRORS = [
'positive' => 'The %s is not a positive number',
'required' => 'Please enter the %s',
'email' => 'The %s is not a valid email address',
'less_than' => 'The %s number must be less than %d',
'greater_than' => 'The %s number must be greater than %d',
'number_range' => 'The %s number must be in range of %d to %d',
'min' => 'The %s must have at least %s characters',
'max' => 'The %s must have at most %s characters',
'between' => 'The %s must have between %d and %d characters',
'same' => 'The %s must match with %s',
'alphanumeric' => 'The %s should have only letters and numbers',
'secure' => 'The %s must have between 8 and 64 characters and contain at least one number, one upper case letter, one lower case letter and one special character',
'valid_email_domain' => 'The %s email address is not active',
'valid_domain' => 'The %s domain name is not active',
];
private static function is_positive(array $data, string $field): bool {
return (intval($data[$field]) >= 0) ? true : false;
}
private static function is_required(array $data, string $field): bool {
if (isset($data[$field])) {
if (common::get_count($data[$field])) {
return false; // Should not be an array here
}
if (is_string($data[$field])) {
return (trim($data[$field]) !== '');
}
if (is_int($data[$field])) {
return true;
}
}
return false;
}
private static function is_email(array $data, string $field): bool {
if (empty($data[$field])) {
return true;
}
return (filter_var($data[$field], FILTER_VALIDATE_EMAIL) === false) ? false : true;
}
private static function is_min(array $data, string $field, string $min): bool {
if (!isset($data[$field])) {
return true;
}
return mb_strlen($data[$field]) >= intval($min);
}
private static function is_max(array $data, string $field, string $max): bool {
if (!isset($data[$field])) {
return true;
}
return mb_strlen($data[$field]) <= intval($max);
}
private static function is_greater_than(array $data, string $field, string $min): bool {
if (!isset($data[$field])) {
return true;
}
return intval($data[$field]) > intval($min);
}
private static function is_less_than(array $data, string $field, string $max): bool {
if (!isset($data[$field])) {
return true;
}
return intval($data[$field]) < intval($max);
}
private static function is_number_range(array $data, string $field, string $min, string $max): bool {
if (!isset($data[$field])) {
return true;
}
$no = intval($data[$field]);
return $no >= intval($min) && $no <= intval($max);
}
private static function is_between(array $data, string $field, string $min, string $max): bool {
if (!isset($data[$field])) {
return true;
}
$len = mb_strlen($data[$field]);
return $len >= intval($min) && $len <= intval($max);
}
private static function is_same(array $data, string $field, string $other): bool {
if (isset($data[$field]) && isset($data[$other])) {
return $data[$field] === $data[$other];
}
return false;
}
private static function is_alphanumeric(array $data, string $field): bool {
if (!isset($data[$field])) {
return true;
}
return ctype_alnum($data[$field]);
}
private static function is_secure(array $data, string $field): bool {
if (!isset($data[$field])) {
return false;
}
// Is 8 to 64 CHRs
$pattern = "#.*^(?=.{8,64})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\W).*$#";
return preg_match($pattern, $data[$field]);
}
private static function is_valid_email_domain(array $data, string $field): bool {
if (!isset($data[$field])) {
return false;
}
$domain = ltrim(stristr($data[$field], '@'), '@') . '.';
return checkdnsrr($domain, 'MX');
}
private static function is_valid_domain(array $data, string $field): bool {
if (!isset($data[$field])) {
return false;
}
return checkdnsrr($data[$field], 'A')
|| checkdnsrr($data[$field], 'AAAA')
|| checkdnsrr($data[$field], 'CNAME');
}
}

@ -10,22 +10,8 @@ declare(strict_types=1);
namespace CodeHydrater;
class validator {
const DEFAULT_VALIDATION_ERRORS = [
'required' => 'Please enter the %s',
'email' => 'The %s is not a valid email address',
'less_than' => 'The %s number must be less than %d',
'greater_than' => 'The %s number must be greater than %d',
'number_range' => 'The %s number must be in range of %d to %d',
'min' => 'The %s must have at least %s characters',
'max' => 'The %s must have at most %s characters',
'between' => 'The %s must have between %d and %d characters',
'same' => 'The %s must match with %s',
'alphanumeric' => 'The %s should have only letters and numbers',
'secure' => 'The %s must have between 8 and 64 characters and contain at least one number, one upper case letter, one lower case letter and one special character',
'valid_email_domain' => 'The %s email address is not active',
'valid_domain' => 'The %s domain name is not active',
];
use \CodeHydrater\traits\form_validator;
private static function make_arrays(array $data, $field): array {
$dataset = [];
@ -84,8 +70,9 @@ class validator {
if (!$pass) {
// get the error message for a specific field and rule if exists
// otherwise get the error message from the $validation_errors
$lookfor = $messages[$field][$rule_name] ?? $validation_errors[$rule_name];
$errors[$field] = sprintf(
$messages[$field][$rule_name] ?? $validation_errors[$rule_name],
$lookfor,
$field,
...$params
);
@ -97,123 +84,6 @@ class validator {
return $errors;
}
private static function is_required(array $data, string $field): bool {
if (isset($data[$field])) {
if (common::get_count($data[$field])) {
return false; // Should not be an array here
}
if (is_string($data[$field])) {
return (trim($data[$field]) !== '');
}
if (is_int($data[$field])) {
return true;
}
}
return false;
}
private static function is_email(array $data, string $field): bool {
if (empty($data[$field])) {
return true;
}
return filter_var($data[$field], FILTER_VALIDATE_EMAIL);
}
private static function is_min(array $data, string $field, string $min): bool {
if (!isset($data[$field])) {
return true;
}
return mb_strlen($data[$field]) >= intval($min);
}
private static function is_max(array $data, string $field, string $max): bool {
if (!isset($data[$field])) {
return true;
}
return mb_strlen($data[$field]) <= intval($max);
}
private static function is_greater_than(array $data, string $field, string $min): bool {
if (!isset($data[$field])) {
return true;
}
return intval($data[$field]) > intval($min);
}
private static function is_less_than(array $data, string $field, string $max): bool {
if (!isset($data[$field])) {
return true;
}
return intval($data[$field]) < intval($max);
}
private static function is_number_range(array $data, string $field, string $min, string $max): bool {
if (!isset($data[$field])) {
return true;
}
$no = intval($data[$field]);
return $no >= intval($min) && $no <= intval($max);
}
private static function is_between(array $data, string $field, string $min, string $max): bool {
if (!isset($data[$field])) {
return true;
}
$len = mb_strlen($data[$field]);
return $len >= intval($min) && $len <= intval($max);
}
private static function is_same(array $data, string $field, string $other): bool {
if (isset($data[$field]) && isset($data[$other])) {
return $data[$field] === $data[$other];
}
return false;
}
private static function is_alphanumeric(array $data, string $field): bool {
if (!isset($data[$field])) {
return true;
}
return ctype_alnum($data[$field]);
}
private static function is_secure(array $data, string $field): bool {
if (!isset($data[$field])) {
return false;
}
// Is 8 to 64 CHRs
$pattern = "#.*^(?=.{8,64})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\W).*$#";
return preg_match($pattern, $data[$field]);
}
private static function is_valid_email_domain(array $data, string $field): bool {
if (!isset($data[$field])) {
return false;
}
$domain = ltrim(stristr($data[$field], '@'), '@') . '.';
return checkdnsrr($domain, 'MX');
}
private static function is_valid_domain(array $data, string $field): bool {
if (!isset($data[$field])) {
return false;
}
return checkdnsrr($data[$field], 'A')
|| checkdnsrr($data[$field], 'AAAA')
|| checkdnsrr($data[$field], 'CNAME');
}
}
/*

Loading…
Cancel
Save