Completed
Pull Request — master (#14)
by Benoît
03:54
created

JsonValidator::loadSchema()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 23
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 3

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 23
ccs 14
cts 14
cp 1
rs 9.0857
cc 3
eloc 15
nc 3
nop 1
crap 3
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
     * Validator instance used for validation.
39
     *
40
     * @var Validator
41
     */
42
    private $validator;
43
44
    /**
45
     * JsonValidator constructor.
46
     *
47
     * @param Validator|null $validator JsonSchema\Validator instance to use.
48
     */
49 97
    public function __construct(Validator $validator = null)
50
    {
51 97
        $this->validator = $validator ?: new Validator();
52 97
    }
53
54
    /**
55
     * Validates JSON data against a schema.
56
     *
57
     * The schema may be passed as file path or as object returned from
58
     * `json_decode($schemaFile)`.
59
     *
60
     * @param mixed         $data   The decoded JSON data.
61
     * @param string|object $schema The schema file or object.
62
     *
63
     * @return string[] The errors found during validation. Returns an empty
64
     *                  array if no errors were found.
65
     *
66
     * @throws InvalidSchemaException If the schema is invalid.
67
     */
68 23
    public function validate($data, $schema)
69
    {
70 23
        if (is_string($schema)) {
71 12
            $schema = $this->loadSchema($schema);
72 8
        } else {
73 21
            $this->assertSchemaValid($schema);
74
        }
75
76 21
        $validator = $this->prepareValidator();
77
78
        try {
79 21
            $validator->check($data, $schema);
80 21
        } catch (InvalidArgumentException $e) {
81 1
            throw new InvalidSchemaException(sprintf(
82 1
                'The schema is invalid: %s',
83 1
                $e->getMessage()
84 1
            ), 0, $e);
85
        }
86
87 21
        $errors = array();
88
89 21
        if (!$validator->isValid()) {
90 14
            $errors = (array) $validator->getErrors();
91
92 14
            foreach ($errors as $key => $error) {
93 14
                $prefix = $error['property'] ? $error['property'].': ' : '';
94 14
                $errors[$key] = $prefix.$error['message'];
95 14
            }
96 14
        }
97
98 21
        return $errors;
99
    }
100
101 21
    private function assertSchemaValid($schema)
102
    {
103 21
        if (null === $this->metaSchema) {
104
            // The meta schema is obviously not validated. If we
105
            // validate it against itself, we have an endless recursion
106 21
            $this->metaSchema = json_decode(file_get_contents(__DIR__.'/../res/meta-schema.json'));
107 21
        }
108
109 21
        if ($schema === $this->metaSchema) {
110 21
            return;
111
        }
112
113 21
        $errors = $this->validate($schema, $this->metaSchema);
114
115 21
        if (count($errors) > 0) {
116 4
            throw new InvalidSchemaException(sprintf(
117 4
                "The schema is invalid:\n%s",
118 4
                implode("\n", $errors)
119 4
            ));
120
        }
121
122
        // not caught by justinrainbow/json-schema
123 17
        if (!is_object($schema)) {
124
            throw new InvalidSchemaException(sprintf(
125
                'The schema must be an object. Got: %s',
126
                $schema,
127
                gettype($schema)
128
            ));
129
        }
130 17
    }
131
132 12
    private function loadSchema($file)
133
    {
134 12
        if (!file_exists($file)) {
135 2
            throw new InvalidSchemaException(sprintf(
136 2
                'The schema file %s does not exist.',
137
                $file
138 2
            ));
139
        }
140
141 10
        $schema = json_decode(file_get_contents($file));
142
143
        try {
144 10
            $this->assertSchemaValid($schema);
145 10
        } catch (InvalidSchemaException $e) {
146 2
            throw new InvalidSchemaException(sprintf(
147 2
                'An error occurred while loading the schema %s: %s',
148 2
                $file,
149 2
                $e->getMessage()
150 2
            ), 0, $e);
151
        }
152
153 8
        return $schema;
154
    }
155
156
    /**
157
     * @return Validator
158
     */
159 21
    private function prepareValidator()
160
    {
161 21
        $this->validator->reset();
162
163 21
        return $this->validator;
164
    }
165
}
166