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