parent
f76f5f99eb
commit
6103aaf0d7
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
@ -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'); |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue