ItemsConstraint::keywords()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
/*
4
 * This file is part of the JVal package.
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace JVal\Constraint;
11
12
use JVal\Constraint;
13
use JVal\Context;
14
use JVal\Exception\Constraint\InvalidTypeException;
15
use JVal\Types;
16
use JVal\Walker;
17
use stdClass;
18
19
/**
20
 * Constraint for the "items" and "additionalItems" keywords.
21
 */
22
class ItemsConstraint implements Constraint
23
{
24
    /**
25
     * {@inheritdoc}
26
     */
27 373
    public function keywords()
28
    {
29 373
        return ['items', 'additionalItems'];
30
    }
31
32
    /**
33
     * {@inheritdoc}
34
     */
35 357
    public function supports($type)
36
    {
37 357
        return $type === Types::TYPE_ARRAY;
38
    }
39
40
    /**
41
     * {@inheritdoc}
42
     */
43 57
    public function normalize(stdClass $schema, Context $context, Walker $walker)
44
    {
45 57
        $this->createDefaults($schema);
46
47 57
        $context->enterNode('items');
48 57
        $this->parseItemsProperty($schema, $context, $walker);
49
50 55
        $context->enterSibling('additionalItems');
51 55
        $this->parseAdditionalItemsProperty($schema, $context, $walker);
52 54
        $context->leaveNode();
53 54
    }
54
55
    /**
56
     * {@inheritdoc}
57
     */
58 40
    public function apply($instance, stdClass $schema, Context $context, Walker $walker)
59
    {
60 40
        if (is_object($schema->items)) {
61
            // 8.2.3.1. If items is a schema, then the child instance must be
62
            // valid against this schema, regardless of its index, and
63
            // regardless of the value of "additionalItems".
64 21
            foreach ($instance as $index => $item) {
65 17
                $context->enterNode($index);
66 17
                $walker->applyConstraints($item, $schema->items, $context);
67 17
                $context->leaveNode();
68 21
            }
69 21
        } else { // "items" is an array
70 21
            $itemSize = count($schema->items);
71
72 21
            foreach ($instance as $index => $item) {
73 20
                $context->enterNode($index);
74
75
                // 8.2.3.2.  If the index is less than, or equal to, the size of
76
                // "items", the child instance must be valid against the
77
                // corresponding schema in the "items" array; otherwise, it must
78
                // be valid against the schema defined by "additionalItems".
79
                //
80
                // NOTE: this is adapted for 0-based indexation.
81 20
                if ($index < $itemSize) {
82 20
                    $walker->applyConstraints($item, $schema->items[$index], $context);
83 20
                } elseif ($schema->additionalItems === false) {
84 6
                    $context->addViolation('additional items are not allowed');
85 6
                } else {
86 5
                    $walker->applyConstraints($item, $schema->additionalItems, $context);
87
                }
88
89 20
                $context->leaveNode();
90 21
            }
91
        }
92 40
    }
93
94 57
    private function createDefaults(stdClass $schema)
95
    {
96 57
        if (!property_exists($schema, 'items')) {
97 11
            $schema->items = new stdClass();
98 11
        }
99
100 57
        if (!property_exists($schema, 'additionalItems') || $schema->additionalItems === true) {
101 23
            $schema->additionalItems = new stdClass();
102 23
        }
103 57
    }
104
105 57
    private function parseItemsProperty(stdClass $schema, Context $context, Walker $walker)
106
    {
107 57
        if (is_object($schema->items)) {
108 35
            $walker->parseSchema($schema->items, $context);
109 57
        } elseif (is_array($schema->items)) {
110 25 View Code Duplication
            foreach ($schema->items as $index => $item) {
111 25
                $context->enterNode($index);
112
113 25
                if (!is_object($item)) {
114 1
                    throw new InvalidTypeException($context, Types::TYPE_OBJECT);
115
                }
116
117 25
                $walker->parseSchema($item, $context);
118 25
                $context->leaveNode();
119 25
            }
120 24
        } else {
121 1
            throw new InvalidTypeException($context, [Types::TYPE_OBJECT, Types::TYPE_ARRAY]);
122
        }
123 55
    }
124
125 55 View Code Duplication
    private function parseAdditionalItemsProperty(stdClass $schema, Context $context, Walker $walker)
126
    {
127 55
        if (is_object($schema->additionalItems)) {
128 35
            $walker->parseSchema($schema->additionalItems, $context);
129 55
        } elseif (!is_bool($schema->additionalItems)) {
130 1
            throw new InvalidTypeException($context, [Types::TYPE_OBJECT, Types::TYPE_BOOLEAN]);
131
        }
132 54
    }
133
}
134