Passed
Pull Request — master (#26)
by Viacheslav
03:12
created

Schema::processObjectRequired()   C

Complexity

Conditions 11
Paths 13

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 11.0295

Importance

Changes 0
Metric Value
dl 0
loc 27
c 0
b 0
f 0
ccs 15
cts 16
cp 0.9375
rs 5.2653
cc 11
eloc 17
nc 13
nop 3
crap 11.0295

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
namespace Swaggest\JsonSchema;
4
5
6
use PhpLang\ScopeExit;
7
use Swaggest\JsonDiff\JsonDiff;
8
use Swaggest\JsonSchema\Constraint\Content;
9
use Swaggest\JsonSchema\Constraint\Format;
10
use Swaggest\JsonSchema\Constraint\Properties;
11
use Swaggest\JsonSchema\Constraint\Type;
12
use Swaggest\JsonSchema\Constraint\UniqueItems;
13
use Swaggest\JsonSchema\Exception\ArrayException;
14
use Swaggest\JsonSchema\Exception\ConstException;
15
use Swaggest\JsonSchema\Exception\EnumException;
16
use Swaggest\JsonSchema\Exception\LogicException;
17
use Swaggest\JsonSchema\Exception\NumericException;
18
use Swaggest\JsonSchema\Exception\ObjectException;
19
use Swaggest\JsonSchema\Exception\StringException;
20
use Swaggest\JsonSchema\Exception\TypeException;
21
use Swaggest\JsonSchema\Meta\Meta;
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|Schema[]|Schema */
51
    public $properties;
52
    /** @var Schema|bool */
53
    public $additionalProperties;
54
    /** @var Schema[] */
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
    private $useObjectAsArray = false;
84
85
    private $__dataToProperty = array();
86
    private $__propertyToData = array();
87
88
    private $__booleanSchema;
89
90 2
    public function addPropertyMapping($dataName, $propertyName, $mapping = self::DEFAULT_MAPPING)
91
    {
92 2
        $this->__dataToProperty[$mapping][$dataName] = $propertyName;
93 2
        $this->__propertyToData[$mapping][$propertyName] = $dataName;
94 2
        return $this;
95
    }
96
97
    /**
98
     * @param mixed $data
99
     * @param Context|null $options
100
     * @return SchemaContract
101
     * @throws Exception
102
     * @throws InvalidValue
103
     * @throws \Exception
104
     */
105 3171
    public static function import($data, Context $options = null)
106
    {
107 3171
        if (null === $options) {
108 20
            $options = new Context();
109
        }
110
111 3171
        $options->applyDefaults = false;
112
113 3171
        if (isset($options->schemasCache) && is_object($data)) {
114
            if ($options->schemasCache->contains($data)) {
115
                return $options->schemasCache->offsetGet($data);
116
            } else {
117
                $schema = parent::import($data, $options);
118
                $options->schemasCache->attach($data, $schema);
119
                return $schema;
120
            }
121
        }
122
123
        // string $data is expected to be $ref uri
124 3171
        if (is_string($data)) {
125 4
            $data = (object)array(self::PROP_REF => $data);
126
        }
127
128 3171
        $data = self::unboolSchema($data);
129 3171
        if ($data instanceof SchemaContract) {
130 72
            return $data;
131
        }
132
133 3099
        return parent::import($data, $options);
134
    }
135
136
    /**
137
     * @param mixed $data
138
     * @param Context|null $options
139
     * @return array|mixed|null|object|\stdClass
140
     * @throws Exception
141
     * @throws InvalidValue
142
     * @throws \Exception
143
     */
144 3193
    public function in($data, Context $options = null)
145
    {
146 3193
        if (null !== $this->__booleanSchema) {
147 72
            if ($this->__booleanSchema) {
148 36
                return $data;
149 36
            } elseif (empty($options->skipValidation)) {
150 18
                $this->fail(new InvalidValue('Denied by false schema'), '#');
151
            }
152
        }
153
154 3139
        if ($options === null) {
155 49
            $options = new Context();
156
        }
157
158 3139
        $options->import = true;
159
160 3139
        if ($options->refResolver === null) {
161 2820
            $options->refResolver = new RefResolver($data);
162
        } else {
163 1694
            $options->refResolver->setRootData($data);
164
        }
165
166 3139
        if ($options->remoteRefProvider) {
167 3078
            $options->refResolver->setRemoteRefProvider($options->remoteRefProvider);
168
        }
169
170 3139
        $options->refResolver->preProcessReferences($data, $options);
171
172 3139
        return $this->process($data, $options, '#');
173
    }
174
175
176
    /**
177
     * @param mixed $data
178
     * @param Context|null $options
179
     * @return array|mixed|null|object|\stdClass
180
     * @throws InvalidValue
181
     * @throws \Exception
182
     */
183 2361
    public function out($data, Context $options = null)
184
    {
185 2361
        if ($options === null) {
186 952
            $options = new Context();
187
        }
188
189 2361
        $options->circularReferences = new \SplObjectStorage();
190 2361
        $options->import = false;
191 2361
        return $this->process($data, $options);
192
    }
193
194
    /**
195
     * @param mixed $data
196
     * @param Context $options
197
     * @param string $path
198
     * @throws InvalidValue
199
     * @throws \Exception
200
     */
201 3121
    private function processType($data, Context $options, $path = '#')
202
    {
203 3121
        if ($options->tolerateStrings && is_string($data)) {
204
            $valid = Type::readString($this->type, $data);
205
        } else {
206 3121
            $valid = Type::isValid($this->type, $data, $options->version);
207
        }
208 3121
        if (!$valid) {
209 674
            $this->fail(new TypeException(ucfirst(
210 674
                    implode(', ', is_array($this->type) ? $this->type : array($this->type))
211 674
                    . ' expected, ' . json_encode($data) . ' received')
212 674
            ), $path);
213
        }
214 3119
    }
215
216
    /**
217
     * @param mixed $data
218
     * @param string $path
219
     * @throws InvalidValue
220
     * @throws \Exception
221
     */
222 1459
    private function processEnum($data, $path = '#')
223
    {
224 1459
        $enumOk = false;
225 1459
        foreach ($this->enum as $item) {
226 1459
            if ($item === $data) { // todo support complex structures here
227 1445
                $enumOk = true;
228 1459
                break;
229
            }
230
        }
231 1459
        if (!$enumOk) {
232 91
            $this->fail(new EnumException('Enum failed, enum: ' . json_encode($this->enum) . ', data: ' . json_encode($data)), $path);
233
        }
234 1445
    }
235
236
    /**
237
     * @param mixed $data
238
     * @param string $path
239
     * @throws InvalidValue
240
     * @throws \Swaggest\JsonDiff\Exception
241
     */
242 43
    private function processConst($data, $path)
243
    {
244 43
        if ($this->const !== $data) {
245 37
            if ((is_object($this->const) && is_object($data))
246 37
                || (is_array($this->const) && is_array($data))) {
247 15
                $diff = new JsonDiff($this->const, $data,
248 15
                    JsonDiff::STOP_ON_DIFF);
249 15
                if ($diff->getDiffCnt() != 0) {
250 15
                    $this->fail(new ConstException('Const failed'), $path);
251
                }
252
            } else {
253 22
                $this->fail(new ConstException('Const failed'), $path);
254
            }
255
        }
256 20
    }
257
258
    /**
259
     * @param mixed $data
260
     * @param Context $options
261
     * @param string $path
262
     * @throws InvalidValue
263
     * @throws \Exception
264
     * @throws \Swaggest\JsonDiff\Exception
265
     */
266 69
    private function processNot($data, Context $options, $path)
267
    {
268 69
        $exception = false;
269
        try {
270 69
            self::unboolSchema($this->not)->process($data, $options, $path . '->not');
271 16
        } catch (InvalidValue $exception) {
272
            // Expected exception
273
        }
274 69
        if ($exception === false) {
275 55
            $this->fail(new LogicException('Not ' . json_encode($this->not) . ' expected, ' . json_encode($data) . ' received'), $path);
276
        }
277 16
    }
278
279
    /**
280
     * @param string $data
281
     * @param string $path
282
     * @throws InvalidValue
283
     */
284 2229
    private function processString($data, $path)
285
    {
286 2229
        if ($this->minLength !== null) {
287 38
            if (mb_strlen($data, 'UTF-8') < $this->minLength) {
288 9
                $this->fail(new StringException('String is too short', StringException::TOO_SHORT), $path);
289
            }
290
        }
291 2223
        if ($this->maxLength !== null) {
292 43
            if (mb_strlen($data, 'UTF-8') > $this->maxLength) {
293 19
                $this->fail(new StringException('String is too long', StringException::TOO_LONG), $path);
294
            }
295
        }
296 2220
        if ($this->pattern !== null) {
297 18
            if (0 === preg_match(Helper::toPregPattern($this->pattern), $data)) {
298 4
                $this->fail(new StringException(json_encode($data) . ' does not match to '
299 4
                    . $this->pattern, StringException::PATTERN_MISMATCH), $path);
300
            }
301
        }
302 2220
        if ($this->format !== null) {
303 403
            $validationError = Format::validationError($this->format, $data);
304 403
            if ($validationError !== null) {
305 137
                if (!($this->format === "uri" && substr($path, -3) === ':id')) {
306 122
                    $this->fail(new StringException($validationError), $path);
307
                }
308
            }
309
        }
310 2220
    }
311
312
    /**
313
     * @param float|int $data
314
     * @param string $path
315
     * @throws InvalidValue
316
     */
317 1041
    private function processNumeric($data, $path)
318
    {
319 1041
        if ($this->multipleOf !== null) {
320 39
            $div = $data / $this->multipleOf;
321 39
            if ($div != (int)$div) {
322 15
                $this->fail(new NumericException($data . ' is not multiple of ' . $this->multipleOf, NumericException::MULTIPLE_OF), $path);
323
            }
324
        }
325
326 1041
        if ($this->exclusiveMaximum !== null && !is_bool($this->exclusiveMaximum)) {
327 32
            if ($data >= $this->exclusiveMaximum) {
328 18
                $this->fail(new NumericException(
329 18
                    'Value less or equal than ' . $this->exclusiveMaximum . ' expected, ' . $data . ' received',
330 18
                    NumericException::MAXIMUM), $path);
331
            }
332
        }
333
334 1041
        if ($this->exclusiveMinimum !== null && !is_bool($this->exclusiveMinimum)) {
335 24
            if ($data <= $this->exclusiveMinimum) {
336 12
                $this->fail(new NumericException(
337 12
                    'Value more or equal than ' . $this->exclusiveMinimum . ' expected, ' . $data . ' received',
338 12
                    NumericException::MINIMUM), $path);
339
            }
340
        }
341
342 1041
        if ($this->maximum !== null) {
343 43
            if ($this->exclusiveMaximum === true) {
344 3
                if ($data >= $this->maximum) {
345 2
                    $this->fail(new NumericException(
346 2
                        'Value less or equal than ' . $this->maximum . ' expected, ' . $data . ' received',
347 3
                        NumericException::MAXIMUM), $path);
348
                }
349
            } else {
350 40
                if ($data > $this->maximum) {
351 13
                    $this->fail(new NumericException(
352 13
                        'Value less than ' . $this->minimum . ' expected, ' . $data . ' received',
353 13
                        NumericException::MAXIMUM), $path);
354
                }
355
            }
356
        }
357
358 1041
        if ($this->minimum !== null) {
359 516
            if ($this->exclusiveMinimum === true) {
360 93
                if ($data <= $this->minimum) {
361 2
                    $this->fail(new NumericException(
362 2
                        'Value more or equal than ' . $this->minimum . ' expected, ' . $data . ' received',
363 93
                        NumericException::MINIMUM), $path);
364
                }
365
            } else {
366 441
                if ($data < $this->minimum) {
367 43
                    $this->fail(new NumericException(
368 43
                        'Value more than ' . $this->minimum . ' expected, ' . $data . ' received',
369 43
                        NumericException::MINIMUM), $path);
370
                }
371
            }
372
        }
373 1040
    }
374
375
    /**
376
     * @param mixed $data
377
     * @param Context $options
378
     * @param string $path
379
     * @return array|mixed|null|object|\stdClass
380
     * @throws InvalidValue
381
     * @throws \Exception
382
     * @throws \Swaggest\JsonDiff\Exception
383
     */
384 101
    private function processOneOf($data, Context $options, $path)
385
    {
386 101
        $successes = 0;
387 101
        $failures = '';
388 101
        $subErrors = [];
389 101
        $skipValidation = false;
390 101
        if ($options->skipValidation) {
391 41
            $skipValidation = true;
392 41
            $options->skipValidation = false;
393
        }
394
395 101
        $result = $data;
396 101
        foreach ($this->oneOf as $index => $item) {
397
            try {
398 101
                $result = self::unboolSchema($item)->process($data, $options, $path . '->oneOf[' . $index . ']');
399 79
                $successes++;
400 79
                if ($successes > 1 || $options->skipValidation) {
401 79
                    break;
402
                }
403 69
            } catch (InvalidValue $exception) {
404 69
                $subErrors[$index] = $exception;
405 101
                $failures .= ' ' . $index . ': ' . Helper::padLines(' ', $exception->getMessage()) . "\n";
406
                // Expected exception
407
            }
408
        }
409 101
        if ($skipValidation) {
410 41
            $options->skipValidation = true;
411 41
            if ($successes === 0) {
412 8
                $result = self::unboolSchema($this->oneOf[0])->process($data, $options, $path . '->oneOf[0]');
413
            }
414
        }
415
416 101
        if (!$options->skipValidation) {
417 60
            if ($successes === 0) {
418 15
                $exception = new LogicException('No valid results for oneOf {' . "\n" . substr($failures, 0, -1) . "\n}");
419 15
                $exception->error = 'No valid results for oneOf';
420 15
                $exception->subErrors = $subErrors;
421 15
                $this->fail($exception, $path);
422 46
            } elseif ($successes > 1) {
423 17
                $exception = new LogicException('More than 1 valid result for oneOf: '
424 17
                    . $successes . '/' . count($this->oneOf) . ' valid results for oneOf {'
425 17
                    . "\n" . substr($failures, 0, -1) . "\n}");
426 17
                $exception->error = 'More than 1 valid result for oneOf';
427 17
                $exception->subErrors = $subErrors;
428 17
                $this->fail($exception, $path);
429
            }
430
        }
431 71
        return $result;
432
    }
433
434
    /**
435
     * @param mixed $data
436
     * @param Context $options
437
     * @param string $path
438
     * @return array|mixed|null|object|\stdClass
439
     * @throws InvalidValue
440
     * @throws \Exception
441
     * @throws \Swaggest\JsonDiff\Exception
442
     */
443 1704
    private function processAnyOf($data, Context $options, $path)
444
    {
445 1704
        $successes = 0;
446 1704
        $failures = '';
447 1704
        $subErrors = [];
448 1704
        $result = $data;
449 1704
        foreach ($this->anyOf as $index => $item) {
450
            try {
451 1704
                $result = self::unboolSchema($item)->process($data, $options, $path . '->anyOf[' . $index . ']');
452 1698
                $successes++;
453 1698
                if ($successes) {
454 1698
                    break;
455
                }
456 430
            } catch (InvalidValue $exception) {
457 430
                $subErrors[$index] = $exception;
458 430
                $failures .= ' ' . $index . ': ' . $exception->getMessage() . "\n";
459
                // Expected exception
460
            }
461
        }
462 1704
        if (!$successes && !$options->skipValidation) {
463 29
            $exception = new LogicException('No valid results for anyOf {' . "\n"
464 29
                . substr(Helper::padLines(' ', $failures, false), 0, -1)
465 29
                . "\n}");
466 29
            $exception->error = 'No valid results for anyOf';
467 29
            $exception->subErrors = $subErrors;
468 29
            $this->fail($exception, $path);
469
        }
470 1698
        return $result;
471
    }
472
473
    /**
474
     * @param mixed $data
475
     * @param Context $options
476
     * @param string $path
477
     * @return array|mixed|null|object|\stdClass
478
     * @throws InvalidValue
479
     * @throws \Exception
480
     * @throws \Swaggest\JsonDiff\Exception
481
     */
482 352
    private function processAllOf($data, Context $options, $path)
483
    {
484 352
        $result = $data;
485 352
        foreach ($this->allOf as $index => $item) {
486 352
            $result = self::unboolSchema($item)->process($data, $options, $path . '->allOf[' . $index . ']');
487
        }
488 314
        return $result;
489
    }
490
491
    /**
492
     * @param mixed $data
493
     * @param Context $options
494
     * @param string $path
495
     * @return array|mixed|null|object|\stdClass
496
     * @throws InvalidValue
497
     * @throws \Exception
498
     * @throws \Swaggest\JsonDiff\Exception
499
     */
500 26
    private function processIf($data, Context $options, $path)
501
    {
502 26
        $valid = true;
503
        try {
504 26
            self::unboolSchema($this->if)->process($data, $options, $path . '->if');
505 13
        } catch (InvalidValue $exception) {
506 13
            $valid = false;
507
        }
508 26
        if ($valid) {
509 18
            if ($this->then !== null) {
510 18
                return self::unboolSchema($this->then)->process($data, $options, $path . '->then');
511
            }
512
        } else {
513 13
            if ($this->else !== null) {
514 6
                return self::unboolSchema($this->else)->process($data, $options, $path . '->else');
515
            }
516
        }
517 10
        return null;
518
    }
519
520
    /**
521
     * @param \stdClass $data
522
     * @param Context $options
523
     * @param string $path
524
     * @throws InvalidValue
525
     */
526 160
    private function processObjectRequired($data, Context $options, $path)
527
    {
528 160
        if (isset($this->__dataToProperty[$options->mapping])) {
529 2
            if ($options->import) {
530 1
                foreach ($this->required as $item) {
531 1
                    if (isset($this->__propertyToData[$options->mapping][$item])) {
532 1
                        $item = $this->__propertyToData[$options->mapping][$item];
533
                    }
534 1
                    if (!property_exists($data, $item)) {
535 1
                        $this->fail(new ObjectException('Required property missing: ' . $item . ', data: ' . json_encode($data, JSON_UNESCAPED_SLASHES), ObjectException::REQUIRED), $path);
536
                    }
537
                }
538
            } else {
539 2
                foreach ($this->required as $item) {
540 2
                    if (isset($this->__dataToProperty[$options->mapping][$item])) {
541
                        $item = $this->__dataToProperty[$options->mapping][$item];
542
                    }
543 2
                    if (!property_exists($data, $item)) {
544 2
                        $this->fail(new ObjectException('Required property missing: ' . $item . ', data: ' . json_encode($data, JSON_UNESCAPED_SLASHES), ObjectException::REQUIRED), $path);
545
                    }
546
                }
547
            }
548
549
        } else {
550 159
            foreach ($this->required as $item) {
551 155
                if (!property_exists($data, $item)) {
552 155
                    $this->fail(new ObjectException('Required property missing: ' . $item . ', data: ' . json_encode($data, JSON_UNESCAPED_SLASHES), ObjectException::REQUIRED), $path);
553
                }
554
            }
555
        }
556 128
    }
557
558
    /**
559
     * @param \stdClass $data
560
     * @param Context $options
561
     * @param string $path
562
     * @param ObjectItemContract|null $result
563
     * @return array|null|ClassStructure|ObjectItemContract
564
     * @throws InvalidValue
565
     * @throws \Exception
566
     * @throws \Swaggest\JsonDiff\Exception
567
     */
568 3134
    private function processObject($data, Context $options, $path, $result = null)
569
    {
570 3134
        $import = $options->import;
571
572 3134
        if (!$options->skipValidation && $this->required !== null) {
573 160
            $this->processObjectRequired($data, $options, $path);
574
        }
575
576 3133
        if ($import) {
577 3121
            if (!$options->validateOnly) {
578
579 3121
                if ($this->useObjectAsArray) {
580 1
                    $result = array();
581 3120
                } elseif (!$result instanceof ObjectItemContract) {
582
                    //* todo check performance impact
583 3120
                    if (null === $this->objectItemClass) {
584 1150
                        $result = new ObjectItem();
585
                    } else {
586 3109
                        $className = $this->objectItemClass;
587 3109
                        if ($options->objectItemClassMapping !== null) {
588
                            if (isset($options->objectItemClassMapping[$className])) {
589
                                $className = $options->objectItemClassMapping[$className];
590
                            }
591
                        }
592 3109
                        $result = new $className;
593
                    }
594
                    //*/
595
596
597 3120
                    if ($result instanceof ClassStructure) {
598 3108
                        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...
599 3108
                            $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...
600
                            /** @noinspection PhpUnusedLocalVariableInspection */
601
                            /* 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...
602
                            $validateOnSetHandler = new ScopeExit(function () use ($result) {
603
                                $result->__validateOnSet = true;
604
                            });
605
                            //*/
606
                        }
607
                    }
608
609
                    //* todo check performance impact
610 3120
                    if ($result instanceof ObjectItemContract) {
611 3120
                        $result->setDocumentPath($path);
612
                    }
613
                    //*/
614
                }
615
            }
616
        }
617
618
        // @todo better check for schema id
619
620 3133
        if ($import
621 3133
            && isset($data->{Schema::PROP_ID_D4})
622 3133
            && ($options->version === Schema::VERSION_DRAFT_04 || $options->version === Schema::VERSION_AUTO)
623 3133
            && is_string($data->{Schema::PROP_ID_D4})) {
624 30
            $id = $data->{Schema::PROP_ID_D4};
625 30
            $refResolver = $options->refResolver;
626 30
            $parentScope = $refResolver->updateResolutionScope($id);
627
            /** @noinspection PhpUnusedLocalVariableInspection */
628
            $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...
629 30
                $refResolver->setResolutionScope($parentScope);
630 30
            });
