Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit 8c4ab65

Browse files
authored
Merge pull request #1 from programmatordev/YAPV-1-validator-core
Validator core
2 parents 1808a7b + d7d10aa commit 8c4ab65

9 files changed

+259
-1
lines changed

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
"php": ">=8.1"
1616
},
1717
"require-dev": {
18-
"phpunit/phpunit": "^10.0"
18+
"phpunit/phpunit": "^10.0",
19+
"symfony/var-dumper": "^6.3"
1920
},
2021
"autoload": {
2122
"psr-4": {

src/ChainedValidatorInterface.php

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\YetAnotherPhpValidator;
4+
5+
use ProgrammatorDev\YetAnotherPhpValidator\Exception\ValidationException;
6+
7+
interface ChainedValidatorInterface
8+
{
9+
// --- Common ---
10+
11+
public function validate(mixed $input): bool;
12+
13+
/**
14+
* @throws ValidationException
15+
*/
16+
public function assert(mixed $input, string $name): void;
17+
18+
// --- Rules ---
19+
20+
// public function notBlank(): ChainedValidatorInterface;
21+
//
22+
// public function greaterThan(mixed $constraint): ChainedValidatorInterface;
23+
}
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\YetAnotherPhpValidator\Exception;
4+
5+
class InvalidRuleException extends \Exception
6+
{
7+
protected $message = 'Invalid rule.';
8+
}

src/Exception/ValidationException.php

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\YetAnotherPhpValidator\Exception;
4+
5+
class ValidationException extends \Exception
6+
{
7+
public function __construct(string $message, array $parameters = [])
8+
{
9+
$message = $this->formatMessage($message, $parameters);
10+
parent::__construct($message);
11+
}
12+
13+
private function formatMessage(string $message, array $parameters = []): string
14+
{
15+
foreach ($parameters as $parameter => $value) {
16+
$message = str_replace("{{ $parameter }}", $this->formatValue($value), $message);
17+
}
18+
19+
return $message;
20+
}
21+
22+
private function formatValue(mixed $value): string
23+
{
24+
if ($value instanceof \DateTimeInterface) {
25+
return $value->format('Y-m-d H:i:s');
26+
}
27+
28+
if (\is_object($value)) {
29+
if ($value instanceof \Stringable) {
30+
return $value->__toString();
31+
}
32+
33+
return 'object';
34+
}
35+
36+
if (\is_array($value)) {
37+
return $this->formatValues($value);
38+
}
39+
40+
if (\is_string($value)) {
41+
return \sprintf('"%s"', $value);
42+
}
43+
44+
if (\is_resource($value)) {
45+
return 'resource';
46+
}
47+
48+
if ($value === null) {
49+
return 'null';
50+
}
51+
52+
if ($value === false) {
53+
return 'false';
54+
}
55+
56+
if ($value === true) {
57+
return 'true';
58+
}
59+
60+
return (string) $value;
61+
}
62+
63+
private function formatValues(array $values): string
64+
{
65+
foreach ($values as $key => $value) {
66+
$values[$key] = $this->formatValue($value);
67+
}
68+
69+
return \implode(', ', $values);
70+
}
71+
}

src/Factory.php

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\YetAnotherPhpValidator;
4+
5+
use ProgrammatorDev\YetAnotherPhpValidator\Exception\InvalidRuleException;
6+
use ProgrammatorDev\YetAnotherPhpValidator\Rule\RuleInterface;
7+
8+
class Factory
9+
{
10+
private string $namespace = 'ProgrammatorDev\\YetAnotherPhpValidator\\Rule';
11+
12+
/**
13+
* @throws InvalidRuleException
14+
*/
15+
public function createRule(string $ruleName, array $arguments = []): RuleInterface
16+
{
17+
try {
18+
$className = \sprintf('%s\\%s', $this->namespace, \ucfirst($ruleName));
19+
return new $className(...$arguments);
20+
}
21+
catch (\Error) {
22+
throw new InvalidRuleException(
23+
\sprintf('"%s" rule does not exist.', $ruleName)
24+
);
25+
}
26+
}
27+
}

src/Rule/AbstractRule.php

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\YetAnotherPhpValidator\Rule;
4+
5+
class AbstractRule
6+
{
7+
private string $name;
8+
9+
public function getName(): string
10+
{
11+
return $this->name;
12+
}
13+
14+
public function setName(string $name): static
15+
{
16+
$this->name = $name;
17+
18+
return $this;
19+
}
20+
}

src/Rule/RuleInterface.php

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\YetAnotherPhpValidator\Rule;
4+
5+
use ProgrammatorDev\YetAnotherPhpValidator\Exception\ValidationException;
6+
7+
interface RuleInterface
8+
{
9+
/**
10+
* @throws ValidationException
11+
*/
12+
public function validate(mixed $input): void;
13+
14+
public function getName(): string;
15+
16+
public function setName(string $name): static;
17+
}

src/StaticValidatorInterface.php

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\YetAnotherPhpValidator;
4+
5+
interface StaticValidatorInterface
6+
{
7+
// public static function notBlank(): ChainedValidatorInterface;
8+
//
9+
// public static function greaterThan(mixed $constraint): ChainedValidatorInterface;
10+
}

src/Validator.php

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\YetAnotherPhpValidator;
4+
5+
use ProgrammatorDev\YetAnotherPhpValidator\Exception\InvalidRuleException;
6+
use ProgrammatorDev\YetAnotherPhpValidator\Exception\ValidationException;
7+
use ProgrammatorDev\YetAnotherPhpValidator\Rule\RuleInterface;
8+
9+
/**
10+
* @mixin StaticValidatorInterface
11+
*/
12+
class Validator
13+
{
14+
private array $rules;
15+
16+
public function __construct(RuleInterface ...$rules)
17+
{
18+
$this->rules = $rules;
19+
}
20+
21+
private static function create(): self
22+
{
23+
return new self();
24+
}
25+
26+
/**
27+
* @throws InvalidRuleException
28+
*/
29+
public static function __callStatic(string $ruleName, array $arguments = []): self
30+
{
31+
return self::create()->__call($ruleName, $arguments);
32+
}
33+
34+
/**
35+
* @throws InvalidRuleException
36+
*/
37+
public function __call(string $ruleName, array $arguments = []): self
38+
{
39+
$factory = new Factory();
40+
$this->addRule($factory->createRule($ruleName, $arguments));
41+
42+
return $this;
43+
}
44+
45+
/**
46+
* @throws ValidationException
47+
*/
48+
public function assert(mixed $input, string $name): void
49+
{
50+
foreach ($this->getRules() as $rule) {
51+
$rule->setName($name)->validate($input);
52+
}
53+
}
54+
55+
public function validate(mixed $input): bool
56+
{
57+
try {
58+
$this->assert($input, 'null');
59+
}
60+
catch (ValidationException) {
61+
return false;
62+
}
63+
64+
return true;
65+
}
66+
67+
/**
68+
* @return RuleInterface[]
69+
*/
70+
private function getRules(): array
71+
{
72+
return $this->rules;
73+
}
74+
75+
private function addRule(RuleInterface $rule): self
76+
{
77+
$this->rules[] = $rule;
78+
79+
return $this;
80+
}
81+
}

0 commit comments

Comments
 (0)