Passed
Pull Request — master (#320)
by Dmitriy
12:15 queued 09:25
created

JsonHandler::validate()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 8
c 1
b 0
f 0
dl 0
loc 16
ccs 9
cts 9
cp 1
rs 10
cc 3
nc 3
nop 3
crap 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule;
6
7
use Yiisoft\Validator\Exception\UnexpectedRuleException;
8
use Yiisoft\Validator\Result;
9
use Yiisoft\Validator\RuleHandlerInterface;
10
use Yiisoft\Validator\ValidationContext;
11
12
use function is_string;
13
14
/**
15
 * Validates that the value is a valid json.
16
 */
17
final class JsonHandler implements RuleHandlerInterface
18
{
19 10
    public function validate(mixed $value, object $rule, ValidationContext $context): Result
20
    {
21 10
        if (!$rule instanceof Json) {
22 1
            throw new UnexpectedRuleException(Json::class, $rule);
23
        }
24
25 9
        $result = new Result();
26
27 9
        if (!$this->isValidJson($value)) {
28 6
            $result->addError(
29 6
                message: $rule->getMessage(),
30 6
                parameters: ['value' => $value]
31
            );
32
        }
33
34 9
        return $result;
35
    }
36
37 9
    private function isValidJson($value): bool
38
    {
39
        // Regular expression is built based on JSON grammar specified at
40
        // https://tools.ietf.org/html/rfc8259
41 9
        $regex = <<<'REGEX'
42
        /
43
        (?(DEFINE)
44
            (?<json>(?>\s*(?&object)\s*|\s*(?&array)\s*))
45
            (?<object>(?>\{\s*(?>(?&member)(?>\s*,\s*(?&member))*)?\s*\}))
46
            (?<member>(?>(?&string)\s*:\s*(?&value)))
47
            (?<array>(?>\[\s*(?>(?&value)(?>\s*,\s*(?&value))*)?\s*\]))
48
            (?<value>(?>)false|null|true|(?&object)|(?&array)|(?&number)|(?&string))
49
            (?<number>(?>-?(?>0|[1-9]\d*)(?>\.\d+)?(?>[eE][-+]?\d+)?))
50
            (?<string>(?>"(?>\\(?>["\\\/bfnrt]|u[a-fA-F0-9]{4})|[^"\\\0-\x1F\x7F]+)*"))
51
        )
52
        \A(?&json)\z
53
        /x
54
        REGEX;
55
56 9
        return is_string($value) && preg_match($regex, $value) === 1;
57
    }
58
}
59