631
        }
632
633 3133
        if ($import
634 3133
            && isset($data->{self::PROP_ID})
635 3133
            && ($options->version >= Schema::VERSION_DRAFT_06 || $options->version === Schema::VERSION_AUTO)
636 3133
            && is_string($data->{self::PROP_ID})) {
637 114
            $id = $data->{self::PROP_ID};
638 114
            $refResolver = $options->refResolver;
639 114
            $parentScope = $refResolver->updateResolutionScope($id);
640
            /** @noinspection PhpUnusedLocalVariableInspection */
641
            $defer = new ScopeExit(function () use ($parentScope, $refResolver) {
642 114
                $refResolver->setResolutionScope($parentScope);
643 114
            });
644
        }
645
646 3133
        if ($import) {
647
            try {
648
                while (
649 3121
                    isset($data->{self::PROP_REF})
650 3121
                    && is_string($data->{self::PROP_REF})
651 3121
                    && !isset($this->properties[self::PROP_REF])
652
                ) {
653 409
                    $refString = $data->{self::PROP_REF};
654
655
                    // todo check performance impact
656 409
                    if ($refString === 'http://json-schema.org/draft-04/schema#'
657 399
                        || $refString === 'http://json-schema.org/draft-06/schema#'
658 409
                        || $refString === 'http://json-schema.org/draft-07/schema#') {
659 26
                        return Schema::schema();
660
                    }
661
662
                    // TODO consider process # by reference here ?
663 383
                    $refResolver = $options->refResolver;
664 383
                    $preRefScope = $refResolver->getResolutionScope();
665
                    /** @noinspection PhpUnusedLocalVariableInspection */
666 383
                    $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...
667 383
                        $refResolver->setResolutionScope($preRefScope);
668 383
                    });
669
670 383
                    $ref = $refResolver->resolveReference($refString);
671 383
                    $data = self::unboolSchemaData($ref->getData());
672 383
                    if (!$options->validateOnly) {
673 383
                        if ($ref->isImported()) {
674 173
                            $refResult = $ref->getImported();
675 173
                            return $refResult;
676
                        }
677 383
                        $ref->setImported($result);
678
                        try {
679 383
                            $refResult = $this->process($data, $options, $path . '->$ref:' . $refString, $result);
680 383
                            if ($refResult instanceof ObjectItemContract) {
681 383
                                $refResult->setFromRef($refString);
682
                            }
683 383
                            $ref->setImported($refResult);
684 1
                        } catch (InvalidValue $exception) {
685 1
                            $ref->unsetImported();
686 1
                            throw $exception;
687
                        }
688 383
                        return $refResult;
689
                    } else {
690
                        $this->process($data, $options, $path . '->$ref:' . $refString);
691
                    }
692
                }
