Passed
Push — master ( 2d7948...93347a )
by Viacheslav
03:31
created

Schema   F

Complexity

Total Complexity 306

Size/Duplication

Total Lines 1358
Duplicated Lines 0 %

Test Coverage

Coverage 95.58%

Importance

Changes 0
Metric Value
wmc 306
eloc 643
dl 0
loc 1358
ccs 605
cts 633
cp 0.9558
rs 1.957
c 0
b 0
f 0

41 Methods

Rating   Name   Duplication   Size   Complexity  
B import() 0 29 7
A processIf() 0 18 5
A processAllOf() 0 7 2
B in() 0 29 7
F processNumeric() 0 53 17
A out() 0 9 2
A processObjectRequired() 0 5 3
A processType() 0 12 5
B processEnum() 0 19 7
B processAnyOf() 0 28 6
B processOneOf() 0 48 11
A addPropertyMapping() 0 8 2
B processConst() 0 12 7
B processString() 0 23 11
A processNot() 0 10 3
F processArray() 0 80 25
F processObject() 0 338 108
A number() 0 5 1
A null() 0 5 1
A getPropertyNames() 0 3 1
A setProperties() 0 4 1
A setUseObjectAsArray() 0 4 1
A setProperty() 0 7 2
A getNestedPropertyNames() 0 3 1
A unboolSchema() 0 19 4
A makeObjectItem() 0 12 4
A string() 0 5 1
A fail() 0 4 1
A boolean() 0 5 1
F process() 0 139 40
A setPatternProperty() 0 7 2
A getObjectItemClass() 0 3 1
A unboolSchemaData() 0 17 4
A getDefault() 0 3 1
A processContent() 0 12 3
A arr() 0 5 1
A getProperties() 0 3 1
A getMeta() 0 6 2
A integer() 0 5 1
A object() 0 5 1
A addMeta() 0 7 2

How to fix   Complexity   

Complex Class

Complex classes like Schema often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Schema, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Swaggest\JsonSchema;
4
5
6
use PhpLang\ScopeExit;
7
use Swaggest\JsonDiff\JsonDiff;
8
use Swaggest\JsonDiff\JsonPointer;
9
use Swaggest\JsonSchema\Constraint\Content;
10
use Swaggest\JsonSchema\Constraint\Format;
11
use Swaggest\JsonSchema\Constraint\Properties;
12
use Swaggest\JsonSchema\Constraint\Type;
13
use Swaggest\JsonSchema\Constraint\UniqueItems;
14
use Swaggest\JsonSchema\Exception\ArrayException;
15
use Swaggest\JsonSchema\Exception\ConstException;
16
use Swaggest\JsonSchema\Exception\EnumException;
17
use Swaggest\JsonSchema\Exception\LogicException;
18
use Swaggest\JsonSchema\Exception\NumericException;
19
use Swaggest\JsonSchema\Exception\ObjectException;
20
use Swaggest\JsonSchema\Exception\StringException;
21
use Swaggest\JsonSchema\Exception\TypeException;
22
use Swaggest\JsonSchema\Meta\MetaHolder;
23
use Swaggest\JsonSchema\Path\PointerUtil;
24
use Swaggest\JsonSchema\Structure\ClassStructure;
25
use Swaggest\JsonSchema\Structure\Egg;
26
use Swaggest\JsonSchema\Structure\ObjectItem;
27
use Swaggest\JsonSchema\Structure\ObjectItemContract;
28
29
/**
30
 * Class Schema
31
 * @package Swaggest\JsonSchema
32
 */
