Skip to content

Commit 656ab1d

Browse files
committed
Recursive Validator added
1 parent f364996 commit 656ab1d

File tree

13 files changed

+195
-40
lines changed

13 files changed

+195
-40
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"email": "[email protected]"
1010
}
1111
],
12-
"version": "2.5.1",
12+
"version": "2.6",
1313
"require": {
1414
"php": ">=8.1",
1515
"anshu-krishna/php-utilities": "^1.0"

examples/index.php

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
namespace ExampleApp;
33
require_once '../vendor/autoload.php';
44

5-
use Krishna\DataValidator\MultiLinedException;
5+
use Krishna\DataValidator\ComplexException;
6+
use Krishna\DataValidator\RecursiveValidator;
67
use Krishna\DataValidator\Returner;
8+
use Krishna\DataValidator\RngFmt\AllowedValues;
79
use Krishna\DataValidator\TypeHandler;
810
use Krishna\DataValidator\TypeInterface;
11+
use Krishna\DataValidator\Types\StringType;
912
use Krishna\DataValidator\Validator;
1013

1114
$rng_50 = strval(new \Krishna\DataValidator\RngFmt\Num\Range(max: 50));
@@ -27,6 +30,19 @@ public static function validate($value, bool $allow_null = false) : Returner {
2730
return Returner::valid('my_type3_' . strval($value));
2831
}
2932
}
33+
class MyStringType implements TypeInterface {
34+
public static function validate($value, bool $allow_null = false) : Returner {
35+
$value = StringType::validate($value);
36+
if(!$value->valid) {
37+
return $value;
38+
}
39+
$value = explode('.', $value->value);
40+
return Returner::valid([
41+
'head' => $value[0],
42+
'body' => $value[1] ?? ''
43+
]);
44+
}
45+
}
3046

3147
TypeHandler::set_custom_type_class('my_type1', MyType1::class);
3248
TypeHandler::set_multiple_custom_type_class([
@@ -56,6 +72,39 @@ public static function validate($value, bool $allow_null = false) : Returner {
5672
} else {
5773
echo "<pre>Error:\n", $error ,"</pre>";
5874
}
59-
} catch (MultiLinedException $th) {
75+
} catch (ComplexException $th) {
76+
var_dump($th->getInfo());
77+
}
78+
79+
echo '<hr />';
80+
81+
// Testing recursive validator
82+
try {
83+
$dv = (new RecursiveValidator(MyStringType::class, step_title: 'Token to array'))
84+
->then([
85+
'head' => 'json64',
86+
'body' => 'json64'
87+
], step_title: 'Base64 JSON decode')
88+
->then([
89+
'head' => [
90+
'alg' => 'string@' . new AllowedValues('HS256', 'HS384', 'HS512', 'RS256', 'RS384', 'RS512'),
91+
'typ' => 'string@' . new AllowedValues('JWT')
92+
],'body' => [
93+
'?iss' => 'string',
94+
'?sub' => 'string|null',
95+
'?aud' => 'string',
96+
'?exp' => 'unsigned',
97+
'?nbf' => 'unsigned',
98+
'?iat' => 'unsigned',
99+
'?kid' => 'unsigned'
100+
]
101+
], step_title: "Test structure of 'head' & 'body'");
102+
['valid' => $valid, 'value' => $data, 'error' => $error] = $dv->validate('eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b2tlbi50ZXN0LmNvbSIsImF1ZCI6ImFwcC50b2tlbi5jb20iLCJpYXQiOjE2NDM4OTE3NTgsIm5iZiI6MTY0Mzg5MTc1OCwiZXhwIjoxNjQzODkyMzU4LCJuYW1lIjoiQW5zaHUgS3Jpc2huYSIsImNpdHkiOiJCYW5nYWxvcmUifQ')->get_as_array();
103+
if($valid) {
104+
var_dump(['Data' => $data]);
105+
} else {
106+
echo "<pre>Error on step '{$error['step']}' =&gt; ", $error['msg']->getFormattedErrors('; ') ,"</pre>";
107+
}
108+
} catch (ComplexException $th) {
60109
var_dump($th->getInfo());
61110
}

src/ArrayHandler.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@ public function __construct(array $list, public readonly OutOfBoundAction $on_ou
1313
is_string($item) => new TypeHandler($item),
1414
is_array($item) => new static($item, $this->on_out_of_bound),
1515
is_object($item) => new ObjectHandler($item, $this->on_out_of_bound),
16-
default => throw new MultiLinedException('{' . strval($item) . '}; Invalid value', $i)
16+
default => throw new ComplexException('{' . strval($item) . '}; Invalid value', $i)
1717
};
18-
} catch(MultiLinedException $th) {
18+
} catch(ComplexException $th) {
1919
foreach($th->getInfo() as $m) {
2020
$error[] = "[{$i}]: {$m}";
2121
}
2222
}
2323
}
2424
if(count($error) > 0) {
25-
throw new MultiLinedException($error);
25+
throw new ComplexException($error);
2626
}
2727
$this->list = $list;
2828
$this->single = count($this->list) === 1;
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
namespace Krishna\DataValidator;
33