693 1
            } catch (InvalidValue $exception) {
694 1
                $this->fail($exception, $path);
695
            }
696
        }
697
698
        /** @var Schema[]|null $properties */
699 3133
        $properties = null;
700
701 3133
        $nestedProperties = null;
702 3133
        if ($this->properties !== null) {
703 3119
            $properties = $this->properties->toArray(); // todo call directly
704 3119
            if ($this->properties instanceof Properties) {
705 3119
                $nestedProperties = $this->properties->nestedProperties;
0 ignored issues
show
Bug Best Practice introduced by
The property nestedProperties does not exist on Swaggest\JsonSchema\Schema. Since you implemented __get, consider adding a @property annotation.
Loading history...
706
            } else {
707 574
                $nestedProperties = array();
708
            }
709
        }
710
711 3133
        $array = array();
712 3133
        if (!empty($this->__dataToProperty[$options->mapping])) { // todo skip on $options->validateOnly
713 3101
            foreach ((array)$data as $key => $value) {
714 3097
                if ($import) {
715 3096
                    if (isset($this->__dataToProperty[$options->mapping][$key])) {
716 3096
                        $key = $this->__dataToProperty[$options->mapping][$key];
717
                    }
718
                } else {
719 20
                    if (isset($this->__propertyToData[$options->mapping][$key])) {
720 1
                        $key = $this->__propertyToData[$options->mapping][$key];
721
                    }
722
                }
723 3101
                $array[$key] = $value;
724
            }
725
        } else {
726 1227
            $array = (array)$data;
727
        }