33
class Schema extends JsonSchema implements MetaHolder, SchemaContract
34
{
35
    const ENUM_NAMES_PROPERTY = 'x-enum-names';
36
    const CONST_PROPERTY = 'const';
37
38
    const DEFAULT_MAPPING = 'default';
39
40
    const VERSION_AUTO = 'a';
41
    const VERSION_DRAFT_04 = 4;
42
    const VERSION_DRAFT_06 = 6;
43
    const VERSION_DRAFT_07 = 7;
44
45
    const PROP_REF = '$ref';
46
    const PROP_ID = '$id';
47
    const PROP_ID_D4 = 'id';
48
49
    // Object
50
    /** @var null|Properties */
51
    public $properties;
52
    /** @var Schema|bool */
53
    public $additionalProperties;
54
    /** @var Schema[]|Properties */
55
    public $patternProperties;
56
    /** @var string[][]|Schema[]|\stdClass */
57
    public $dependencies;
58
59
    // Array
60
    /** @var null|Schema|Schema[] */
61
    public $items;
62
    /** @var null|Schema|bool */
63
    public $additionalItems;
64
65
    /** @var Schema[] */
66
    public $allOf;
67
    /** @var Schema */
68
    public $not;
69
    /** @var Schema[] */
70
    public $anyOf;
71
    /** @var Schema[] */
72
    public $oneOf;
73
74
    /** @var Schema */
75
    public $if;
76
    /** @var Schema */
77
    public $then;
78
    /** @var Schema */
79
    public $else;
80
81
82
    public $objectItemClass;
83
84
    /**
85
     * @todo check usages/deprecate
86
     * @var bool
87
     */
88
    private $useObjectAsArray = false;
89
90
    private $__booleanSchema;
91
92 4
    public function addPropertyMapping($dataName, $propertyName, $mapping = self::DEFAULT_MAPPING)
93
    {
94 4
        if (null === $this->properties) {
95
            $this->properties = new Properties();
96
        }
97
98 4
        $this->properties->addPropertyMapping($dataName, $propertyName, $mapping);
99 4
        return $this;
100
    }
101
102
    /**
103
     * @param mixed $data
104
     * @param Context|null $options
105
     * @return SchemaContract
106
     * @throws Exception
107
     * @throws InvalidValue
108
     * @throws \Exception
109
     */
110 3295
    public static function import($data, Context $options = null)
111
    {
112 3295
        if (null === $options) {
113 31
            $options = new Context();
114
        }
115
116 3295
        $options->applyDefaults = false;
117
118 3295
        if (isset($options->schemasCache) && is_object($data)) {
119
            if ($options->schemasCache->contains($data)) {
120
                return $options->schemasCache->offsetGet($data);
121
            } else {
122
                $schema = parent::import($data, $options);
123
                $options->schemasCache->attach($data, $schema);
124
                return $schema;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $schema also could return the type Swaggest\JsonSchema\Structure\ClassStructureTrait which is incompatible with the documented return type Swaggest\JsonSchema\SchemaContract.
Loading history...
125
            }
126
        }
127
128
        // string $data is expected to be $ref uri
129 3295
        if (is_string($data)) {
130 4
            $data = (object)array(self::PROP_REF => $data);
131
        }
132
133 3295
        $data = self::unboolSchema($data);
134 3295
        if ($data instanceof SchemaContract) {
135 72
            return $data;
136
        }
137
138 3223
        return parent::import($data, $options);
0 ignored issues
show
Bug Best Practice introduced by
The expression return parent::import($data, $options) also could return the type Swaggest\JsonSchema\Structure\ClassStructureTrait which is incompatible with the documented return type Swaggest\JsonSchema\SchemaContract.
Loading history...
139
    }
140
141
    /**
142
     * @param mixed $data
143
     * @param Context|null $options
144
     * @return array|mixed|null|object|\stdClass
145
     * @throws Exception
146
     * @throws InvalidValue
147
     * @throws \Exception
148
     */
149 3320
    public function in($data, Context $options = null)
150
    {
151 3320
        if (null !== $this->__booleanSchema) {
152 72
            if ($this->__booleanSchema) {
153 36
                return $data;
154 36
            } elseif (empty($options->skipValidation)) {
155 18
                $this->fail(new InvalidValue('Denied by false schema'), '#');
156
            }
157
        }
158
159 3266
        if ($options === null) {
160 66
            $options = new Context();
161
        }
162
163 3266
        $options->import = true;
164
165 3266
        if ($options->refResolver === null) {
166 2933
            $options->refResolver = new RefResolver($data);
167
        } else {
168 1766
            $options->refResolver->setRootData($data);
169
        }
170
171 3266
        if ($options->remoteRefProvider) {
172 3190
            $options->refResolver->setRemoteRefProvider($options->remoteRefProvider);
173
        }
174
175 3266
        $options->refResolver->preProcessReferences($data, $options);
176
177 3266
        return $this->process($data, $options, '#');
178
    }
179
180
181
    /**
182
     * @param mixed $data
183
     * @param Context|null $options
184
     * @return array|mixed|null|object|\stdClass
185
     * @throws InvalidValue
186
     * @throws \Exception
187
     */
188 2452
    public function out($data, Context $options = null)
189
    {
190 2452
        if ($options === null) {
191 1007
            $options = new Context();
192
        }
193
194 2452
        $options->circularReferences = new \SplObjectStorage();
195 2452
        $options->import = false;
196 2452
        return $this->process($data, $options);
197
    }
198
199
    /**
200
     * @param mixed $data
201
     * @param Context $options
202
     * @param string $path
203
     * @throws InvalidValue
204
     * @throws \Exception
205
     */
206 3254
    private function processType($data, Context $options, $path = '#')
207
    {
208 3254
        if ($options->tolerateStrings && is_string($data)) {
209
            $valid = Type::readString($this->type, $data);
210
        } else {
211 3254
            $valid = Type::isValid($this->type, $data, $options->version);
212
        }
213 3254
        if (!$valid) {
214 696
            $this->fail(new TypeException(ucfirst(
215 696
                    implode(', ', is_array($this->type) ? $this->type : array($this->type))
216 696
                    . ' expected, ' . json_encode($data) . ' received')
217 696
            ), $path);
218
        }
219 3252
    }
220
221
    /**
222
     * @param mixed $data
223
     * @param string $path
224
     * @throws InvalidValue
225
     * @throws \Exception
226
     */
227 1510
    private function processEnum($data, $path = '#')
228
    {
229 1510
        $enumOk = false;
230 1510
        foreach ($this->enum as $item) {
231 1510
            if ($item === $data) {
232 1490
                $enumOk = true;
233 1490
                break;
234
            } else {
235 1446
                if (is_array($item) || is_object($item)) {
236 12
                    $diff = new JsonDiff($item, $data, JsonDiff::STOP_ON_DIFF);
237 12
                    if ($diff->getDiffCnt() === 0) {
238 3
                        $enumOk = true;
239 1446
                        break;
240
                    }
241
                }
242
            }
243
        }
244 1510
        if (!$enumOk) {
245 107
            $this->fail(new EnumException('Enum failed, enum: ' . json_encode($this->enum) . ', data: ' . json_encode($data)), $path);
246
        }
247 1493
    }
248
249
    /**
250
     * @param mixed $data
251
     * @param string $path
252
     * @throws InvalidValue
253
     * @throws \Swaggest\JsonDiff\Exception
254
     */
255 43
    private function processConst($data, $path)
256
    {
257 43
        if ($this->const !== $data) {
258 37
            if ((is_object($this->const) && is_object($data))
259 37
                || (is_array($this->const) && is_array($data))) {
260 15
                $diff = new JsonDiff($this->const, $data,
261 15
                    JsonDiff::STOP_ON_DIFF);
262 15
                if ($diff->getDiffCnt() != 0) {
263 15
                    $this->fail(new ConstException('Const failed'), $path);
264
                }
265
            } else {
266 22
                $this->fail(new ConstException('Const failed'), $path);
267
            }
268
        }
269 20
    }
270
271
    /**
272
     * @param mixed $data
273
     * @param Context $options
274
     * @param string $path
275
     * @throws InvalidValue
276
     * @throws \Exception
277
     * @throws \Swaggest\JsonDiff\Exception
278
     */
279 70
    private function processNot($data, Context $options, $path)
280
    {
281 70
        $exception = false;
282
        try {
283 70
            self::unboolSchema($this->not)->process($data, $options, $path . '->not');
284 16
        } catch (InvalidValue $exception) {
285
            // Expected exception
286
        }
287 70
        if ($exception === false) {
288 56
            $this->fail(new LogicException('Not ' . json_encode($this->not) . ' expected, ' . json_encode($data) . ' received'), $path . '->not');
289
        }
290 16
    }
291
292
    /**
293
     * @param string $data
294
     * @param string $path
295
     * @throws InvalidValue
296
     */
297 2328
    private function processString($data, $path)
298
    {
299 2328
        if ($this->minLength !== null) {
300 38
            if (mb_strlen($data, 'UTF-8') < $this->minLength) {
301 9
                $this->fail(new StringException('String is too short', StringException::TOO_SHORT), $path);
302
            }
303
        }
304 2322
        if ($this->maxLength !== null) {
305 43
            if (mb_strlen($data, 'UTF-8') > $this->maxLength) {
306 19
                $this->fail(new StringException('String is too long', StringException::TOO_LONG), $path);
307
            }
308
        }
309 2319
        if ($this->pattern !== null) {
310 18
            if (0 === preg_match(Helper::toPregPattern($this->pattern), $data)) {
311 4
                $this->fail(new StringException(json_encode($data) . ' does not match to '
312 4
                    . $this->pattern, StringException::PATTERN_MISMATCH), $path);
313
            }
314
        }
315 2319
        if ($this->format !== null) {
316 443
            $validationError = Format::validationError($this->format, $data);
317 443
            if ($validationError !== null) {
318 150
                if (!($this->format === "uri" && substr($path, -3) === ':id')) {
319 131
                    $this->fail(new StringException($validationError), $path);
320
                }
321
            }
322
        }
323 2319
    }
324
325
    /**
326
     * @param float|int $data
327
     * @param string $path
328
     * @throws InvalidValue
329
     */
330 1088
    private function processNumeric($data, $path)
331
    {
332 1088
        if ($this->multipleOf !== null) {
333 39
            $div = $data / $this->multipleOf;
334 39
            if ($div != (int)$div) {
335 15
                $this->fail(new NumericException($data . ' is not multiple of ' . $this->multipleOf, NumericException::MULTIPLE_OF), $path);
336
            }
337
        }
338
339 1088
        if ($this->exclusiveMaximum !== null && !is_bool($this->exclusiveMaximum)) {
340 32
            if ($data >= $this->exclusiveMaximum) {
341 18
                $this->fail(new NumericException(
342 18
                    'Value less or equal than ' . $this->exclusiveMaximum . ' expected, ' . $data . ' received',
343 18
                    NumericException::MAXIMUM), $path);
344
            }
345
        }
346
347 1088
        if ($this->exclusiveMinimum !== null && !is_bool($this->exclusiveMinimum)) {
348 24
            if ($data <= $this->exclusiveMinimum) {
349 12
                $this->fail(new NumericException(
350 12
                    'Value more or equal than ' . $this->exclusiveMinimum . ' expected, ' . $data . ' received',
351 12
                    NumericException::MINIMUM), $path);
352
            }
353
        }
354
355 1088
        if ($this->maximum !== null) {
356 46
            if ($this->exclusiveMaximum === true) {
357 3
                if ($data >= $this->maximum) {
358 2
                    $this->fail(new NumericException(
359 2
                        'Value less or equal than ' . $this->maximum . ' expected, ' . $data . ' received',
360 3
                        NumericException::MAXIMUM), $path);
361
                }
362
            } else {
363 43
                if ($data > $this->maximum) {
364 14
                    $this->fail(new NumericException(
365 14
                        'Value less than ' . $this->maximum . ' expected, ' . $data . ' received',
366 14
                        NumericException::MAXIMUM), $path);
367
                }
368
            }
369
        }
370
371 1088
        if ($this->minimum !== null) {
372 524
            if ($this->exclusiveMinimum === true) {
373 93
                if ($data <= $this->minimum) {
374 2
                    $this->fail(new NumericException(
375 2
                        'Value more or equal than ' . $this->minimum . ' expected, ' . $data . ' received',
376 93
                        NumericException::MINIMUM), $path);
377
                }
378
            } else {
379 449
                if ($data < $this->minimum) {
380 46
                    $this->fail(new NumericException(
381 46
                        'Value more than ' . $this->minimum . ' expected, ' . $data . ' received',
382 46
                        NumericException::MINIMUM), $path);
383
                }
384
            }
385
        }
386 1087
    }
387
388
    /**
389
     * @param mixed $data
390
     * @param Context $options
391
     * @param string $path
392
     * @return array|mixed|null|object|\stdClass
393
     * @throws InvalidValue
394
     * @throws \Exception
395
     * @throws \Swaggest\JsonDiff\Exception
396
     */
397 107
    private function processOneOf($data, Context $options, $path)
398
    {
399 107
        $successes = 0;
400 107
        $failures = '';
401 107
        $subErrors = [];
402 107
        $skipValidation = false;
403 107
        if ($options->skipValidation) {
404 41
            $skipValidation = true;
405 41
            $options->skipValidation = false;
406
        }
407
408 107
        $result = $data;
409 107
        foreach ($this->oneOf as $index => $item) {
410
            try {
411 107
                $result = self::unboolSchema($item)->process($data, $options, $path . '->oneOf[' . $index . ']');
412 85
                $successes++;
413 85
                if ($successes > 1 || $options->skipValidation) {
414 85
                    break;
415
                }
416 75
            } catch (InvalidValue $exception) {
417 75
                $subErrors[$index] = $exception;
418 107
                $failures .= ' ' . $index . ': ' . Helper::padLines(' ', $exception->getMessage()) . "\n";
419
                // Expected exception
420
            }
421
        }
422 107
        if ($skipValidation) {
423 41
            $options->skipValidation = true;
424 41
            if ($successes === 0) {
425 8
                $result = self::unboolSchema($this->oneOf[0])->process($data, $options, $path . '->oneOf[0]');
426
            }
427
        }
428
429 107
        if (!$options->skipValidation) {
430 66
            if ($successes === 0) {
431 20
                $exception = new LogicException('No valid results for oneOf {' . "\n" . substr($failures, 0, -1) . "\n}");
432 20
                $exception->error = 'No valid results for oneOf';
433 20
                $exception->subErrors = $subErrors;
434 20
                $this->fail($exception, $path);
435 52
            } elseif ($successes > 1) {
436 17
                $exception = new LogicException('More than 1 valid result for oneOf: '
437 17
                    . $successes . '/' . count($this->oneOf) . ' valid results for oneOf {'
438 17
                    . "\n" . substr($failures, 0, -1) . "\n}");
439 17
                $exception->error = 'More than 1 valid result for oneOf';
440 17
                $exception->subErrors = $subErrors;
441 17
                $this->fail($exception, $path);
442
            }
443
        }
444 77
        return $result;
445
    }
446
447
    /**
448
     * @param mixed $data
449
     * @param Context $options
450
     * @param string $path
451
     * @return array|mixed|null|object|\stdClass
452
     * @throws InvalidValue
453
     * @throws \Exception
454
     * @throws \Swaggest\JsonDiff\Exception
455
     */
456 1760
    private function processAnyOf($data, Context $options, $path)
457
    {
458 1760
        $successes = 0;
459 1760
        $failures = '';
460 1760
        $subErrors = [];
461 1760
        $result = $data;
462 1760
        foreach ($this->anyOf as $index => $item) {
463
            try {
464 1760
                $result = self::unboolSchema($item)->process($data, $options, $path . '->anyOf[' . $index . ']');
465 1754
                $successes++;
466 1754
                if ($successes) {
467 1754
                    break;
468
                }
469 445
            } catch (InvalidValue $exception) {
470 445
                $subErrors[$index] = $exception;
471 445
                $failures .= ' ' . $index . ': ' . $exception->getMessage() . "\n";
472
                // Expected exception
473
            }
474
        }
475 1760
        if (!$successes && !$options->skipValidation) {
476 31
            $exception = new LogicException('No valid results for anyOf {' . "\n"
477 31
                . substr(Helper::padLines(' ', $failures, false), 0, -1)
478 31
                . "\n}");
479 31
            $exception->error = 'No valid results for anyOf';
480 31
            $exception->subErrors = $subErrors;
481 31
            $this->fail($exception, $path);
482
        }
483 1754
        return $result;
484
    }
485
486
    /**
487
     * @param mixed $data
488
     * @param Context $options
489
     * @param string $path
490
     * @return array|mixed|null|object|\stdClass
491
     * @throws InvalidValue
492
     * @throws \Exception
493
     * @throws \Swaggest\JsonDiff\Exception
494
     */
495 354
    private function processAllOf($data, Context $options, $path)
496
    {
497 354
        $result = $data;
498 354
        foreach ($this->allOf as $index => $item) {
499 354
            $result = self::unboolSchema($item)->process($data, $options, $path . '->allOf[' . $index . ']');
500
        }
501 314
        return $result;
502
    }
503
504
    /**
505
     * @param mixed $data
506
     * @param Context $options
507
     * @param string $path
508
     * @return array|mixed|null|object|\stdClass
509
     * @throws InvalidValue
510
     * @throws \Exception
511
     * @throws \Swaggest\JsonDiff\Exception
512
     */
513 26
    private function processIf($data, Context $options, $path)
514
    {
515 26
        $valid = true;
516
        try {
517 26
            self::unboolSchema($this->if)->process($data, $options, $path . '->if');
518 13
        } catch (InvalidValue $exception) {
519 13
            $valid = false;
520
        }
521 26
        if ($valid) {
522 18
            if ($this->then !== null) {
523 18
                return self::unboolSchema($this->then)->process($data, $options, $path . '->then');
524
            }
525
        } else {
526 13
            if ($this->else !== null) {
527 6
                return self::unboolSchema($this->else)->process($data, $options, $path . '->else');
528
            }
529
        }
530 10
        return null;
531
    }
532
533
    /**
534
     * @param array $array
535
     * @param Context $options
536
     * @param string $path
537
     * @throws InvalidValue
538
     */
539 165
    private function processObjectRequired($array, Context $options, $path)
0 ignored issues
show
Unused Code introduced by
The parameter $options is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

539
    private function processObjectRequired($array, /** @scrutinizer ignore-unused */ Context $options, $path)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
540
    {
541 165
        foreach ($this->required as $item) {
542 161
            if (!array_key_exists($item, $array)) {
543 161
                $this->fail(new ObjectException('Required property missing: ' . $item . ', data: ' . json_encode($array, JSON_UNESCAPED_SLASHES), ObjectException::REQUIRED), $path);
544
            }
545
        }
546 133
    }
547
548
    /**
549
     * @param object $data
550
     * @param Context $options
551
     * @param string $path
552
     * @param ObjectItemContract|null $result
553
     * @return array|null|ClassStructure|ObjectItemContract
554
     * @throws InvalidValue
555
     * @throws \Exception
556
     * @throws \Swaggest\JsonDiff\Exception
557
     */
558 3266
    private function processObject($data, Context $options, $path, $result = null)
559
    {
560 3266
        $import = $options->import;
561
562 3266
        $hasMapping = isset($this->properties->__dataToProperty[$options->mapping]);
563
564 3266
        $array = !$data instanceof \stdClass ? get_object_vars($data) : (array)$data;
565
566
        // convert imported data to default mapping before validation
567 3266
        if ($import && $options->mapping !== self::DEFAULT_MAPPING) {
568 2
            if (isset($this->properties->__dataToProperty[$options->mapping])) {
569 2
                foreach ($this->properties->__dataToProperty[$options->mapping] as $dataName => $propertyName) {
570 2
                    if (!isset($array[$dataName])) {
571
                        continue;
572
                    }
573
574 2
                    $propertyName = isset($this->properties->__propertyToData[self::DEFAULT_MAPPING][$propertyName])
575 2
                        ? $this->properties->__propertyToData[self::DEFAULT_MAPPING][$propertyName]
576 2
                        : $propertyName;
577 2
                    if ($propertyName !== $dataName) {
578 2
                        $array[$propertyName] = $array[$dataName];
579 2
                        unset($array[$dataName]);
580
                    }
581
                }
582
            }
583
        }
584
585 3266
        if (!$options->skipValidation && $this->required !== null) {
586 165
            $this->processObjectRequired($array, $options, $path);
587
        }
588
589
        // build result entity
590 3265
        if ($import) {
591 3248
            if (!$options->validateOnly) {
592
593 3248
                if ($this->useObjectAsArray) {
594 1
                    $result = array();
595 3247
                } elseif (!$result instanceof ObjectItemContract) {
596
                    //* todo check performance impact
597 3247
                    if (null === $this->objectItemClass) {
598 1183
                        $result = new ObjectItem();
599
                    } else {
600 3236
                        $className = $this->objectItemClass;
601 3236
                        if ($options->objectItemClassMapping !== null) {
602
                            if (isset($options->objectItemClassMapping[$className])) {
603
                                $className = $options->objectItemClassMapping[$className];
604
                            }
605
                        }
606 3236
                        $result = new $className;
607
                    }
608
                    //*/
609
610
611 3247
                    if ($result instanceof ClassStructure) {
612 3232
                        if ($result->__validateOnSet) {
0 ignored issues
show
Bug Best Practice introduced by
The property __validateOnSet does not exist on Swaggest\JsonSchema\Structure\ObjectItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
613 3232
                            $result->__validateOnSet = false;
0 ignored issues
show
Bug Best Practice introduced by
The property __validateOnSet does not exist on Swaggest\JsonSchema\Structure\ObjectItem. Since you implemented __set, consider adding a @property annotation.
Loading history...
614
                            /** @noinspection PhpUnusedLocalVariableInspection */
615
                            /* todo check performance impact
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
616
                            $validateOnSetHandler = new ScopeExit(function () use ($result) {
617
                                $result->__validateOnSet = true;
618
                            });
619
                            //*/
620
                        }
621
                    }
622
623
                    //* todo check performance impact
624 3247
                    if ($result instanceof ObjectItemContract) {
625 3247
                        $result->setDocumentPath($path);
626
                    }
627
                    //*/
628
                }
629
            }
630
        }
631
632
        // @todo better check for schema id
633
634 3265
        if ($import
635 3265
            && isset($array[Schema::PROP_ID_D4])
636 3265
            && ($options->version === Schema::VERSION_DRAFT_04 || $options->version === Schema::VERSION_AUTO)
637 3265
            && is_string($array[Schema::PROP_ID_D4])) {
638 42
            $id = $array[Schema::PROP_ID_D4];
639 42
            $refResolver = $options->refResolver;
640 42
            $parentScope = $refResolver->updateResolutionScope($id);
641
            /** @noinspection PhpUnusedLocalVariableInspection */
642
            $defer = new ScopeExit(function () use ($parentScope, $refResolver) {
0 ignored issues
show
Unused Code introduced by
The assignment to $defer is dead and can be removed.
Loading history...
643 42
                $refResolver->setResolutionScope($parentScope);
644 42
            });
645
        }
646
647 3265
        if ($import
648 3265
            && isset($array[self::PROP_ID])
649 3265
            && ($options->version >= Schema::VERSION_DRAFT_06 || $options->version === Schema::VERSION_AUTO)
650 3265
            && is_string($array[self::PROP_ID])) {
651 114
            $id = $array[self::PROP_ID];
652 114
            $refResolver = $options->refResolver;
653 114
            $parentScope = $refResolver->updateResolutionScope($id);
654
            /** @noinspection PhpUnusedLocalVariableInspection */
655
            $defer = new ScopeExit(function () use ($parentScope, $refResolver) {
656 114
                $refResolver->setResolutionScope($parentScope);
657 114
            });
658
        }
659
660
        // check $ref
661 3265
        if ($import) {
662
            try {
663
664 3248
                $refProperty = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $refProperty is dead and can be removed.
Loading history...
665 3248
                $dereference = true;
666
667 3248
                if (isset($array[self::PROP_REF])) {
668 447
                    $refProperty = $this->properties[self::PROP_REF];
669
670 447
                    if (isset($refProperty) && ($refProperty->format !== Format::URI_REFERENCE)) {
671 14
                        $dereference = false;
672
                    }
673
                }
674
675
                if (
676 3248
                    isset($array[self::PROP_REF])
677 3248
                    && is_string($array[self::PROP_REF])
678 3248
                    && $dereference
679
                ) {
680 435
                    $refString = $array[self::PROP_REF];
681
682
                    // todo check performance impact
683 435
                    if ($refString === 'http://json-schema.org/draft-04/schema#'
684 425
                        || $refString === 'http://json-schema.org/draft-06/schema#'
685 435
                        || $refString === 'http://json-schema.org/draft-07/schema#') {
686 26
                        return Schema::schema();
687
                    }
688
689
                    // TODO consider process # by reference here ?
690 409
                    $refResolver = $options->refResolver;
691 409
                    $preRefScope = $refResolver->getResolutionScope();
692
                    /** @noinspection PhpUnusedLocalVariableInspection */
693
                    $deferRefScope = new ScopeExit(function () use ($preRefScope, $refResolver) {
0 ignored issues
show
Unused Code introduced by
The assignment to $deferRefScope is dead and can be removed.
Loading history...
694 409
                        $refResolver->setResolutionScope($preRefScope);
695 409
                    });
696
697 409
                    $ref = $refResolver->resolveReference($refString);
698 409
                    $data = self::unboolSchemaData($ref->getData());
699 409
                    if (!$options->validateOnly) {
700 409
                        if ($ref->isImported()) {
701 185
                            $refResult = $ref->getImported();
702 185
                            return $refResult;
703
                        }
704 409
                        $ref->setImported($result);
705
                        try {
706 409
                            $refResult = $this->process($data, $options, $path . '->$ref:' . $refString, $result);
707 409
                            if ($refResult instanceof ObjectItemContract) {
708 409
                                if ($refResult->getFromRefs()) {
709 47
                                    $refResult = clone $refResult; // @todo check performance, consider option
710
                                }
711 409
                                $refResult->setFromRef($refString);
712
                            }
713 409
                            $ref->setImported($refResult);
714 1
                        } catch (InvalidValue $exception) {
715 1
                            $ref->unsetImported();
716 1
                            throw $exception;
717
                        }
718 409
                        return $refResult;
719
                    } else {
720 3248
                        $this->process($data, $options, $path . '->$ref:' . $refString);
721
                    }
722
                }
723 1
            } catch (InvalidValue $exception) {
724 1
                $this->fail($exception, $path);
725
            }
726
        }
727
728
        /** @var Schema[]|null $properties */
729 3265
        $properties = null;
730
731 3265
        $nestedProperties = null;
732 3265
        if ($this->properties !== null) {
733 3251
            $properties = $this->properties->toArray(); // todo call directly
734
735 3251
            if ($this->properties instanceof Properties) {
0 ignored issues
show
introduced by
$this->properties is always a sub-type of Swaggest\JsonSchema\Constraint\Properties.
Loading history...
736 3251
                $nestedProperties = $this->properties->nestedProperties;
737
            } else {
738 588
                $nestedProperties = array();
739
            }
740
        }
741
742
743 3265
        if (!$options->skipValidation) {
744 3244
            if ($this->minProperties !== null && count($array) < $this->minProperties) {
745 4
                $this->fail(new ObjectException("Not enough properties", ObjectException::TOO_FEW), $path);
746
            }
747 3244
            if ($this->maxProperties !== null && count($array) > $this->maxProperties) {
748 3
                $this->fail(new ObjectException("Too many properties", ObjectException::TOO_MANY), $path);
749
            }
750 3244
            if ($this->propertyNames !== null) {
751 19
                $propertyNames = self::unboolSchema($this->propertyNames);
752 19
                foreach ($array as $key => $tmp) {
753 12
                    $propertyNames->process($key, $options, $path . '->propertyNames:' . $key);
0 ignored issues
show
introduced by
The method process() does not exist on Swaggest\JsonSchema\JsonSchema. Maybe you want to declare this class abstract? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

753
                    $propertyNames->/** @scrutinizer ignore-call */ 
754
                                    process($key, $options, $path . '->propertyNames:' . $key);
Loading history...
754
                }
755
            }
756
        }
757
758 3265
        $defaultApplied = array();
759 3265
        if ($import
760 3265
            && !$options->validateOnly
761 3265
            && $options->applyDefaults
762 3265
            && $properties !== null
763
        ) {
764 41
            foreach ($properties as $key => $property) {
765
                // todo check when property is \stdClass `{}` here (RefTest)
766 39
                if ($property instanceof SchemaContract && null !== $default = $property->getDefault()) {
767 6
                    if (!array_key_exists($key, $array)) {
768 6
                        $defaultApplied[$key] = true;
769 39
                        $array[$key] = $default;
770
                    }
771
                }
772
            }
773
        }
774
775 3265
        foreach ($array as $key => $value) {
776 3255
            if ($key === '' && PHP_VERSION_ID < 71000) {
777 1
                $this->fail(new InvalidValue('Empty property name'), $path);
778
            }
779
780 3254
            $found = false;
781
782 3254
            if (!$options->skipValidation && !empty($this->dependencies)) {
783 73
                $deps = $this->dependencies;
784 73
                if (isset($deps->$key)) {
785 63
                    $dependencies = $deps->$key;
786 63
                    $dependencies = self::unboolSchema($dependencies);
787 63
                    if ($dependencies instanceof SchemaContract) {
788 29
                        $dependencies->process($data, $options, $path . '->dependencies:' . $key);
789
                    } else {
790 34
                        foreach ($dependencies as $item) {
791 31
                            if (!array_key_exists($item, $array)) {
792 18
                                $this->fail(new ObjectException('Dependency property missing: ' . $item,
793 31
                                    ObjectException::DEPENDENCY_MISSING), $path);
794
                            }
795
                        }
796
                    }
797
                }
798
            }
799
800 3254
            $propertyFound = false;
801 3254
            if (isset($properties[$key])) {
802
                /** @var Schema[] $properties */
803 3244
                $prop = self::unboolSchema($properties[$key]);
804 3244
                $propertyFound = true;
805 3244
                $found = true;
806 3244
                if ($prop instanceof SchemaContract) {
807 3187
                    $value = $prop->process(
808 3187
                        $value,
809 3187
                        isset($defaultApplied[$key]) ? $options->withDefault() : $options,
810 3187
                        $path . '->properties:' . $key
811
                    );
812
                }
813
            }
814
815
            /** @var Egg[] $nestedEggs */
816 3249
            $nestedEggs = null;
817 3249
            if (isset($nestedProperties[$key])) {
818 6
                $found = true;
819 6
                $nestedEggs = $nestedProperties[$key];
820
                // todo iterate all nested props?
821 6
                $value = self::unboolSchema($nestedEggs[0]->propertySchema)->process($value, $options, $path . '->nestedProperties:' . $key);
822
            }
823
824 3249
            if ($this->patternProperties !== null) {
825 178
                foreach ($this->patternProperties as $pattern => $propertySchema) {
826 178
                    if (preg_match(Helper::toPregPattern($pattern), $key)) {
827 126
                        $found = true;
828 126
                        $value = self::unboolSchema($propertySchema)->process($value, $options,
829 126
                            $path . '->patternProperties[' . strtr($pattern, array('~' => '~1', ':' => '~2')) . ']:' . $key);
830 99
                        if (!$options->validateOnly && $import) {
831 156
                            $result->addPatternPropertyName($pattern, $key);
0 ignored issues
show
Bug introduced by
The method addPatternPropertyName() does not exist on Swaggest\JsonSchema\Structure\ObjectItemContract. It seems like you code against a sub-type of said class. However, the method does not exist in Swaggest\JsonSchema\Stru...\ClassStructureContract. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

831
                            $result->/** @scrutinizer ignore-call */ 
832
                                     addPatternPropertyName($pattern, $key);
Loading history...
832
                        }
833
                        //break; // todo manage multiple import data properly (pattern accessor)
834
                    }
835
                }
836
            }
837 3249
            if (!$found && $this->additionalProperties !== null) {
838 1021
                if (!$options->skipValidation && $this->additionalProperties === false) {
839 15
                    $this->fail(new ObjectException('Additional properties not allowed: ' . $key), $path);
840
                }
841
842 1021
                if ($this->additionalProperties instanceof SchemaContract) {
843 1021
                    $value = $this->additionalProperties->process($value, $options, $path . '->additionalProperties:' . $key);
844
                }
845
846 1014
                if ($import && !$this->useObjectAsArray && !$options->validateOnly) {
847 1010
                    $result->addAdditionalPropertyName($key);
848
                }
849
            }
850
851 3245
            $propertyName = $key;
852
853 3245
            if ($hasMapping) {
854 3221
                if (isset($this->properties->__dataToProperty[self::DEFAULT_MAPPING][$key])) {
855
                    // todo check performance of local map access
856 73
                    $propertyName = $this->properties->__dataToProperty[self::DEFAULT_MAPPING][$key];
857
                }
858
            }
859
860 3245
            if ($options->mapping !== self::DEFAULT_MAPPING) {
861 2
                if (!$import) {
862 2
                    if (isset($this->properties->__propertyToData[$options->mapping][$propertyName])) {
863
                        // todo check performance of local map access
864 2
                        $propertyName = $this->properties->__propertyToData[$options->mapping][$propertyName];
865
                    }
866
                }
867
            }
868
869 3245
            if (!$options->validateOnly && $nestedEggs && $import) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $nestedEggs of type Swaggest\JsonSchema\Structure\Egg[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
870 5
                foreach ($nestedEggs as $nestedEgg) {
871 5
                    $result->setNestedProperty($key, $value, $nestedEgg);
872
                }
873 5
                if ($propertyFound) {
874 5
                    $result->$propertyName = $value;
875
                }
876
            } else {
877 3244
                if (!$import && $hasMapping) {
878 29
                    if (isset($this->properties->__propertyToData[$options->mapping][$propertyName])) {
879 4
                        $propertyName = $this->properties->__propertyToData[$options->mapping][$propertyName];
880
                    }
881
                }
882
883 3244
                if ($this->useObjectAsArray && $import) {
884 1
                    $result[$propertyName] = $value;
885
                } else {
886 3244
                    if ($found || !$import) {
887 3243
                        $result->$propertyName = $value;
888 1178
                    } elseif (!isset($result->$propertyName)) {
889 3245
                        $result->$propertyName = $value;
890
                    }
891
                }
892
            }
893
        }
894
895 3252
        return $result;
896
    }
897
898
    /**
899
     * @param array $data
900
     * @param Context $options
901
     * @param string $path
902
     * @param array $result
903
     * @return mixed
904
     * @throws InvalidValue
905
     * @throws \Exception
906
     * @throws \Swaggest\JsonDiff\Exception
907
     */
908 1238
    private function processArray($data, Context $options, $path, $result)
909
    {
910 1238
        $count = count($data);
911 1238
        if (!$options->skipValidation) {
912 1038
            if ($this->minItems !== null && $count < $this->minItems) {
913 9
                $this->fail(new ArrayException("Not enough items in array"), $path);
914
            }
915
916 1032
            if ($this->maxItems !== null && $count > $this->maxItems) {
917 6
                $this->fail(new ArrayException("Too many items in array"), $path);
918
            }
919
        }
920
921 1226
        $pathItems = 'items';
922 1226
        $this->items = self::unboolSchema($this->items);
923 1226
        if ($this->items instanceof SchemaContract) {
0 ignored issues
show
introduced by
$this->items is never a sub-type of Swaggest\JsonSchema\SchemaContract.
Loading history...
924 873
            $items = array();
925 873
            $additionalItems = $this->items;
926 703
        } elseif ($this->items === null) { // items defaults to empty schema so everything is valid
927 703
            $items = array();
928 703
            $additionalItems = true;
929
        } else { // listed items
930 104
            $items = $this->items;
931 104
            $additionalItems = $this->additionalItems;
932 104
            $pathItems = 'additionalItems';
933
        }
934
935
        /**
936
         * @var Schema|Schema[] $items
937
         * @var null|bool|Schema $additionalItems
938
         */
939 1226
        $itemsLen = is_array($items) ? count($items) : 0;
940 1226
        $index = 0;
941 1226
        foreach ($result as $key => $value) {
942 1101
            if ($index < $itemsLen) {
943 94
                $itemSchema = self::unboolSchema($items[$index]);
944 94
                $result[$key] = $itemSchema->process($value, $options, $path . '->items:' . $index);
945
            } else {
946 1101
                if ($additionalItems instanceof SchemaContract) {
947 847
                    $result[$key] = $additionalItems->process($value, $options, $path . '->' . $pathItems
948 847
                        . '[' . $index . ']:' . $index);
949 587
                } elseif (!$options->skipValidation && $additionalItems === false) {
950 6
                    $this->fail(new ArrayException('Unexpected array item'), $path);
951
                }
952
            }
953 1079
            ++$index;
954
        }
955
956 1200
        if (!$options->skipValidation && $this->uniqueItems) {
957 522
            if (!UniqueItems::isValid($data)) {
958 22
                $this->fail(new ArrayException('Array is not unique'), $path);
959
            }
960
        }
961
962 1181
        if (!$options->skipValidation && $this->contains !== null) {
963
            /** @var Schema|bool $contains */
964 36
            $contains = $this->contains;
965 36
            if ($contains === false) {
0 ignored issues
show
introduced by
The condition $contains === false is always false.
Loading history...
966 4
                $this->fail(new ArrayException('Contains is false'), $path);
967
            }
968 32
            if ($count === 0) {
969 7
                $this->fail(new ArrayException('Empty array fails contains constraint'), $path);
970
            }
971 25
            if ($contains === true) {
0 ignored issues
show
introduced by
The condition $contains === true is always false.
Loading history...
972 2
                $contains = self::unboolSchema($contains);
973
            }
974 25
            $containsOk = false;
975 25
            foreach ($data as $key => $item) {
976
                try {
977 25
                    $contains->process($item, $options, $path . '->' . $key);
978 17
                    $containsOk = true;
979 17
                    break;
980 21
                } catch (InvalidValue $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
981
                }
982
            }
983 25
            if (!$containsOk) {
984 8
                $this->fail(new ArrayException('Array fails contains constraint'), $path);
985
            }
986
        }
987 1162
        return $result;
988
    }
989
990
    /**
991
     * @param mixed|string $data
992
     * @param Context $options
993
     * @param string $path
994
     * @return bool|mixed|string
995
     * @throws InvalidValue
996
     */
997 20
    private function processContent($data, Context $options, $path)
998
    {
999
        try {
1000 20
            if ($options->unpackContentMediaType) {
1001 10
                return Content::process($options, $this->contentEncoding, $this->contentMediaType, $data, $options->import);
1002
            } else {
1003 10
                Content::process($options, $this->contentEncoding, $this->contentMediaType, $data, true);
1004
            }
1005 4
        } catch (InvalidValue $exception) {
1006 4
            $this->fail($exception, $path);
1007
        }
1008 10
        return $data;
1009
    }
1010
1011
    /**
1012
     * @param mixed $data
1013
     * @param Context $options
1014
     * @param string $path
1015
     * @param mixed|null $result
1016
     * @return array|mixed|null|object|\stdClass
1017
     * @throws InvalidValue
1018
     * @throws \Exception
1019
     * @throws \Swaggest\JsonDiff\Exception
1020
     */
1021 3313
    public function process($data, Context $options, $path = '#', $result = null)
1022
    {
1023 3313
        $origData = $data;
0 ignored issues
show
Unused Code introduced by
The assignment to $origData is dead and can be removed.
Loading history...
1024 3313
        $import = $options->import;
1025
1026 3313
        if (!$import && $data instanceof SchemaExporter) {
1027 2
            $data = $data->exportSchema(); // Used to export ClassStructure::schema()
1028
        }
1029
1030 3313
        if (!$import && $data instanceof ObjectItemContract) {
1031 808
            $result = new \stdClass();
1032
1033 808
            if ('#' === $path) {
1034 794
                $injectDefinitions = new ScopeExit(function () use ($result, $options) {
0 ignored issues
show
Unused Code introduced by
The assignment to $injectDefinitions is dead and can be removed.
Loading history...
1035 794
                    foreach ($options->exportedDefinitions as $ref => $data) {
1036 6
                        if ($data !== null) {
1037 6
                            JsonPointer::add($result, JsonPointer::splitPath($ref), $data,
1038
                                /*JsonPointer::SKIP_IF_ISSET + */
1039 6
                                JsonPointer::RECURSIVE_KEY_CREATION);
1040
                        }
1041
                    }
1042 794
                });
1043
            }
1044
1045 808
            if ($options->isRef) {
1046 6
                $options->isRef = false;
1047
            } else {
1048 808
                if ('#' !== $path && $refs = $data->getFromRefs()) {
1049 6
                    $ref = $refs[0];
1050 6
                    if (!array_key_exists($ref, $options->exportedDefinitions) && strpos($ref, '://') === false) {
1051 6
                        $exported = null;
1052 6
                        $options->exportedDefinitions[$ref] = &$exported;
1053 6
                        $options->isRef = true;
1054 6
                        $exported = $this->process($data, $options, $ref);
1055 6
                        unset($exported);
1056
                    }
1057
1058 6
                    $countRefs = count($refs);
1059 6
                    for ($i = 1; $i < $countRefs; $i++) {
1060 2
                        $ref = $refs[$i];
1061 2
                        if (!array_key_exists($ref, $options->exportedDefinitions) && strpos($ref, '://') === false) {
1062 2
                            $exported = new \stdClass();
1063 2
                            $exported->{self::PROP_REF} = $refs[$i - 1];
1064 2
                            $options->exportedDefinitions[$ref] = $exported;
1065
                        }
1066
                    }
1067
1068 6
                    $result->{self::PROP_REF} = $refs[$countRefs - 1];
1069 6
                    return $result;
1070
                }
1071
            }
1072
1073 808
            if ($options->circularReferences->contains($data)) {
1074
                /** @noinspection PhpIllegalArrayKeyTypeInspection */
1075 1
                $path = $options->circularReferences[$data];
1076 1
                $result->{self::PROP_REF} = PointerUtil::getDataPointer($path, true);
1077 1
                return $result;
1078
            }
1079 808
            $options->circularReferences->attach($data, $path);
1080
1081 808
            $data = $data->jsonSerialize();
1082
        }
1083
1084 3313
        $path .= $this->getFromRefPath();
1085
1086 3313
        if (!$import && is_array($data) && $this->useObjectAsArray) {
1087 1
            $data = (object)$data;
1088
        }
1089
1090 3313
        if (null !== $options->dataPreProcessor) {
1091
            $data = $options->dataPreProcessor->process($data, $this, $import);
1092
        }
1093
1094 3313
        if ($result === null) {
1095 3313
            $result = $data;
1096
        }
1097
1098 3313
        if ($options->skipValidation) {
1099 1450
            goto skipValidation;
1100
        }
1101
1102 3275
        if ($this->type !== null) {
1103 3254
            $this->processType($data, $options, $path);
1104
        }
1105
1106 3274
        if ($this->enum !== null) {
1107 1510
            $this->processEnum($data, $path);
1108
        }
1109
1110 3274
        if (array_key_exists(self::CONST_PROPERTY, $this->__arrayOfData)) {
1111 43
            $this->processConst($data, $path);
1112
        }
1113
1114 3274
        if ($this->not !== null) {
1115 70
            $this->processNot($data, $options, $path);
1116
        }
1117
1118 3274
        if (is_string($data)) {
1119 2328
            $this->processString($data, $path);
1120
        }
1121
1122 3274
        if (is_int($data) || is_float($data)) {
1123 1088
            $this->processNumeric($data, $path);
1124
        }
1125
1126 3273
        if ($this->if !== null) {
1127 26
            $result = $this->processIf($data, $options, $path);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $result is correct as $this->processIf($data, $options, $path) targeting Swaggest\JsonSchema\Schema::processIf() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1128
        }
1129
1130
        skipValidation:
1131
1132 3311
        if ($this->oneOf !== null) {
1133 107
            $result = $this->processOneOf($data, $options, $path);
1134
        }
1135
1136 3311
        if ($this->anyOf !== null) {
1137 1760
            $result = $this->processAnyOf($data, $options, $path);
1138
        }
1139
1140 3311
        if ($this->allOf !== null) {
1141 354
            $result = $this->processAllOf($data, $options, $path);
1142
        }
1143
1144 3311
        if (is_object($data)) {
1145 3266
            $result = $this->processObject($data, $options, $path, $result);
1146
        }
1147
1148 3308
        if (is_array($data)) {
1149 1238
            $result = $this->processArray($data, $options, $path, $result);
0 ignored issues
show
Bug introduced by
It seems like $result can also be of type Swaggest\JsonSchema\Schema and Swaggest\JsonSchema\Structure\ClassStructure and Swaggest\JsonSchema\Structure\ObjectItemContract and object and stdClass; however, parameter $result of Swaggest\JsonSchema\Schema::processArray() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1149
            $result = $this->processArray($data, $options, $path, /** @scrutinizer ignore-type */ $result);
Loading history...
1150
        }
1151
1152 3308
        if ($this->contentEncoding !== null || $this->contentMediaType !== null) {
1153 20
            if ($import && !is_string($data)) {
1154 6
                return $result;
1155
            }
1156 20
            $result = $this->processContent($data, $options, $path);
1157
        }
1158
1159 3308
        return $result;
1160
    }
1161
1162
    /**
1163
     * @param boolean $useObjectAsArray
1164
     * @return Schema
1165
     */
1166 1
    public function setUseObjectAsArray($useObjectAsArray)
1167
    {
1168 1
        $this->useObjectAsArray = $useObjectAsArray;
1169 1
        return $this;
1170
    }
1171
1172
    /**
1173
     * @param InvalidValue $exception
1174
     * @param string $path
1175
     * @throws InvalidValue
1176
     */
1177 1263
    private function fail(InvalidValue $exception, $path)
1178
    {
1179 1263
        $exception->addPath($path);
1180 1263
        throw $exception;
1181
    }
1182
1183 16
    public static function integer()
1184
    {
1185 16
        $schema = new static();
1186 16
        $schema->type = Type::INTEGER;
1187 16
        return $schema;
1188
    }
1189
1190 4
    public static function number()
1191
    {
1192 4
        $schema = new static();
1193 4
        $schema->type = Type::NUMBER;
1194 4
        return $schema;
1195
    }
1196
1197 13
    public static function string()
1198
    {
1199 13
        $schema = new static();
1200 13
        $schema->type = Type::STRING;
1201 13
        return $schema;
1202
    }
1203
1204 4
    public static function boolean()
1205
    {
1206 4
        $schema = new static();
1207 4
        $schema->type = Type::BOOLEAN;
1208 4
        return $schema;
1209
    }
1210
1211 8
    public static function object()
1212
    {
1213 8
        $schema = new static();
1214 8
        $schema->type = Type::OBJECT;
1215 8
        return $schema;
1216
    }
1217
1218 1
    public static function arr()
1219
    {
1220 1
        $schema = new static();
1221 1
        $schema->type = Type::ARR;
1222 1
        return $schema;
1223
    }
1224
1225
    public static function null()
1226
    {
1227
        $schema = new static();
1228
        $schema->type = Type::NULL;
1229
        return $schema;
1230
    }
1231
1232
1233
    /**
1234
     * @param Properties $properties
1235
     * @return Schema
1236
     */
1237 3
    public function setProperties($properties)
1238
    {
1239 3
        $this->properties = $properties;
1240 3
        return $this;
1241
    }
1242
1243
    /**
1244
     * @param string $name
1245
     * @param Schema $schema
1246
     * @return $this
1247
     */
1248 5
    public function setProperty($name, $schema)
1249
    {
1250 5
        if (null === $this->properties) {
1251 5
            $this->properties = new Properties();
1252
        }
1253 5
        $this->properties->__set($name, $schema);
1254 5
        return $this;
1255
    }
1256
1257
    /**
1258
     * @param string $name
1259
     * @param SchemaContract $schema
1260
     * @return $this
1261
     * @throws Exception
1262
     */
1263
    public function setPatternProperty($name, $schema)
1264
    {
1265
        if (null === $this->patternProperties) {
1266
            $this->patternProperties = new Properties();
1267
        }
1268
        $this->patternProperties->__set($name, $schema);
1269
        return $this;
1270
    }
1271
1272
1273
    /** @var mixed[] */
1274
    private $metaItems = array();
1275
1276 1
    public function addMeta($meta, $name = null)
1277
    {
1278 1
        if ($name === null) {
1279 1
            $name = get_class($meta);
1280
        }
1281 1
        $this->metaItems[$name] = $meta;
1282 1
        return $this;
1283
    }
1284
1285 1
    public function getMeta($name)
1286
    {
1287 1
        if (isset($this->metaItems[$name])) {
1288 1
            return $this->metaItems[$name];
1289
        }
1290
        return null;
1291
    }
1292
1293
    /**
1294
     * @param Context $options
1295
     * @return ObjectItemContract
1296
     */
1297 5
    public function makeObjectItem(Context $options = null)
1298
    {
1299 5
        if (null === $this->objectItemClass) {
1300
            return new ObjectItem();
1301
        } else {
1302 5
            $className = $this->objectItemClass;
1303 5
            if ($options !== null) {
1304
                if (isset($options->objectItemClassMapping[$className])) {
1305
                    $className = $options->objectItemClassMapping[$className];
1306
                }
1307
            }
1308 5
            return new $className;
1309
        }
1310
    }
1311
1312
    /**
1313
     * @param mixed $schema
1314
     * @return mixed|Schema
1315
     */
1316 3324
    private static function unboolSchema($schema)
1317
    {
1318 3324
        static $trueSchema;
1319 3324
        static $falseSchema;
1320
1321 3324
        if (null === $trueSchema) {
1322 1
            $trueSchema = new Schema();
1323 1
            $trueSchema->__booleanSchema = true;
1324 1
            $falseSchema = new Schema();
1325 1
            $falseSchema->not = $trueSchema;
1326 1
            $falseSchema->__booleanSchema = false;
1327
        }
1328
1329 3324
        if ($schema === true) {
1330 108
            return $trueSchema;
1331 3296
        } elseif ($schema === false) {
1332 94
            return $falseSchema;
1333
        } else {
1334 3264
            return $schema;
1335
        }
1336
    }
1337
1338
    /**
1339
     * @param mixed $data
1340
     * @return \stdClass
1341
     */
1342 409
    private static function unboolSchemaData($data)
1343
    {
1344 409
        static $trueSchema;
1345 409
        static $falseSchema;
1346
1347 409
        if (null === $trueSchema) {
1348 1
            $trueSchema = new \stdClass();
1349 1
            $falseSchema = new \stdClass();
1350 1
            $falseSchema->not = $trueSchema;
1351
        }
1352
1353 409
        if ($data === true) {
1354 6
            return $trueSchema;
1355 405
        } elseif ($data === false) {
1356 5
            return $falseSchema;
1357
        } else {
1358 400
            return $data;
1359
        }
1360
    }
1361
1362 39
    public function getDefault()
1363
    {
1364 39
        return $this->default;
1365
    }
1366
1367 99
    public function getProperties()
1368
    {
1369 99
        return $this->properties;
1370
    }
1371
1372
    public function getObjectItemClass()
1373
    {
1374
        return $this->objectItemClass;
1375
    }
1376
1377
    /**
1378
     * @return string[]
1379
     */
1380
    public function getPropertyNames()
1381
    {
1382
        return array_keys($this->getProperties()->toArray());
1383
    }
1384
1385
    /**
1386
     * @return string[]
1387
     */
1388 97
    public function getNestedPropertyNames()
1389
    {
1390 97
        return $this->getProperties()->nestedPropertyNames;
1391
    }
1392
1393
}
1394