]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ObjectConstraint.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / vendor / justinrainbow / json-schema / src / JsonSchema / Constraints / ObjectConstraint.php
1 <?php
2
3 /*
4  * This file is part of the JsonSchema 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 JsonSchema\Constraints;
11
12 use JsonSchema\Entity\JsonPointer;
13
14 /**
15  * The ObjectConstraint Constraints, validates an object against a given schema
16  *
17  * @author Robert Schönthal <seroscho@googlemail.com>
18  * @author Bruno Prieto Reis <bruno.p.reis@gmail.com>
19  */
20 class ObjectConstraint extends Constraint
21 {
22     /**
23      * @var array List of properties to which a default value has been applied
24      */
25     protected $appliedDefaults = array();
26
27     /**
28      * {@inheritdoc}
29      */
30     public function check(&$element, $schema = null, JsonPointer $path = null, $properties = null,
31         $additionalProp = null, $patternProperties = null, $appliedDefaults = array())
32     {
33         if ($element instanceof UndefinedConstraint) {
34             return;
35         }
36
37         $this->appliedDefaults = $appliedDefaults;
38
39         $matches = array();
40         if ($patternProperties) {
41             // validate the element pattern properties
42             $matches = $this->validatePatternProperties($element, $path, $patternProperties);
43         }
44
45         if ($properties) {
46             // validate the element properties
47             $this->validateProperties($element, $properties, $path);
48         }
49
50         // validate additional element properties & constraints
51         $this->validateElement($element, $matches, $schema, $path, $properties, $additionalProp);
52     }
53
54     public function validatePatternProperties($element, JsonPointer $path = null, $patternProperties)
55     {
56         $try = array('/', '#', '+', '~', '%');
57         $matches = array();
58         foreach ($patternProperties as $pregex => $schema) {
59             $delimiter = '/';
60             // Choose delimiter. Necessary for patterns like ^/ , otherwise you get error
61             foreach ($try as $delimiter) {
62                 if (strpos($pregex, $delimiter) === false) { // safe to use
63                     break;
64                 }
65             }
66
67             // Validate the pattern before using it to test for matches
68             if (@preg_match($delimiter . $pregex . $delimiter . 'u', '') === false) {
69                 $this->addError($path, 'The pattern "' . $pregex . '" is invalid', 'pregex', array('pregex' => $pregex));
70                 continue;
71             }
72             foreach ($element as $i => $value) {
73                 if (preg_match($delimiter . $pregex . $delimiter . 'u', $i)) {
74                     $matches[] = $i;
75                     $this->checkUndefined($value, $schema ?: new \stdClass(), $path, $i, in_array($i, $this->appliedDefaults));
76                 }
77             }
78         }
79
80         return $matches;
81     }
82
83     /**
84      * Validates the element properties
85      *
86      * @param \StdClass        $element        Element to validate
87      * @param array            $matches        Matches from patternProperties (if any)
88      * @param \StdClass        $schema         ObjectConstraint definition
89      * @param JsonPointer|null $path           Current test path
90      * @param \StdClass        $properties     Properties
91      * @param mixed            $additionalProp Additional properties
92      */
93     public function validateElement($element, $matches, $schema = null, JsonPointer $path = null,
94         $properties = null, $additionalProp = null)
95     {
96         $this->validateMinMaxConstraint($element, $schema, $path);
97
98         foreach ($element as $i => $value) {
99             $definition = $this->getProperty($properties, $i);
100
101             // no additional properties allowed
102             if (!in_array($i, $matches) && $additionalProp === false && $this->inlineSchemaProperty !== $i && !$definition) {
103                 $this->addError($path, 'The property ' . $i . ' is not defined and the definition does not allow additional properties', 'additionalProp');
104             }
105
106             // additional properties defined
107             if (!in_array($i, $matches) && $additionalProp && !$definition) {
108                 if ($additionalProp === true) {
109                     $this->checkUndefined($value, null, $path, $i, in_array($i, $this->appliedDefaults));
110                 } else {
111                     $this->checkUndefined($value, $additionalProp, $path, $i, in_array($i, $this->appliedDefaults));
112                 }
113             }
114
115             // property requires presence of another
116             $require = $this->getProperty($definition, 'requires');
117             if ($require && !$this->getProperty($element, $require)) {
118                 $this->addError($path, 'The presence of the property ' . $i . ' requires that ' . $require . ' also be present', 'requires');
119             }
120
121             $property = $this->getProperty($element, $i, $this->factory->createInstanceFor('undefined'));
122             if (is_object($property)) {
123                 $this->validateMinMaxConstraint(!($property instanceof UndefinedConstraint) ? $property : $element, $definition, $path);
124             }
125         }
126     }
127
128     /**
129      * Validates the definition properties
130      *
131      * @param \stdClass        $element    Element to validate
132      * @param \stdClass        $properties Property definitions
133      * @param JsonPointer|null $path       Path?
134      */
135     public function validateProperties(&$element, $properties = null, JsonPointer $path = null)
136     {
137         $undefinedConstraint = $this->factory->createInstanceFor('undefined');
138
139         foreach ($properties as $i => $value) {
140             $property = &$this->getProperty($element, $i, $undefinedConstraint);
141             $definition = $this->getProperty($properties, $i);
142
143             if (is_object($definition)) {
144                 // Undefined constraint will check for is_object() and quit if is not - so why pass it?
145                 $this->checkUndefined($property, $definition, $path, $i, in_array($i, $this->appliedDefaults));
146             }
147         }
148     }
149
150     /**
151      * retrieves a property from an object or array
152      *
153      * @param mixed  $element  Element to validate
154      * @param string $property Property to retrieve
155      * @param mixed  $fallback Default value if property is not found
156      *
157      * @return mixed
158      */
159     protected function &getProperty(&$element, $property, $fallback = null)
160     {
161         if (is_array($element) && (isset($element[$property]) || array_key_exists($property, $element)) /*$this->checkMode == self::CHECK_MODE_TYPE_CAST*/) {
162             return $element[$property];
163         } elseif (is_object($element) && property_exists($element, $property)) {
164             return $element->$property;
165         }
166
167         return $fallback;
168     }
169
170     /**
171      * validating minimum and maximum property constraints (if present) against an element
172      *
173      * @param \stdClass        $element          Element to validate
174      * @param \stdClass        $objectDefinition ObjectConstraint definition
175      * @param JsonPointer|null $path             Path to test?
176      */
177     protected function validateMinMaxConstraint($element, $objectDefinition, JsonPointer $path = null)
178     {
179         // Verify minimum number of properties
180         if (isset($objectDefinition->minProperties) && !is_object($objectDefinition->minProperties)) {
181             if ($this->getTypeCheck()->propertyCount($element) < $objectDefinition->minProperties) {
182                 $this->addError($path, 'Must contain a minimum of ' . $objectDefinition->minProperties . ' properties', 'minProperties', array('minProperties' => $objectDefinition->minProperties));
183             }
184         }
185         // Verify maximum number of properties
186         if (isset($objectDefinition->maxProperties) && !is_object($objectDefinition->maxProperties)) {
187             if ($this->getTypeCheck()->propertyCount($element) > $objectDefinition->maxProperties) {
188                 $this->addError($path, 'Must contain no more than ' . $objectDefinition->maxProperties . ' properties', 'maxProperties', array('maxProperties' => $objectDefinition->maxProperties));
189             }
190         }
191     }
192 }