4-
class MultiLinedException extends \Exception {
4+
class ComplexException extends \Exception {
55
private array $info = [];
66
public function __construct(array|string $message, ?string $prefix = null, int $code = 0, ?\Throwable $previous = null) {
77
parent::__construct('Use getInfo() for messages', $code, $previous);
@@ -20,4 +20,7 @@ public function getInfo() :array {
2020
public function __toString(): string {
2121
return $this->message;
2222
}
23+
public function getFormattedErrors(string $seperator = ', ') : string {
24+
return implode($seperator, $this->info);
25+
}
2326
}

src/ErrorReader.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,7 @@ public function __toString() : string {
2323
public function __debugInfo() {
2424
return $this->errors;
2525
}
26+
public function getFormattedErrors(string $seperator = ', ') : string {
27+
return implode($seperator, $this->errors);
28+
}
2629
}

src/ObjectHandler.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,17 @@ public function __construct(object $list, public readonly OutOfBoundAction $on_o
2121
is_string($item) => new TypeHandler($item),
2222
is_array($item) => new ArrayHandler($item, $this->on_out_of_bound),
2323
is_object($item) => new static($item, $this->on_out_of_bound),
24-
default => throw new MultiLinedException('{' . strval($item) . '}; Invalid value', $key)
24+
default => throw new ComplexException('{' . strval($item) . '}; Invalid value', $key)
2525
};
2626
$ret_list[$key] = $info;
27-
} catch (MultiLinedException $th) {
27+
} catch (ComplexException $th) {
2828
foreach($th->getInfo() as $m) {
2929
$error[] = "[{$key}]: {$m}";
3030
}
3131
}
3232
}
3333
if(count($error) > 0) {
34-
throw new MultiLinedException($error);
34+
throw new ComplexException($error);
3535
}
3636
$this->list = $ret_list;
3737
}

src/RecursiveValidator.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
namespace Krishna\DataValidator;
3+
4+
class RecursiveValidator {
5+
private $steps = [];
6+
private $titles = [];
7+
public function __construct(
8+
TypeHandler|string|array $struct,
9+
OutOfBoundAction $on_out_of_bound = OutOfBoundAction::Keep,
10+
?string $step_title = null
11+
) {
12+
$this->then($struct, $on_out_of_bound, $step_title);
13+
}
14+
public function then(
15+
TypeHandler|string|array $struct,
16+
OutOfBoundAction $on_out_of_bound = OutOfBoundAction::Keep,
17+
?string $step_title = null
18+
) {
19+
if(is_array($struct)) {
20+
$this->steps[] = new Validator($struct, $on_out_of_bound);
21+
} elseif(is_string($struct)) {
22+
$this->steps[] = new TypeHandler($struct);
23+
} elseif(is_a($struct, TypeHandler::class)) {
24+
$this->steps[] = $struct;
25+
}
26+
$this->titles[] = ($step_title === null) ? strval(count($this->steps)) : $step_title;
27+
return $this;
28+
}
29+
public function validate(mixed $val) : Returner {
30+
foreach($this->steps as $i => $t) {
31+
if(is_a($t, Validator::class)) {
32+
if(!is_array($val) && !is_object($val)) {
33+
return Returner::invalid([
34+
'step' => $this->titles[$i],
35+
'msg' => new ErrorReader(["Expected 'array|object'"])
36+
]);
37+
}
38+
$val = $t->validate($val);
39+
if($val->valid) {
40+
$val = $val->value;
41+
} else {
42+
return Returner::invalid([
43+
'step' => $this->titles[$i],
44+
'msg' => $val->error
45+
]);
46+
}
47+
} else {
48+
$val = $t->validate($val);
49+
if($val->valid) {
50+
$val = $val->value;
51+
} else {
52+
return Returner::invalid([
53+
'step' => $this->titles[$i],
54+
'msg' => new ErrorReader([$val->error])
55+
]);
56+
}
57+
}
58+
}
59+
return Returner::valid($val);
60+
}
61+
}

src/RngFmt/AllowedValues.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
namespace Krishna\DataValidator\RngFmt;
3+
4+
use Krishna\DataValidator\Returner;
5+
6+
class AllowedValues extends \Krishna\DataValidator\AbstractRangerFormatter {
7+
private array $allowed;
8+
public function __construct(...$allowed) {
9+
$this->allowed = $allowed;
10+
}
11+
public function exec($value): Returner {
12+
if(in_array($value, $this->allowed, true)) {
13+
return Returner::valid($value);
14+
}
15+
return Returner::invalid('Unsupported value');
16+
}
17+
}

src/RngFmt/Num/Range.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
namespace Krishna\DataValidator\RngFmt\Num;
33

4-
use Krishna\DataValidator\MultiLinedException;
4+
use Krishna\DataValidator\ComplexException;
55
use Krishna\DataValidator\Returner;
66

77
class Range extends \Krishna\DataValidator\AbstractRangerFormatter {
@@ -10,7 +10,7 @@ public function __construct(private ?float $min = null, private ?float $max = nu
1010
($this->min === null && $this->max === null) ||
1111
($this->min !== null && $this->max !== null && $this->min > $this->max)
1212
) {
13-
throw new MultiLinedException('Invalid range values');
13+
throw new ComplexException('Invalid range values');
1414
}
1515
}
1616
public function exec($value): Returner {

src/RngFmt/Str/Range.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
namespace Krishna\DataValidator\RngFmt\Str;
33

4-
use Krishna\DataValidator\MultiLinedException;
4+
use Krishna\DataValidator\ComplexException;
55
use Krishna\DataValidator\Returner;
66

77
class Range extends \Krishna\DataValidator\AbstractRangerFormatter {
@@ -10,7 +10,7 @@ public function __construct(private ?int $min = null, private ?int $max = null)
1010
($this->min === null && $this->max === null) ||
1111
($this->min !== null && $this->max !== null && $this->min > $this->max)
1212
) {
13-
throw new MultiLinedException('Invalid range values');
13+
throw new ComplexException('Invalid range values');
1414
}
1515
}
1616
public function exec($value): Returner {

0 commit comments

Comments
 (0)