728
729 3133
        if (!$options->skipValidation) {
730 3112
            if ($this->minProperties !== null && count($array) < $this->minProperties) {
731 4
                $this->fail(new ObjectException("Not enough properties", ObjectException::TOO_FEW), $path);
732
            }
733 3112
            if ($this->maxProperties !== null && count($array) > $this->maxProperties) {
734 3
                $this->fail(new ObjectException("Too many properties", ObjectException::TOO_MANY), $path);
735
            }
736 3112
            if ($this->propertyNames !== null) {
737 17
                $propertyNames = self::unboolSchema($this->propertyNames);
738 17
                foreach ($array as $key => $tmp) {
739 10
                    $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

739
                    $propertyNames->/** @scrutinizer ignore-call */ 
740
                                    process($key, $options, $path . '->propertyNames:' . $key);
Loading history...
740
                }
741
            }
742
        }
743
744 3133
        $defaultApplied = array();
745 3133
        if ($import
746 3133
            && !$options->validateOnly
747 3133
            && $options->applyDefaults
748 3133
            && $properties !== null
749
        ) {
750 33
            foreach ($properties as $key => $property) {
751
                // todo check when property is \stdClass `{}` here (RefTest)
752 31
                if ($property instanceof SchemaContract && null !== $default = $property->getDefault()) {
753 6
                    if (isset($this->__dataToProperty[$options->mapping][$key])) {
754
                        $key = $this->__dataToProperty[$options->mapping][$key];
755
                    }
756 6
                    if (!array_key_exists($key, $array)) {
757 6
                        $defaultApplied[$key] = true;
758 31
                        $array[$key] = $default;
759
                    }
760
                }
761
            }
762
        }
