ex
Fork of mbed-os-example-mbed5-blinky by
dumi_doc-master/schema/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ObjectConstraint.php@44:c1d8923072ba, 2017-07-18 (annotated)
- Committer:
- TMBOY
- Date:
- Tue Jul 18 16:27:22 2017 +0800
- Revision:
- 44:c1d8923072ba
?
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| TMBOY | 44:c1d8923072ba | 1 | <?php |
| TMBOY | 44:c1d8923072ba | 2 | |
| TMBOY | 44:c1d8923072ba | 3 | /* |
| TMBOY | 44:c1d8923072ba | 4 | * This file is part of the JsonSchema package. |
| TMBOY | 44:c1d8923072ba | 5 | * |
| TMBOY | 44:c1d8923072ba | 6 | * For the full copyright and license information, please view the LICENSE |
| TMBOY | 44:c1d8923072ba | 7 | * file that was distributed with this source code. |
| TMBOY | 44:c1d8923072ba | 8 | */ |
| TMBOY | 44:c1d8923072ba | 9 | |
| TMBOY | 44:c1d8923072ba | 10 | namespace JsonSchema\Constraints; |
| TMBOY | 44:c1d8923072ba | 11 | |
| TMBOY | 44:c1d8923072ba | 12 | use JsonSchema\Entity\JsonPointer; |
| TMBOY | 44:c1d8923072ba | 13 | |
| TMBOY | 44:c1d8923072ba | 14 | /** |
| TMBOY | 44:c1d8923072ba | 15 | * The ObjectConstraint Constraints, validates an object against a given schema |
| TMBOY | 44:c1d8923072ba | 16 | * |
| TMBOY | 44:c1d8923072ba | 17 | * @author Robert Schönthal <seroscho@googlemail.com> |
| TMBOY | 44:c1d8923072ba | 18 | * @author Bruno Prieto Reis <bruno.p.reis@gmail.com> |
| TMBOY | 44:c1d8923072ba | 19 | */ |
| TMBOY | 44:c1d8923072ba | 20 | class ObjectConstraint extends Constraint |
| TMBOY | 44:c1d8923072ba | 21 | { |
| TMBOY | 44:c1d8923072ba | 22 | /** |
| TMBOY | 44:c1d8923072ba | 23 | * {@inheritDoc} |
| TMBOY | 44:c1d8923072ba | 24 | */ |
| TMBOY | 44:c1d8923072ba | 25 | public function check($element, $definition = null, JsonPointer $path = null, $additionalProp = null, $patternProperties = null) |
| TMBOY | 44:c1d8923072ba | 26 | { |
| TMBOY | 44:c1d8923072ba | 27 | if ($element instanceof UndefinedConstraint) { |
| TMBOY | 44:c1d8923072ba | 28 | return; |
| TMBOY | 44:c1d8923072ba | 29 | } |
| TMBOY | 44:c1d8923072ba | 30 | |
| TMBOY | 44:c1d8923072ba | 31 | $matches = array(); |
| TMBOY | 44:c1d8923072ba | 32 | if ($patternProperties) { |
| TMBOY | 44:c1d8923072ba | 33 | $matches = $this->validatePatternProperties($element, $path, $patternProperties); |
| TMBOY | 44:c1d8923072ba | 34 | } |
| TMBOY | 44:c1d8923072ba | 35 | |
| TMBOY | 44:c1d8923072ba | 36 | if ($definition) { |
| TMBOY | 44:c1d8923072ba | 37 | // validate the definition properties |
| TMBOY | 44:c1d8923072ba | 38 | $this->validateDefinition($element, $definition, $path); |
| TMBOY | 44:c1d8923072ba | 39 | } |
| TMBOY | 44:c1d8923072ba | 40 | |
| TMBOY | 44:c1d8923072ba | 41 | // additional the element properties |
| TMBOY | 44:c1d8923072ba | 42 | $this->validateElement($element, $matches, $definition, $path, $additionalProp); |
| TMBOY | 44:c1d8923072ba | 43 | } |
| TMBOY | 44:c1d8923072ba | 44 | |
| TMBOY | 44:c1d8923072ba | 45 | public function validatePatternProperties($element, JsonPointer $path = null, $patternProperties) |
| TMBOY | 44:c1d8923072ba | 46 | { |
| TMBOY | 44:c1d8923072ba | 47 | $try = array('/','#','+','~','%'); |
| TMBOY | 44:c1d8923072ba | 48 | $matches = array(); |
| TMBOY | 44:c1d8923072ba | 49 | foreach ($patternProperties as $pregex => $schema) { |
| TMBOY | 44:c1d8923072ba | 50 | $delimiter = '/'; |
| TMBOY | 44:c1d8923072ba | 51 | // Choose delimiter. Necessary for patterns like ^/ , otherwise you get error |
| TMBOY | 44:c1d8923072ba | 52 | foreach ($try as $delimiter) { |
| TMBOY | 44:c1d8923072ba | 53 | if (strpos($pregex, $delimiter) === false) { // safe to use |
| TMBOY | 44:c1d8923072ba | 54 | break; |
| TMBOY | 44:c1d8923072ba | 55 | } |
| TMBOY | 44:c1d8923072ba | 56 | } |
| TMBOY | 44:c1d8923072ba | 57 | |
| TMBOY | 44:c1d8923072ba | 58 | // Validate the pattern before using it to test for matches |
| TMBOY | 44:c1d8923072ba | 59 | if (@preg_match($delimiter. $pregex . $delimiter, '') === false) { |
| TMBOY | 44:c1d8923072ba | 60 | $this->addError($path, 'The pattern "' . $pregex . '" is invalid', 'pregex', array('pregex' => $pregex,)); |
| TMBOY | 44:c1d8923072ba | 61 | continue; |
| TMBOY | 44:c1d8923072ba | 62 | } |
| TMBOY | 44:c1d8923072ba | 63 | foreach ($element as $i => $value) { |
| TMBOY | 44:c1d8923072ba | 64 | if (preg_match($delimiter . $pregex . $delimiter, $i)) { |
| TMBOY | 44:c1d8923072ba | 65 | $matches[] = $i; |
| TMBOY | 44:c1d8923072ba | 66 | $this->checkUndefined($value, $schema ? : new \stdClass(), $path, $i); |
| TMBOY | 44:c1d8923072ba | 67 | } |
| TMBOY | 44:c1d8923072ba | 68 | } |
| TMBOY | 44:c1d8923072ba | 69 | } |
| TMBOY | 44:c1d8923072ba | 70 | return $matches; |
| TMBOY | 44:c1d8923072ba | 71 | } |
| TMBOY | 44:c1d8923072ba | 72 | |
| TMBOY | 44:c1d8923072ba | 73 | /** |
| TMBOY | 44:c1d8923072ba | 74 | * Validates the element properties |
| TMBOY | 44:c1d8923072ba | 75 | * |
| TMBOY | 44:c1d8923072ba | 76 | * @param \stdClass $element Element to validate |
| TMBOY | 44:c1d8923072ba | 77 | * @param array $matches Matches from patternProperties (if any) |
| TMBOY | 44:c1d8923072ba | 78 | * @param \stdClass $objectDefinition ObjectConstraint definition |
| TMBOY | 44:c1d8923072ba | 79 | * @param JsonPointer|null $path Path to test? |
| TMBOY | 44:c1d8923072ba | 80 | * @param mixed $additionalProp Additional properties |
| TMBOY | 44:c1d8923072ba | 81 | */ |
| TMBOY | 44:c1d8923072ba | 82 | public function validateElement($element, $matches, $objectDefinition = null, JsonPointer $path = null, $additionalProp = null) |
| TMBOY | 44:c1d8923072ba | 83 | { |
| TMBOY | 44:c1d8923072ba | 84 | $this->validateMinMaxConstraint($element, $objectDefinition, $path); |
| TMBOY | 44:c1d8923072ba | 85 | |
| TMBOY | 44:c1d8923072ba | 86 | foreach ($element as $i => $value) { |
| TMBOY | 44:c1d8923072ba | 87 | $definition = $this->getProperty($objectDefinition, $i); |
| TMBOY | 44:c1d8923072ba | 88 | |
| TMBOY | 44:c1d8923072ba | 89 | // no additional properties allowed |
| TMBOY | 44:c1d8923072ba | 90 | if (!in_array($i, $matches) && $additionalProp === false && $this->inlineSchemaProperty !== $i && !$definition) { |
| TMBOY | 44:c1d8923072ba | 91 | $this->addError($path, "The property " . $i . " is not defined and the definition does not allow additional properties", 'additionalProp'); |
| TMBOY | 44:c1d8923072ba | 92 | } |
| TMBOY | 44:c1d8923072ba | 93 | |
| TMBOY | 44:c1d8923072ba | 94 | // additional properties defined |
| TMBOY | 44:c1d8923072ba | 95 | if (!in_array($i, $matches) && $additionalProp && !$definition) { |
| TMBOY | 44:c1d8923072ba | 96 | if ($additionalProp === true) { |
| TMBOY | 44:c1d8923072ba | 97 | $this->checkUndefined($value, null, $path, $i); |
| TMBOY | 44:c1d8923072ba | 98 | } else { |
| TMBOY | 44:c1d8923072ba | 99 | $this->checkUndefined($value, $additionalProp, $path, $i); |
| TMBOY | 44:c1d8923072ba | 100 | } |
| TMBOY | 44:c1d8923072ba | 101 | } |
| TMBOY | 44:c1d8923072ba | 102 | |
| TMBOY | 44:c1d8923072ba | 103 | // property requires presence of another |
| TMBOY | 44:c1d8923072ba | 104 | $require = $this->getProperty($definition, 'requires'); |
| TMBOY | 44:c1d8923072ba | 105 | if ($require && !$this->getProperty($element, $require)) { |
| TMBOY | 44:c1d8923072ba | 106 | $this->addError($path, "The presence of the property " . $i . " requires that " . $require . " also be present", 'requires'); |
| TMBOY | 44:c1d8923072ba | 107 | } |
| TMBOY | 44:c1d8923072ba | 108 | |
| TMBOY | 44:c1d8923072ba | 109 | $property = $this->getProperty($element, $i, $this->factory->createInstanceFor('undefined')); |
| TMBOY | 44:c1d8923072ba | 110 | if (is_object($property)) { |
| TMBOY | 44:c1d8923072ba | 111 | $this->validateMinMaxConstraint(!($property instanceof UndefinedConstraint) ? $property : $element, $definition, $path); |
| TMBOY | 44:c1d8923072ba | 112 | } |
| TMBOY | 44:c1d8923072ba | 113 | } |
| TMBOY | 44:c1d8923072ba | 114 | } |
| TMBOY | 44:c1d8923072ba | 115 | |
| TMBOY | 44:c1d8923072ba | 116 | /** |
| TMBOY | 44:c1d8923072ba | 117 | * Validates the definition properties |
| TMBOY | 44:c1d8923072ba | 118 | * |
| TMBOY | 44:c1d8923072ba | 119 | * @param \stdClass $element Element to validate |
| TMBOY | 44:c1d8923072ba | 120 | * @param \stdClass $objectDefinition ObjectConstraint definition |
| TMBOY | 44:c1d8923072ba | 121 | * @param JsonPointer|null $path Path? |
| TMBOY | 44:c1d8923072ba | 122 | */ |
| TMBOY | 44:c1d8923072ba | 123 | public function validateDefinition($element, $objectDefinition = null, JsonPointer $path = null) |
| TMBOY | 44:c1d8923072ba | 124 | { |
| TMBOY | 44:c1d8923072ba | 125 | $undefinedConstraint = $this->factory->createInstanceFor('undefined'); |
| TMBOY | 44:c1d8923072ba | 126 | |
| TMBOY | 44:c1d8923072ba | 127 | foreach ($objectDefinition as $i => $value) { |
| TMBOY | 44:c1d8923072ba | 128 | $property = $this->getProperty($element, $i, $undefinedConstraint); |
| TMBOY | 44:c1d8923072ba | 129 | $definition = $this->getProperty($objectDefinition, $i); |
| TMBOY | 44:c1d8923072ba | 130 | |
| TMBOY | 44:c1d8923072ba | 131 | if($this->factory->getCheckMode() & Constraint::CHECK_MODE_TYPE_CAST){ |
| TMBOY | 44:c1d8923072ba | 132 | if(!($property instanceof Constraint)) { |
| TMBOY | 44:c1d8923072ba | 133 | $property = $this->coerce($property, $definition); |
| TMBOY | 44:c1d8923072ba | 134 | |
| TMBOY | 44:c1d8923072ba | 135 | if($this->factory->getCheckMode() & Constraint::CHECK_MODE_COERCE) { |
| TMBOY | 44:c1d8923072ba | 136 | if (is_object($element)) { |
| TMBOY | 44:c1d8923072ba | 137 | $element->{$i} = $property; |
| TMBOY | 44:c1d8923072ba | 138 | } else { |
| TMBOY | 44:c1d8923072ba | 139 | $element[$i] = $property; |
| TMBOY | 44:c1d8923072ba | 140 | } |
| TMBOY | 44:c1d8923072ba | 141 | } |
| TMBOY | 44:c1d8923072ba | 142 | } |
| TMBOY | 44:c1d8923072ba | 143 | } |
| TMBOY | 44:c1d8923072ba | 144 | |
| TMBOY | 44:c1d8923072ba | 145 | if (is_object($definition)) { |
| TMBOY | 44:c1d8923072ba | 146 | // Undefined constraint will check for is_object() and quit if is not - so why pass it? |
| TMBOY | 44:c1d8923072ba | 147 | $this->checkUndefined($property, $definition, $path, $i); |
| TMBOY | 44:c1d8923072ba | 148 | } |
| TMBOY | 44:c1d8923072ba | 149 | } |
| TMBOY | 44:c1d8923072ba | 150 | } |
| TMBOY | 44:c1d8923072ba | 151 | |
| TMBOY | 44:c1d8923072ba | 152 | /** |
| TMBOY | 44:c1d8923072ba | 153 | * Converts a value to boolean. For example, "true" becomes true. |
| TMBOY | 44:c1d8923072ba | 154 | * @param $value The value to convert to boolean |
| TMBOY | 44:c1d8923072ba | 155 | * @return bool|mixed |
| TMBOY | 44:c1d8923072ba | 156 | */ |
| TMBOY | 44:c1d8923072ba | 157 | protected function toBoolean($value) |
| TMBOY | 44:c1d8923072ba | 158 | { |
| TMBOY | 44:c1d8923072ba | 159 | if($value === "true"){ |
| TMBOY | 44:c1d8923072ba | 160 | return true; |
| TMBOY | 44:c1d8923072ba | 161 | } |
| TMBOY | 44:c1d8923072ba | 162 | |
| TMBOY | 44:c1d8923072ba | 163 | if($value === "false"){ |
| TMBOY | 44:c1d8923072ba | 164 | return false; |
| TMBOY | 44:c1d8923072ba | 165 | } |
| TMBOY | 44:c1d8923072ba | 166 | |
| TMBOY | 44:c1d8923072ba | 167 | return $value; |
| TMBOY | 44:c1d8923072ba | 168 | } |
| TMBOY | 44:c1d8923072ba | 169 | |
| TMBOY | 44:c1d8923072ba | 170 | /** |
| TMBOY | 44:c1d8923072ba | 171 | * Converts a numeric string to a number. For example, "4" becomes 4. |
| TMBOY | 44:c1d8923072ba | 172 | * |
| TMBOY | 44:c1d8923072ba | 173 | * @param mixed $value The value to convert to a number. |
| TMBOY | 44:c1d8923072ba | 174 | * @return int|float|mixed |
| TMBOY | 44:c1d8923072ba | 175 | */ |
| TMBOY | 44:c1d8923072ba | 176 | protected function toNumber($value) |
| TMBOY | 44:c1d8923072ba | 177 | { |
| TMBOY | 44:c1d8923072ba | 178 | if(is_numeric($value)) { |
| TMBOY | 44:c1d8923072ba | 179 | return $value + 0; // cast to number |
| TMBOY | 44:c1d8923072ba | 180 | } |
| TMBOY | 44:c1d8923072ba | 181 | |
| TMBOY | 44:c1d8923072ba | 182 | return $value; |
| TMBOY | 44:c1d8923072ba | 183 | } |
| TMBOY | 44:c1d8923072ba | 184 | |
| TMBOY | 44:c1d8923072ba | 185 | protected function toInteger($value) |
| TMBOY | 44:c1d8923072ba | 186 | { |
| TMBOY | 44:c1d8923072ba | 187 | if(is_numeric($value) && (int)$value == $value) { |
| TMBOY | 44:c1d8923072ba | 188 | return (int)$value; // cast to number |
| TMBOY | 44:c1d8923072ba | 189 | } |
| TMBOY | 44:c1d8923072ba | 190 | |
| TMBOY | 44:c1d8923072ba | 191 | return $value; |
| TMBOY | 44:c1d8923072ba | 192 | } |
| TMBOY | 44:c1d8923072ba | 193 | |
| TMBOY | 44:c1d8923072ba | 194 | /** |
| TMBOY | 44:c1d8923072ba | 195 | * Given a value and a definition, attempts to coerce the value into the |
| TMBOY | 44:c1d8923072ba | 196 | * type specified by the definition's 'type' property. |
| TMBOY | 44:c1d8923072ba | 197 | * |
| TMBOY | 44:c1d8923072ba | 198 | * @param mixed $value Value to coerce. |
| TMBOY | 44:c1d8923072ba | 199 | * @param \stdClass $definition A definition with information about the expected type. |
| TMBOY | 44:c1d8923072ba | 200 | * @return bool|int|string |
| TMBOY | 44:c1d8923072ba | 201 | */ |
| TMBOY | 44:c1d8923072ba | 202 | protected function coerce($value, $definition) |
| TMBOY | 44:c1d8923072ba | 203 | { |
| TMBOY | 44:c1d8923072ba | 204 | $types = isset($definition->type)?$definition->type:null; |
| TMBOY | 44:c1d8923072ba | 205 | if($types){ |
| TMBOY | 44:c1d8923072ba | 206 | foreach((array)$types as $type) { |
| TMBOY | 44:c1d8923072ba | 207 | switch ($type) { |
| TMBOY | 44:c1d8923072ba | 208 | case "boolean": |
| TMBOY | 44:c1d8923072ba | 209 | $value = $this->toBoolean($value); |
| TMBOY | 44:c1d8923072ba | 210 | break; |
| TMBOY | 44:c1d8923072ba | 211 | case "integer": |
| TMBOY | 44:c1d8923072ba | 212 | $value = $this->toInteger($value); |
| TMBOY | 44:c1d8923072ba | 213 | break; |
| TMBOY | 44:c1d8923072ba | 214 | case "number": |
| TMBOY | 44:c1d8923072ba | 215 | $value = $this->toNumber($value); |
| TMBOY | 44:c1d8923072ba | 216 | break; |
| TMBOY | 44:c1d8923072ba | 217 | } |
| TMBOY | 44:c1d8923072ba | 218 | } |
| TMBOY | 44:c1d8923072ba | 219 | } |
| TMBOY | 44:c1d8923072ba | 220 | return $value; |
| TMBOY | 44:c1d8923072ba | 221 | } |
| TMBOY | 44:c1d8923072ba | 222 | |
| TMBOY | 44:c1d8923072ba | 223 | /** |
| TMBOY | 44:c1d8923072ba | 224 | * retrieves a property from an object or array |
| TMBOY | 44:c1d8923072ba | 225 | * |
| TMBOY | 44:c1d8923072ba | 226 | * @param mixed $element Element to validate |
| TMBOY | 44:c1d8923072ba | 227 | * @param string $property Property to retrieve |
| TMBOY | 44:c1d8923072ba | 228 | * @param mixed $fallback Default value if property is not found |
| TMBOY | 44:c1d8923072ba | 229 | * |
| TMBOY | 44:c1d8923072ba | 230 | * @return mixed |
| TMBOY | 44:c1d8923072ba | 231 | */ |
| TMBOY | 44:c1d8923072ba | 232 | protected function getProperty($element, $property, $fallback = null) |
| TMBOY | 44:c1d8923072ba | 233 | { |
| TMBOY | 44:c1d8923072ba | 234 | if (is_array($element) && (isset($element[$property]) || array_key_exists($property, $element)) /*$this->checkMode == self::CHECK_MODE_TYPE_CAST*/) { |
| TMBOY | 44:c1d8923072ba | 235 | return $element[$property]; |
| TMBOY | 44:c1d8923072ba | 236 | } elseif (is_object($element) && property_exists($element, $property)) { |
| TMBOY | 44:c1d8923072ba | 237 | return $element->$property; |
| TMBOY | 44:c1d8923072ba | 238 | } |
| TMBOY | 44:c1d8923072ba | 239 | |
| TMBOY | 44:c1d8923072ba | 240 | return $fallback; |
| TMBOY | 44:c1d8923072ba | 241 | } |
| TMBOY | 44:c1d8923072ba | 242 | |
| TMBOY | 44:c1d8923072ba | 243 | /** |
| TMBOY | 44:c1d8923072ba | 244 | * validating minimum and maximum property constraints (if present) against an element |
| TMBOY | 44:c1d8923072ba | 245 | * |
| TMBOY | 44:c1d8923072ba | 246 | * @param \stdClass $element Element to validate |
| TMBOY | 44:c1d8923072ba | 247 | * @param \stdClass $objectDefinition ObjectConstraint definition |
| TMBOY | 44:c1d8923072ba | 248 | * @param JsonPointer|null $path Path to test? |
| TMBOY | 44:c1d8923072ba | 249 | */ |
| TMBOY | 44:c1d8923072ba | 250 | protected function validateMinMaxConstraint($element, $objectDefinition, JsonPointer $path = null) { |
| TMBOY | 44:c1d8923072ba | 251 | // Verify minimum number of properties |
| TMBOY | 44:c1d8923072ba | 252 | if (isset($objectDefinition->minProperties) && !is_object($objectDefinition->minProperties)) { |
| TMBOY | 44:c1d8923072ba | 253 | if ($this->getTypeCheck()->propertyCount($element) < $objectDefinition->minProperties) { |
| TMBOY | 44:c1d8923072ba | 254 | $this->addError($path, "Must contain a minimum of " . $objectDefinition->minProperties . " properties", 'minProperties', array('minProperties' => $objectDefinition->minProperties,)); |
| TMBOY | 44:c1d8923072ba | 255 | } |
| TMBOY | 44:c1d8923072ba | 256 | } |
| TMBOY | 44:c1d8923072ba | 257 | // Verify maximum number of properties |
| TMBOY | 44:c1d8923072ba | 258 | if (isset($objectDefinition->maxProperties) && !is_object($objectDefinition->maxProperties)) { |
| TMBOY | 44:c1d8923072ba | 259 | if ($this->getTypeCheck()->propertyCount($element) > $objectDefinition->maxProperties) { |
| TMBOY | 44:c1d8923072ba | 260 | $this->addError($path, "Must contain no more than " . $objectDefinition->maxProperties . " properties", 'maxProperties', array('maxProperties' => $objectDefinition->maxProperties,)); |
| TMBOY | 44:c1d8923072ba | 261 | } |
| TMBOY | 44:c1d8923072ba | 262 | } |
| TMBOY | 44:c1d8923072ba | 263 | } |
| TMBOY | 44:c1d8923072ba | 264 | } |
