These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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\Constraints\Factory; |
||
15 | use JsonSchema\Exception\InvalidArgumentException; |
||
16 | use JsonSchema\Exception\ResourceNotFoundException; |
||
17 | use JsonSchema\RefResolver; |
||
18 | use JsonSchema\Uri\UriResolver; |
||
19 | use JsonSchema\Uri\UriRetriever; |
||
20 | use JsonSchema\Validator; |
||
21 | use Webmozart\PathUtil\Path; |
||
22 | |||
23 | /** |
||
24 | * Validates decoded JSON values against a JSON schema. |
||
25 | * |
||
26 | * This class is a wrapper for {@link Validator} that adds exceptions and |
||
27 | * validation of schema files. A few edge cases that are not handled by |
||
28 | * {@link Validator} are handled by this class. |
||
29 | * |
||
30 | * @since 1.0 |
||
31 | * |
||
32 | * @author Bernhard Schussek <[email protected]> |
||
33 | */ |
||
34 | class JsonValidator |
||
35 | { |
||
36 | /** |
||
37 | * The schema used for validating schemas. |
||
38 | * |
||
39 | * @var object|null |
||
40 | */ |
||
41 | private $metaSchema; |
||
42 | |||
43 | /** |
||
44 | * Validator instance used for validation. |
||
45 | * |
||
46 | * @var Validator |
||
47 | */ |
||
48 | private $validator; |
||
49 | |||
50 | /** |
||
51 | * Validator instance used for internal validation. |
||
52 | * |
||
53 | * @var Validator|null |
||
54 | */ |
||
55 | private $internalValidator; |
||
56 | |||
57 | /** |
||
58 | * Validator instance used for internal validation. |
||
59 | * |
||
60 | * @var Validator|null |
||
61 | */ |
||
62 | private $internalFactory; |
||
63 | |||
64 | /** |
||
65 | * Version of the justinrainbow/json-schema library. |
||
66 | 115 | * |
|
67 | * @var int |
||
68 | 115 | */ |
|
69 | 115 | private $jsonSchemaVersion; |
|
70 | 115 | ||
71 | /** |
||
72 | * JsonValidator constructor. |
||
73 | * |
||
74 | * @param Validator|null $validator JsonSchema\Validator instance |
||
75 | * to use |
||
76 | * @param UriRetriever|null $uriRetriever The retriever for fetching |
||
77 | * JSON schemas |
||
78 | */ |
||
79 | public function __construct(Validator $validator = null, UriRetriever $uriRetriever = null) |
||
80 | { |
||
81 | if (method_exists('JsonSchema\Validator', 'getUriRetriever')) { |
||
82 | if (!method_exists('JsonSchema\Validator', 'getSchemaStorage')) { |
||
83 | $this->jsonSchemaVersion = 2; |
||
84 | } else { |
||
85 | $this->jsonSchemaVersion = 3; |
||
86 | } |
||
87 | $this->validator = $validator ?: new Validator(); |
||
88 | 31 | if ($uriRetriever) { |
|
89 | $this->validator->setUriRetriever($uriRetriever); |
||
0 ignored issues
–
show
|
|||
90 | 31 | } |
|
91 | 1 | if (2 === $this->jsonSchemaVersion) { |
|
92 | $this->resolver = new RefResolver($uriRetriever ?: new UriRetriever(), new UriResolver()); |
||
0 ignored issues
–
show
The property
resolver does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
![]() |
|||
93 | } |
||
94 | 31 | } else { |
|
95 | 18 | $this->jsonSchemaVersion = 4; |
|
96 | 29 | $this->internalFactory = new Factory(null, $uriRetriever); |
|
0 ignored issues
–
show
It seems like
new \JsonSchema\Constrai...ry(null, $uriRetriever) of type object<JsonSchema\Constraints\Factory> is incompatible with the declared type object<JsonSchema\Validator>|null of property $internalFactory .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||
97 | 26 | $this->validator = $validator ?: new Validator($this->internalFactory); |
|
98 | $this->internalValidator = new Validator($this->internalFactory); |
||
99 | 3 | } |
|
100 | } |
||
101 | 3 | ||
102 | 3 | /** |
|
103 | * Validates JSON data against a schema. |
||
104 | * |
||
105 | * The schema may be passed as file path or as object returned from |
||
106 | 26 | * `json_decode($schemaFile)`. |
|
107 | * |
||
108 | * @param mixed $data The decoded JSON data |
||
109 | 26 | * @param string|object|null $schema The schema file or object. If `null`, |
|
110 | 1 | * the validator will look for a `$schema` |
|
111 | 1 | * property |
|
112 | 1 | * |
|
113 | 1 | * @return string[] The errors found during validation. Returns an empty |
|
114 | 1 | * array if no errors were found |
|
115 | * |
||
116 | * @throws InvalidSchemaException If the schema is invalid |
||
117 | 26 | */ |
|
118 | public function validate($data, $schema = null) |
||
119 | 26 | { |
|
120 | 15 | if (null === $schema && isset($data->{'$schema'})) { |
|
121 | $schema = $data->{'$schema'}; |
||
122 | 15 | } |
|
123 | 15 | ||
124 | 15 | if (is_string($schema)) { |
|
125 | $schema = $this->loadSchema($schema); |
||
126 | } elseif (is_object($schema)) { |
||
127 | $this->assertSchemaValid($schema); |
||
128 | 26 | } else { |
|
129 | throw new InvalidSchemaException(sprintf( |
||
130 | 'The schema must be given as string, object or in the "$schema" '. |
||
131 | 26 | 'property of the JSON data. Got: %s', |
|
132 | is_object($schema) ? get_class($schema) : gettype($schema) |
||
133 | 26 | )); |
|
134 | } |
||
135 | |||
136 | 26 | $this->validator->reset(); |
|
137 | |||
138 | try { |
||
139 | 26 | $this->validator->check($data, $schema); |
|
140 | 26 | } catch (ResourceNotFoundException $e) { |
|
141 | throw new InvalidSchemaException($e->getMessage(), $e->getCode(), $e); |
||
142 | } catch (InvalidArgumentException $e) { |
||
143 | 26 | throw new InvalidSchemaException(sprintf( |
|
144 | 'The schema is invalid: %s', |
||
145 | 26 | $e->getMessage() |
|
146 | 3 | ), 0, $e); |
|
147 | 3 | } |
|
148 | 3 | ||
149 | $errors = array(); |
||
150 | |||
151 | 23 | if (!$this->validator->isValid()) { |
|
152 | $errors = (array) $this->validator->getErrors(); |
||
153 | 18 | ||
154 | foreach ($errors as $key => $error) { |
||
155 | $prefix = $error['property'] ? $error['property'].': ' : ''; |
||
156 | 18 | $errors[$key] = $prefix.$error['message']; |
|
157 | } |
||
158 | } |
||
159 | 18 | ||
160 | 16 | return $errors; |
|
161 | } |
||
162 | |||
163 | private function assertSchemaValid($schema) |
||
164 | { |
||
165 | 18 | if (null === $this->metaSchema) { |
|
166 | 2 | // The meta schema is obviously not validated. If we |
|
167 | 2 | // validate it against itself, we have an endless recursion |
|
168 | 2 | $this->metaSchema = json_decode(file_get_contents(__DIR__.'/../res/meta-schema.json')); |
|
169 | |||
170 | 2 | switch ($this->jsonSchemaVersion) { |
|
171 | case 3: |
||
172 | $this->validator->getSchemaStorage()->addSchema('http://json-schema.org/draft-04/schema', $this->metaSchema); |
||
0 ignored issues
–
show
The method
getSchemaStorage() does not seem to exist on object<JsonSchema\Validator> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||
173 | break; |
||
174 | 16 | case 4: |
|
175 | 2 | $this->internalFactory->getSchemaStorage()->addSchema('http://json-schema.org/draft-04/schema', $this->metaSchema); |
|
0 ignored issues
–
show
The method
getSchemaStorage() does not seem to exist on object<JsonSchema\Validator> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||
176 | 2 | break; |
|
177 | 2 | } |
|
178 | } |
||
179 | 2 | ||
180 | 2 | if ($schema === $this->metaSchema) { |
|
181 | return; |
||
182 | } |
||
183 | 14 | ||
184 | $errors = $this->validate($schema, $this->metaSchema); |
||
185 | |||
186 | if (count($errors) > 0) { |
||
187 | throw new InvalidSchemaException(sprintf( |
||
188 | "The schema is invalid:\n%s", |
||
189 | implode("\n", $errors) |
||
190 | )); |
||
191 | } |
||
192 | |||
193 | if (3 === $this->jsonSchemaVersion && !isset($schema->{'$ref'})) { |
||
194 | $this->validator->getSchemaStorage()->addSchema($schema->id, $schema); |
||
0 ignored issues
–
show
The method
getSchemaStorage() does not seem to exist on object<JsonSchema\Validator> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||
195 | } |
||
196 | } |
||
197 | |||
198 | private function loadSchema($file) |
||
199 | { |
||
200 | // Retrieve schema and cache in UriRetriever |
||
201 | $file = Path::canonicalize($file); |
||
202 | |||
203 | // Add file:// scheme if necessary |
||
204 | if (false === strpos($file, '://')) { |
||
205 | $file = 'file://'.$file; |
||
206 | } |
||
207 | |||
208 | if (2 === $this->jsonSchemaVersion) { |
||
209 | // Resolve references to other schemas |
||
210 | try { |
||
211 | $schema = $this->resolver->resolve($file); |
||
212 | } catch (ResourceNotFoundException $e) { |
||
213 | throw new InvalidSchemaException(sprintf( |
||
214 | 'The schema %s does not exist.', |
||
215 | $file |
||
216 | ), 0, $e); |
||
217 | } |
||
218 | } else { |
||
219 | $schema = (object) array('$ref' => $file); |
||
220 | } |
||
221 | |||
222 | try { |
||
223 | $this->assertSchemaValid($schema); |
||
224 | } catch (InvalidSchemaException $e) { |
||
225 | throw new InvalidSchemaException(sprintf( |
||
226 | 'An error occurred while loading the schema %s: %s', |
||
227 | $file, |
||
228 | $e->getMessage() |
||
229 | ), 0, $e); |
||
230 | } |
||
231 | |||
232 | return $schema; |
||
233 | } |
||
234 | } |
||
235 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.