763
764 3133
        foreach ($array as $key => $value) {
765 3123
            if ($key === '' && PHP_VERSION_ID < 71000) {
766 1
                $this->fail(new InvalidValue('Empty property name'), $path);
767
            }
768
769 3122
            $found = false;
770
771 3122
            if (!$options->skipValidation && !empty($this->dependencies)) {
772 73
                $deps = $this->dependencies;
773 73
                if (isset($deps->$key)) {
774 63
                    $dependencies = $deps->$key;
775 63
                    $dependencies = self::unboolSchema($dependencies);
776 63
                    if ($dependencies instanceof SchemaContract) {
777 29
                        $dependencies->process($data, $options, $path . '->dependencies:' . $key);
778
                    } else {
779 34
                        foreach ($dependencies as $item) {
780 31
                            if (!property_exists($data, $item)) {
781 18
                                $this->fail(new ObjectException('Dependency property missing: ' . $item,
782 31
                                    ObjectException::DEPENDENCY_MISSING), $path);
783
                            }
784
                        }
785
                    }
786
                }
787
            }
788
789 3122
            $propertyFound = false;
790 3122
            if (isset($properties[$key])) {
791
                /** @var Schema[] $properties */
792 3112
                $prop = self::unboolSchema($properties[$key]);
793 3112
                $propertyFound = true;
794 3112
                $found = true;
795 3112
                if ($prop instanceof SchemaContract) {
796 3055
                    $value = $prop->process(
797 3055
                        $value,
798 3055
                        isset($defaultApplied[$key]) ? $options->withDefault() : $options,
799 3055
                        $path . '->properties:' . $key
800
                    );
801
                }
802
            }
803
804
            /** @var Egg[] $nestedEggs */
805 3117
            $nestedEggs = null;
806 3117
            if (isset($nestedProperties[$key])) {
807 6
                $found = true;
808 6
                $nestedEggs = $nestedProperties[$key];
809
                // todo iterate all nested props?
810 6
                $value = self::unboolSchema($nestedEggs[0]->propertySchema)->process($value, $options, $path . '->nestedProperties:' . $key);
811
            }
812
813 3117
            if ($this->patternProperties !== null) {
814 166
                foreach ($this->patternProperties as $pattern => $propertySchema) {
815 166
                    if (preg_match(Helper::toPregPattern($pattern), $key)) {
816 120
                        $found = true;
817 120
                        $value = self::unboolSchema($propertySchema)->process($value, $options,
818 120
                            $path . '->patternProperties[' . $pattern . ']:' . $key);
819 93
                        if (!$options->validateOnly && $import) {
820 144
                            $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

820
                            $result->/** @scrutinizer ignore-call */ 
821
                                     addPatternPropertyName($pattern, $key);
Loading history...
821
                        }
822
                        //break; // todo manage multiple import data properly (pattern accessor)
823
                    }
824
                }
825
            }
826 3117
            if (!$found && $this->additionalProperties !== null) {
827 988
                if (!$options->skipValidation && $this->additionalProperties === false) {
828 12
                    $this->fail(new ObjectException('Additional properties not allowed'), $path . ':' . $key);
829
                }
830
831 988
                if ($this->additionalProperties instanceof SchemaContract) {
832 988
                    $value = $this->additionalProperties->process($value, $options, $path . '->additionalProperties:' . $key);
833
                }
834
835 981
                if ($import && !$this->useObjectAsArray && !$options->validateOnly) {
836 980
                    $result->addAdditionalPropertyName($key);
837
                }
838
            }
839
840 3113
            if (!$options->validateOnly && $nestedEggs && $import) {
841 5
                foreach ($nestedEggs as $nestedEgg) {
842 5
                    $result->setNestedProperty($key, $value, $nestedEgg);
843
                }
844 5
                if ($propertyFound) {
845 5
                    $result->$key = $value;
846
                }
847
            } else {
848 3112
                if ($this->useObjectAsArray && $import) {
849 1
                    $result[$key] = $value;
850
                } else {
851 3112
                    if ($found || !$import) {
852 3111
                        $result->$key = $value;
853 1134
                    } elseif (!isset($result->$key)) {
854 3113
                        $result->$key = $value;
855
                    }
856
                }
857
            }
858
        }
