Completed
Pull Request — master (#14)
by Benoît
06:43 queued 01:48
created

JsonValidator::createValidator()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
ccs 5
cts 5
cp 1
rs 9.4286
cc 2
eloc 5
nc 2
nop 0
crap 2
1
<?php
2
3
/*
4
 * This file is part of the Webmozart JSON package.
5
 *
6
 * (c) Bernhard Schussek <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Webmozart\Json;
13
14
use JsonSchema\Exception\InvalidArgumentException;
15
use JsonSchema\Validator;
16
17
/**
18
 * Validates decoded JSON values against a JSON schema.
19
 *
20
 * This class is a wrapper for {@link Validator} that adds exceptions and
21
 * validation of schema files. A few edge cases that are not handled by
22
 * {@link Validator} are handled by this class.
23
 *
24
 * @since  1.0
25
 *
26
 * @author Bernhard Schussek <[email protected]>
27
 */
28
class JsonValidator
29
{
30
    /**
31
     * The schema used for validating schemas.
32
     *
33
     * @var object|null
34
     */
35
    private $metaSchema;
36
37
    /**
38
     * Callable creating new Validator instances.
39
     *
40
     * @var callable
41
     */
42
    private $validatorFactory;
43
44
    public function __construct(callable $validatorFactory = null)
45
    {
46 21
        $this->validatorFactory = $validatorFactory ?: function () {
47 21
            return new Validator();
48
        };
49 104
    }
50
51
    /**
52
     * Validates JSON data against a schema.
53
     *
54
     * The schema may be passed as file path or as object returned from
55
     * `json_decode($schemaFile)`.
56
     *
57
     * @param mixed         $data   The decoded JSON data.
58
     * @param string|object $schema The schema file or object.
59
     *
60
     * @return string[] The errors found during validation. Returns an empty
61
     *                  array if no errors were found.
62
     *
63
     * @throws InvalidSchemaException If the schema is invalid.
64
     */
65 24
    public function validate($data, $schema)
66
    {
67 24
        if (is_string($schema)) {
68 13
            $schema = $this->loadSchema($schema);
69 8
        } else {
70 22
            $this->assertSchemaValid($schema);
71
        }
72
73 22
        $validator = $this->createValidator();
74
75
        try {
76 21
            $validator->check($data, $schema);
77 21
        } catch (InvalidArgumentException $e) {
78 1
            throw new InvalidSchemaException(sprintf(
79 1
                'The schema is invalid: %s',
80 1
                $e->getMessage()
81 1
            ), 0, $e);
82
        }
83
84 21
        $errors = array();
85
86 21
        if (!$validator->isValid()) {
87 14
            $errors = (array) $validator->getErrors();
88
89 14
            foreach ($errors as $key => $error) {
90 14
                $prefix = $error['property'] ? $error['property'].': ' : '';
91 14
                $errors[$key] = $prefix.$error['message'];
92 14
            }
93 14
        }
94
95 21
        return $errors;
96
    }
97
98 22
    private function assertSchemaValid($schema)
99
    {
100 22
        if (null === $this->metaSchema) {
101
            // The meta schema is obviously not validated. If we
102
            // validate it against itself, we have an endless recursion
103 22
            $this->metaSchema = json_decode(file_get_contents(__DIR__.'/../res/meta-schema.json'));
104 22
        }
105
106 22
        if ($schema === $this->metaSchema) {
107 22
            return;
108
        }
109
110 22
        $errors = $this->validate($schema, $this->metaSchema);
111
112 21
        if (count($errors) > 0) {
113 4
            throw new InvalidSchemaException(sprintf(
114 4
                "The schema is invalid:\n%s",
115 4
                implode("\n", $errors)
116 4
            ));
117
        }
118
119
        // not caught by justinrainbow/json-schema
120 17
        if (!is_object($schema)) {
121
            throw new InvalidSchemaException(sprintf(
122
                'The schema must be an object. Got: %s',
123
                $schema,
124
                gettype($schema)
125
            ));
126
        }
127 17
    }
128
129 13
    private function loadSchema($file)
130
    {
131 13
        if (!file_exists($file)) {
132 2
            throw new InvalidSchemaException(sprintf(
133 2
                'The schema file %s does not exist.',
134
                $file
135 2
            ));
136
        }
137
138 11
        $schema = json_decode(file_get_contents($file));
139
140
        try {
141 11
            $this->assertSchemaValid($schema);
142 11
        } catch (InvalidSchemaException $e) {
143 2
            throw new InvalidSchemaException(sprintf(
144 2
                'An error occurred while loading the schema %s: %s',
145 2
                $file,
146 2
                $e->getMessage()
147 2
            ), 0, $e);
148
        }
149
150 8
        return $schema;
151
    }
152
153
    /**
154
     * @return Validator
155
     */
156 22
    private function createValidator()
157
    {
158 22
        $validator = call_user_func($this->validatorFactory);
159
160 22
        if (!$validator instanceof Validator) {
161 1
            throw new UnexpectedTypeException('JsonSchema\Validator', $validator);
162
        }
163
164 21
        return $validator;
165
    }
166
}
167