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

Commit a6d6533

Browse files
committed
feat: added core validator
1 parent 1808a7b commit a6d6533

9 files changed

Lines changed: 272 additions & 1 deletion

composer.json

Lines changed: 2 additions & 1 deletion
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

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

src/Factory.php

Lines changed: 27 additions & 0 deletions
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

Lines changed: 20 additions & 0 deletions
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

Lines changed: 17 additions & 0 deletions
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);
17+
}

src/StaticValidatorInterface.php

Lines changed: 10 additions & 0 deletions
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

Lines changed: 81 additions & 0 deletions
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($ruleName, $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, '');
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(string $name, RuleInterface $rule): self
76+
{
77+
$this->rules[$name] = $rule;
78+
79+
return $this;
80+
}
81+
}

0 commit comments

Comments
 (0)