859
860 3121
        return $result;
861
    }
862
863
    /**
864
     * @param array $data
865
     * @param Context $options
866
     * @param string $path
867
     * @param array $result
868
     * @return mixed
869
     * @throws InvalidValue
870
     * @throws \Exception
871
     * @throws \Swaggest\JsonDiff\Exception
872
     */
873 1202
    private function processArray($data, Context $options, $path, $result)
874
    {
875 1202
        $count = count($data);
876 1202
        if (!$options->skipValidation) {
877 1002
            if ($this->minItems !== null && $count < $this->minItems) {
878 9
                $this->fail(new ArrayException("Not enough items in array"), $path);
879
            }
880
881 996
            if ($this->maxItems !== null && $count > $this->maxItems) {
882 6
                $this->fail(new ArrayException("Too many items in array"), $path);
883
            }
884
        }
885
886 1190
        $pathItems = 'items';
887 1190
        $this->items = self::unboolSchema($this->items);
888 1190
        if ($this->items instanceof SchemaContract) {
889 844
            $items = array();
890 844
            $additionalItems = $this->items;
891 683
        } elseif ($this->items === null) { // items defaults to empty schema so everything is valid
892 683
            $items = array();
893 683
            $additionalItems = true;
894
        } else { // listed items
895 104
            $items = $this->items;
896 104
            $additionalItems = $this->additionalItems;
897 104
            $pathItems = 'additionalItems';
898
        }
899
900
        /**
901
         * @var Schema|Schema[] $items
902
         * @var null|bool|Schema $additionalItems
903
         */
904 1190
        $itemsLen = is_array($items) ? count($items) : 0;
905 1190
        $index = 0;
906 1190
        foreach ($result as $key => $value) {
907 1065
            if ($index < $itemsLen) {
908 94
                $itemSchema = self::unboolSchema($items[$index]);
909 94
                $result[$key] = $itemSchema->process($value, $options, $path . '->items:' . $index);
910
            } else {
911 1065
                if ($additionalItems instanceof SchemaContract) {
912 818
                    $result[$key] = $additionalItems->process($value, $options, $path . '->' . $pathItems
913 818
                        . '[' . $index . ']:' . $index);
914 567
                } elseif (!$options->skipValidation && $additionalItems === false) {
915 6
                    $this->fail(new ArrayException('Unexpected array item'), $path);
916
                }
917
            }
918 1045
            ++$index;
919
        }
920
921 1166
        if (!$options->skipValidation && $this->uniqueItems) {
922 500
            if (!UniqueItems::isValid($data)) {
923 19
                $this->fail(new ArrayException('Array is not unique'), $path);
924
            }
925
        }
926
927 1147
        if (!$options->skipValidation && $this->contains !== null) {
928
            /** @var Schema|bool $contains */
929 36
            $contains = $this->contains;
930 36
            if ($contains === false) {
931 4
                $this->fail(new ArrayException('Contains is false'), $path);
932
            }
933 32
            if ($count === 0) {
934 7
                $this->fail(new ArrayException('Empty array fails contains constraint'), $path);
935
            }
936 25
            if ($contains === true) {
937 2
                $contains = self::unboolSchema($contains);
938
            }
939 25
            $containsOk = false;
940 25
            foreach ($data as $key => $item) {
941
                try {
942 25
                    $contains->process($item, $options, $path . '->' . $key);
943 17
                    $containsOk = true;
944 17
                    break;
945 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...
946
                }
947
            }
948 25
            if (!$containsOk) {
949 8
                $this->fail(new ArrayException('Array fails contains constraint'), $path);
950
            }
951
        }
952 1128
        return $result;
953
    }
