inputs = $inputs; } /** * Valida um campo usando uma regra específica. */ public function validate(string $field, callable|string $rule, string $message = '', array $additionalParams = []): static { $value = $this->inputs[$field] ?? null; // Se for string, monta callable usando a própria classe if (is_string(value: $rule) && method_exists(object_or_class: self::class, method: $rule)) { $rule = [self::class, $rule]; } $params = array_merge([$value], $additionalParams); $result = call_user_func_array(callback: $rule, args: $params); // Caso seja validação de senha (retorna array) if (is_array(value: $result) && isset($result['valid'])) { if (!$result['valid']) { $this->errors[$field] = [ 'status' => 'is_invalid', 'message' => $result['errors'] ]; } } // Para outras validações booleanas elseif ($result === false) { $this->errors[$field] = [ 'status' => 'is_invalid', 'message' => $message ]; } return $this; } public function getErrors(): array { return $this->errors; } public function passes(): bool { return empty($this->errors); } // ---------- Regras comuns ---------- public static function validateEmail(string $value): bool { return (bool) filter_var(value: $value, filter: FILTER_VALIDATE_EMAIL); } public static function validatePhone(string $value, int $minLength = 10, int $maxLength = 13): bool { $digits = preg_replace(pattern: '/\D+/', replacement: '', subject: $value); $len = strlen(string: $digits); return $len >= $minLength && $len <= $maxLength; } public static function validateCpf(string $value): bool { $cpf = preg_replace(pattern: '/\D+/', replacement: '', subject: $value); if (strlen(string: $cpf) !== 11 || preg_match(pattern: '/(\d)\1{10}/', subject: $cpf)) { return false; } for ($t = 9; $t < 11; $t++) { $d = 0; for ($c = 0; $c < $t; $c++) { $d += $cpf[$c] * (($t + 1) - $c); } $d = ((10 * $d) % 11) % 10; if ($cpf[$c] != $d) { return false; } } return true; } public static function validateCnpj(string $value): bool { $cnpj = preg_replace(pattern: '/\D+/', replacement: '', subject: $value); if (strlen(string: $cnpj) != 14) { return false; } if (preg_match(pattern: '/(\d)\1{13}/', subject: $cnpj)) { return false; } $tamanho = 12; $multiplicadores = [5,4,3,2,9,8,7,6,5,4,3,2]; for ($i = 0; $i < 2; $i++) { $soma = 0; for ($j = 0; $j < $tamanho; $j++) { $soma += $cnpj[$j] * $multiplicadores[$j + ($i == 1 ? 1 : 0)]; } $digito = ($soma % 11 < 2) ? 0 : 11 - ($soma % 11); if ($cnpj[$tamanho] != $digito) { return false; } $tamanho++; } return true; } public static function notEmpty(mixed $value): bool { if (is_array(value: $value)) { return !empty(array_filter(array: $value, callback: fn($v) => $v !== null && $v !== '')); } return !empty(trim(string: (string) $value)); } public static function validatePassword(string $password, array $rules = []): array { $errors = []; $minLength = $rules['minLength'] ?? 8; $maxLength = $rules['maxLength'] ?? 64; $requireUpper = $rules['upper'] ?? true; $requireLower = $rules['lower'] ?? true; $requireDigit = $rules['digit'] ?? true; $requireSymbol = $rules['symbol'] ?? true; if (strlen(string: $password) < $minLength) { $errors[] = "Senha deve ter no mínimo {$minLength} caracteres."; } if (strlen(string: $password) > $maxLength) { $errors[] = "Senha deve ter no máximo {$maxLength} caracteres."; } if ($requireUpper && !preg_match(pattern: '/[A-Z]/', subject: $password)) { $errors[] = "Senha deve conter pelo menos uma letra maiúscula."; } if ($requireLower && !preg_match(pattern: '/[a-z]/', subject: $password)) { $errors[] = "Senha deve conter pelo menos uma letra minúscula."; } if ($requireDigit && !preg_match(pattern: '/\d/', subject: $password)) { $errors[] = "Senha deve conter pelo menos um número."; } if ($requireSymbol && !preg_match(pattern: '/[\W_]/', subject: $password)) { $errors[] = "Senha deve conter pelo menos um símbolo."; } return [ 'valid' => empty($errors), 'errors' => $errors ]; } public static function validateList(mixed $value, array $validOptions): bool { if (is_array(value: $value)) { foreach ($value as $item) { if (!in_array(needle: $item, haystack: $validOptions, strict: true)) { return false; } } return true; } return in_array(needle: $value, haystack: $validOptions, strict: true); } }