Completed
Pull Request — master (#18)
by Mathieu
03:26
created

JsonValidator::validate()   D

Complexity

Conditions 10
Paths 14

Size

Total Lines 42
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 10.0071

Importance

Changes 3
Bugs 0 Features 1
Metric Value
c 3
b 0
f 1
dl 0
loc 42
ccs 23
cts 24
cp 0.9583
rs 4.8196
cc 10
eloc 27
nc 14
nop 2
crap 10.0071

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Exception\ResourceNotFoundException;
16
use JsonSchema\RefResolver;
17
use JsonSchema\Uri\UriResolver;
18
use JsonSchema\Uri\UriRetriever;
19
use JsonSchema\Validator;
20
use Webmozart\PathUtil\Path;
21
22
/**
23
 * Validates decoded JSON values against a JSON schema.
24
 *
25
 * This class is a wrapper for {@link Validator} that adds exceptions and
26
 * validation of schema files. A few edge cases that are not handled by
27
 * {@link Validator} are handled by this class.
28
 *
29
 * @since  1.0
30
 *
31
 * @author Bernhard Schussek <[email protected]>
32
 */
33
class JsonValidator
34
{
35
    /**
36
     * The schema used for validating schemas.
37
     *
38
     * @var object|null
39
     */
40
    private $metaSchema;
41
42
    /**
43
     * Validator instance used for validation.
44
     *
45
     * @var Validator
46
     */
47
    private $validator;
48
49
    /**
50
     * for fetching & resolving JSON schemas.
51
     *
52
     * @var RefResolver
53
     */
54
    private $resolver;
55
56
    /**
57
     * JsonValidator constructor.
58
     *
59
     * @param Validator|null $validator JsonSchema\Validator instance to use.
60
     */
61 111
    public function __construct(
62
        Validator $validator = null,
63
        RefResolver $resolver = null
64
    ) {
65 111
        $this->validator = $validator ?: new Validator();
66 111
        $this->resolver = $resolver ?: new RefResolver(new UriRetriever(), new UriResolver());
67 111
    }
68
69
    /**
70
     * Validates JSON data against a schema.
71
     *
72
     * The schema may be passed as file path or as object returned from
73
     * `json_decode($schemaFile)`.
74
     *
75
     * @param mixed              $data   The decoded JSON data.
76
     * @param string|object|null $schema The schema file or object. If `null`,
77
     *                                   the validator will look for a `$schema`
78
     *                                   property.
79
     *
80
     * @return string[] The errors found during validation. Returns an empty
81
     *                  array if no errors were found.
82
     *
83
     * @throws InvalidSchemaException If the schema is invalid.
84
     */
85 28
    public function validate($data, $schema = null)
86
    {
87 28
        if (null === $schema && isset($data->{'$schema'})) {
88
            $schema = $data->{'$schema'};
89
        }
90
91 28
        if (is_string($schema)) {
92 15
            $schema = $this->loadSchema($schema);
93 14
        } elseif (is_object($schema)) {
94 11
            $this->assertSchemaValid($schema);
95
        } else {
96 3
            throw new InvalidSchemaException(sprintf(
97
                'The schema must be given as string, object or in the "$schema" '.
98 3
                'property of the JSON data. Got: %s',
99 3
                is_object($schema) ? get_class($schema) : gettype($schema)
100
            ));
101
        }
102
103 11
        $this->validator->reset();
104
105
        try {
106 11
            $this->validator->check($data, $schema);
107 1
        } catch (InvalidArgumentException $e) {
108 1
            throw new InvalidSchemaException(sprintf(
109 1
                'The schema is invalid: %s',
110 1
                $e->getMessage()
111 1
            ), 0, $e);
112
        }
113
114 11
        $errors = array();
115
116 11
        if (!$this->validator->isValid()) {
117 6
            $errors = (array) $this->validator->getErrors();
118
119 6
            foreach ($errors as $key => $error) {
120 6
                $prefix = $error['property'] ? $error['property'].': ' : '';
121 6
                $errors[$key] = $prefix.$error['message'];
122
            }
123
        }
124
125 11
        return $errors;
126
    }
127
128 11
    private function assertSchemaValid($schema)
129
    {
130 11
        if (null === $this->metaSchema) {
131
            // The meta schema is obviously not validated. If we
132
            // validate it against itself, we have an endless recursion
133 11
            $this->metaSchema = json_decode(file_get_contents(__DIR__.'/../res/meta-schema.json'));
134
        }
135
136 11
        if ($schema === $this->metaSchema) {
137 11
            return;
138
        }
139
140 11
        $errors = $this->validate($schema, $this->metaSchema);
141
142 11
        if (count($errors) > 0) {
143 1
            throw new InvalidSchemaException(sprintf(
144 1
                "The schema is invalid:\n%s",
145 1
                implode("\n", $errors)
146
            ));
147
        }
148 10
    }
149
150 15
    private function loadSchema($file)
151
    {
152
        try {
153 15
            $schema = $this->resolver->resolve($file);
154 1
            $this->assertSchemaValid($schema);
155 14
        } catch (ResourceNotFoundException $e) {
156 13
            throw new InvalidSchemaException(sprintf(
157 13
                'The schema %s does not exist.',
158
                $file
159 13
            ), 0, $e);
160 1
        } catch (InvalidSchemaException $e) {
161
            throw new InvalidSchemaException(sprintf(
162
                'An error occurred while loading the schema %s: %s',
163
                $file,
164
                $e->getMessage()
165
            ), 0, $e);
166
        }
167
168 1
        return $schema;
169
    }
170
}
171