954
955
    /**
956
     * @param mixed|string $data
957
     * @param Context $options
958
     * @param string $path
959
     * @return bool|mixed|string
960
     * @throws InvalidValue
961
     */
962 14
    private function processContent($data, Context $options, $path)
963
    {
964
        try {
965 14
            if ($options->unpackContentMediaType) {
966 7
                return Content::process($options, $this->contentEncoding, $this->contentMediaType, $data, $options->import);
967
            } else {
968 7
                Content::process($options, $this->contentEncoding, $this->contentMediaType, $data, true);
969
            }
970 4
        } catch (InvalidValue $exception) {
971 4
            $this->fail($exception, $path);
972
        }
973 7
        return $data;
974
    }
975
976
    /**
977
     * @param mixed $data
978
     * @param Context $options
979
     * @param string $path
980
     * @param mixed|null $result
981
     * @return array|mixed|null|object|\stdClass
982
     * @throws InvalidValue
983
     * @throws \Exception
984
     * @throws \Swaggest\JsonDiff\Exception
985
     */
986 3180
    public function process($data, Context $options, $path = '#', $result = null)
987
    {
988 3180
        $import = $options->import;
989
990 3180
        if ($ref = $this->getFromRef()) {
991 356
            $path .= '->$ref[' . $ref . ']';
992
        }
993
994 3180
        if (!$import && $data instanceof ObjectItemContract) {
995 780
            $result = new \stdClass();
996
997 780
            if ($ref = $data->getFromRef()) {
998 1
                $result->{self::PROP_REF} = $ref;
999 1
                return $result;
1000
            }
1001
1002 780
            if ($options->circularReferences->contains($data)) {
1003
                /** @noinspection PhpIllegalArrayKeyTypeInspection */
1004 1
                $path = $options->circularReferences[$data];
1005 1
                $result->{self::PROP_REF} = PointerUtil::getDataPointer($path, true);
1006 1
                return $result;
1007
            }
1008 780
            $options->circularReferences->attach($data, $path);
1009
1010 780
            $data = $data->jsonSerialize();
1011
        }
1012 3180
        if (!$import && is_array($data) && $this->useObjectAsArray) {
1013 1
            $data = (object)$data;
1014
        }
1015
1016 3180
        if (null !== $options->dataPreProcessor) {
1017
            $data = $options->dataPreProcessor->process($data, $this, $import);
1018
        }
1019
1020 3180
        if ($result === null) {
1021 3180
            $result = $data;
1022
        }
1023
1024 3180
        if ($options->skipValidation) {
1025 1416
            goto skipValidation;
1026
        }
1027
1028 3142
        if ($this->type !== null) {
1029 3121
            $this->processType($data, $options, $path);
1030
        }
1031
1032 3141
        if ($this->enum !== null) {
1033 1459
            $this->processEnum($data, $path);
1034
        }
1035
1036 3141
        if (array_key_exists(self::CONST_PROPERTY, $this->__arrayOfData)) {
1037 43
            $this->processConst($data, $path);
1038
        }
1039
1040 3141
        if ($this->not !== null) {
1041 69
            $this->processNot($data, $options, $path);
1042
        }
1043
1044 3141
        if (is_string($data)) {
1045 2229
            $this->processString($data, $path);
1046
        }
1047
1048 3141
        if (is_int($data) || is_float($data)) {
1049 1041
            $this->processNumeric($data, $path);
1050
        }
1051
1052 3141
        if ($this->if !== null) {
1053 26
            $result = $this->processIf($data, $options, $path);
1054
        }
1055
1056
        skipValidation:
1057
1058 3179
        if ($this->oneOf !== null) {
1059 101
            $result = $this->processOneOf($data, $options, $path);
1060
        }
1061
1062 3179
        if ($this->anyOf !== null) {
1063 1704
            $result = $this->processAnyOf($data, $options, $path);
1064
        }
1065
1066 3179
        if ($this->allOf !== null) {
1067 352
            $result = $this->processAllOf($data, $options, $path);
1068
        }
1069
1070 3179
        if ($data instanceof \stdClass) {
1071 3134
            $result = $this->processObject($data, $options, $path, $result);
1072
        }
1073
1074 3176
        if (is_array($data)) {
1075 1202
            $result = $this->processArray($data, $options, $path, $result);
1076
        }
1077
1078 3176
        if ($this->contentEncoding !== null || $this->contentMediaType !== null) {
1079 14
            $result = $this->processContent($data, $options, $path);
1080
        }
1081
1082 3176
        return $result;
1083
    }
1084
1085
    /**
1086
     * @param boolean $useObjectAsArray
1087
     * @return Schema
1088
     */
1089 1
    public function setUseObjectAsArray($useObjectAsArray)
1090
    {
1091 1
        $this->useObjectAsArray = $useObjectAsArray;
1092 1
        return $this;
1093
    }
1094
1095
    /**
1096
     * @param InvalidValue $exception
1097
     * @param string $path
1098
     * @throws InvalidValue
1099
     */
1100 1213
    private function fail(InvalidValue $exception, $path)
1101
    {
1102 1213
        if ($path !== '#') {
1103 754
            $exception->addPath($path);
1104
        }
1105 1213
        throw $exception;
1106
    }
1107
1108 13
    public static function integer()
1109
    {
1110 13
        $schema = new static();
1111 13
        $schema->type = Type::INTEGER;
1112 13
        return $schema;
1113
    }
1114
1115 4
    public static function number()
1116
    {
1117 4
        $schema = new static();
1118 4
        $schema->type = Type::NUMBER;
1119 4
        return $schema;
1120
    }
1121
1122 8
    public static function string()
1123
    {
1124 8
        $schema = new static();
1125 8
        $schema->type = Type::STRING;
1126 8
        return $schema;
1127
    }
1128
1129 4
    public static function boolean()
1130
    {
1131 4
        $schema = new static();
1132 4
        $schema->type = Type::BOOLEAN;
1133 4
        return $schema;
1134
    }
1135
1136 6
    public static function object()
1137
    {
1138 6
        $schema = new static();
1139 6
        $schema->type = Type::OBJECT;
1140 6
        return $schema;
1141
    }
1142
1143 1
    public static function arr()
1144
    {
1145 1
        $schema = new static();
1146 1
        $schema->type = Type::ARR;
1147 1
        return $schema;
1148
    }
1149
1150
    public static function null()
1151
    {
1152
        $schema = new static();
1153
        $schema->type = Type::NULL;
1154
        return $schema;
1155
    }
1156
1157
1158
    /**
1159
     * @param Properties $properties
1160
     * @return Schema
1161
     */
1162 3
    public function setProperties($properties)
1163
    {
1164 3
        $this->properties = $properties;
1165 3
        return $this;
1166
    }
1167
1168
    /**
1169
     * @param string $name
1170
     * @param Schema $schema
1171
     * @return $this
1172
     */
1173 3
    public function setProperty($name, $schema)
1174
    {
1175 3
        if (null === $this->properties) {
1176 3
            $this->properties = new Properties();
1177
        }
1178 3
        $this->properties->__set($name, $schema);
1179 3
        return $this;
1180
    }
1181
1182
    /** @var Meta[] */
1183
    private $metaItems = array();
1184
1185 1
    public function addMeta(Meta $meta)
1186
    {
1187 1
        $this->metaItems[get_class($meta)] = $meta;
1188 1
        return $this;
1189
    }
1190
1191 1
    public function getMeta($className)
1192
    {
1193 1
        if (isset($this->metaItems[$className])) {
1194 1
            return $this->metaItems[$className];
1195
        }
1196
        return null;
1197
    }
1198
1199
    /**
1200
     * @param Context $options
1201
     * @return ObjectItemContract
1202
     */
1203 5
    public function makeObjectItem(Context $options = null)
1204
    {
1205 5
        if (null === $this->objectItemClass) {
1206
            return new ObjectItem();
1207
        } else {
1208 5
            $className = $this->objectItemClass;
1209 5
            if ($options !== null) {
1210
                if (isset($options->objectItemClassMapping[$className])) {
1211
                    $className = $options->objectItemClassMapping[$className];
1212
                }
1213
            }
1214 5
            return new $className;
1215
        }
1216
    }
1217
1218
    /**
1219
     * @param mixed $schema
1220
     * @return mixed|Schema
1221
     */
1222 3192
    private static function unboolSchema($schema)
1223
    {
1224 3192
        static $trueSchema;
1225 3192
        static $falseSchema;
1226
1227 3192
        if (null === $trueSchema) {
1228 1
            $trueSchema = new Schema();
1229 1
            $trueSchema->__booleanSchema = true;
1230 1
            $falseSchema = new Schema();
1231 1
            $falseSchema->not = $trueSchema;
1232 1
            $falseSchema->__booleanSchema = false;
1233
        }
1234
1235 3192
        if ($schema === true) {
1236 108
            return $trueSchema;
1237 3164
        } elseif ($schema === false) {
1238 94
            return $falseSchema;
1239
        } else {
1240 3132
            return $schema;
1241
        }
1242
    }
1243
1244
    /**
1245
     * @param mixed $data
1246
     * @return \stdClass
1247
     */
1248 383
    private static function unboolSchemaData($data)
1249
    {
1250 383
        static $trueSchema;
1251 383
        static $falseSchema;
1252
1253 383
        if (null === $trueSchema) {
1254 1
            $trueSchema = new \stdClass();
1255 1
            $falseSchema = new \stdClass();
1256 1
            $falseSchema->not = $trueSchema;
1257
        }
1258
1259 383
        if ($data === true) {
1260 6
            return $trueSchema;
1261 379
        } elseif ($data === false) {
1262 5
            return $falseSchema;
1263
        } else {
1264 374
            return $data;
1265
        }
1266
    }
1267
1268 31
    public function getDefault()
1269
    {
1270 31
        return $this->default;
1271
    }
1272
1273 86
    public function getProperties()
1274
    {
1275 86
        return $this->properties;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->properties also could return the type Swaggest\JsonSchema\Schema which is incompatible with the return type mandated by Swaggest\JsonSchema\Sche...ntract::getProperties() of null|Swaggest\JsonSchema...a\Constraint\Properties.
Loading history...
1276
    }
1277
1278
    public function getObjectItemClass()
1279
    {
1280
        return $this->objectItemClass;
1281
    }
1282
}
1283