]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blobdiff - 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
diff --git a/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ObjectConstraint.php b/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ObjectConstraint.php
new file mode 100644 (file)
index 0000000..0010d29
--- /dev/null
@@ -0,0 +1,192 @@
+<?php
+
+/*
+ * This file is part of the JsonSchema package.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace JsonSchema\Constraints;
+
+use JsonSchema\Entity\JsonPointer;
+
+/**
+ * The ObjectConstraint Constraints, validates an object against a given schema
+ *
+ * @author Robert Schönthal <seroscho@googlemail.com>
+ * @author Bruno Prieto Reis <bruno.p.reis@gmail.com>
+ */
+class ObjectConstraint extends Constraint
+{
+    /**
+     * @var array List of properties to which a default value has been applied
+     */
+    protected $appliedDefaults = array();
+
+    /**
+     * {@inheritdoc}
+     */
+    public function check(&$element, $schema = null, JsonPointer $path = null, $properties = null,
+        $additionalProp = null, $patternProperties = null, $appliedDefaults = array())
+    {
+        if ($element instanceof UndefinedConstraint) {
+            return;
+        }
+
+        $this->appliedDefaults = $appliedDefaults;
+
+        $matches = array();
+        if ($patternProperties) {
+            // validate the element pattern properties
+            $matches = $this->validatePatternProperties($element, $path, $patternProperties);
+        }
+
+        if ($properties) {
+            // validate the element properties
+            $this->validateProperties($element, $properties, $path);
+        }
+
+        // validate additional element properties & constraints
+        $this->validateElement($element, $matches, $schema, $path, $properties, $additionalProp);
+    }
+
+    public function validatePatternProperties($element, JsonPointer $path = null, $patternProperties)
+    {
+        $try = array('/', '#', '+', '~', '%');
+        $matches = array();
+        foreach ($patternProperties as $pregex => $schema) {
+            $delimiter = '/';
+            // Choose delimiter. Necessary for patterns like ^/ , otherwise you get error
+            foreach ($try as $delimiter) {
+                if (strpos($pregex, $delimiter) === false) { // safe to use
+                    break;
+                }
+            }
+
+            // Validate the pattern before using it to test for matches
+            if (@preg_match($delimiter . $pregex . $delimiter . 'u', '') === false) {
+                $this->addError($path, 'The pattern "' . $pregex . '" is invalid', 'pregex', array('pregex' => $pregex));
+                continue;
+            }
+            foreach ($element as $i => $value) {
+                if (preg_match($delimiter . $pregex . $delimiter . 'u', $i)) {
+                    $matches[] = $i;
+                    $this->checkUndefined($value, $schema ?: new \stdClass(), $path, $i, in_array($i, $this->appliedDefaults));
+                }
+            }
+        }
+
+        return $matches;
+    }
+
+    /**
+     * Validates the element properties
+     *
+     * @param \StdClass        $element        Element to validate
+     * @param array            $matches        Matches from patternProperties (if any)
+     * @param \StdClass        $schema         ObjectConstraint definition
+     * @param JsonPointer|null $path           Current test path
+     * @param \StdClass        $properties     Properties
+     * @param mixed            $additionalProp Additional properties
+     */
+    public function validateElement($element, $matches, $schema = null, JsonPointer $path = null,
+        $properties = null, $additionalProp = null)
+    {
+        $this->validateMinMaxConstraint($element, $schema, $path);
+
+        foreach ($element as $i => $value) {
+            $definition = $this->getProperty($properties, $i);
+
+            // no additional properties allowed
+            if (!in_array($i, $matches) && $additionalProp === false && $this->inlineSchemaProperty !== $i && !$definition) {
+                $this->addError($path, 'The property ' . $i . ' is not defined and the definition does not allow additional properties', 'additionalProp');
+            }
+
+            // additional properties defined
+            if (!in_array($i, $matches) && $additionalProp && !$definition) {
+                if ($additionalProp === true) {
+                    $this->checkUndefined($value, null, $path, $i, in_array($i, $this->appliedDefaults));
+                } else {
+                    $this->checkUndefined($value, $additionalProp, $path, $i, in_array($i, $this->appliedDefaults));
+                }
+            }
+
+            // property requires presence of another
+            $require = $this->getProperty($definition, 'requires');
+            if ($require && !$this->getProperty($element, $require)) {
+                $this->addError($path, 'The presence of the property ' . $i . ' requires that ' . $require . ' also be present', 'requires');
+            }
+
+            $property = $this->getProperty($element, $i, $this->factory->createInstanceFor('undefined'));
+            if (is_object($property)) {
+                $this->validateMinMaxConstraint(!($property instanceof UndefinedConstraint) ? $property : $element, $definition, $path);
+            }
+        }
+    }
+
+    /**
+     * Validates the definition properties
+     *
+     * @param \stdClass        $element    Element to validate
+     * @param \stdClass        $properties Property definitions
+     * @param JsonPointer|null $path       Path?
+     */
+    public function validateProperties(&$element, $properties = null, JsonPointer $path = null)
+    {
+        $undefinedConstraint = $this->factory->createInstanceFor('undefined');
+
+        foreach ($properties as $i => $value) {
+            $property = &$this->getProperty($element, $i, $undefinedConstraint);
+            $definition = $this->getProperty($properties, $i);
+
+            if (is_object($definition)) {
+                // Undefined constraint will check for is_object() and quit if is not - so why pass it?
+                $this->checkUndefined($property, $definition, $path, $i, in_array($i, $this->appliedDefaults));
+            }
+        }
+    }
+
+    /**
+     * retrieves a property from an object or array
+     *
+     * @param mixed  $element  Element to validate
+     * @param string $property Property to retrieve
+     * @param mixed  $fallback Default value if property is not found
+     *
+     * @return mixed
+     */
+    protected function &getProperty(&$element, $property, $fallback = null)
+    {
+        if (is_array($element) && (isset($element[$property]) || array_key_exists($property, $element)) /*$this->checkMode == self::CHECK_MODE_TYPE_CAST*/) {
+            return $element[$property];
+        } elseif (is_object($element) && property_exists($element, $property)) {
+            return $element->$property;
+        }
+
+        return $fallback;
+    }
+
+    /**
+     * validating minimum and maximum property constraints (if present) against an element
+     *
+     * @param \stdClass        $element          Element to validate
+     * @param \stdClass        $objectDefinition ObjectConstraint definition
+     * @param JsonPointer|null $path             Path to test?
+     */
+    protected function validateMinMaxConstraint($element, $objectDefinition, JsonPointer $path = null)
+    {
+        // Verify minimum number of properties
+        if (isset($objectDefinition->minProperties) && !is_object($objectDefinition->minProperties)) {
+            if ($this->getTypeCheck()->propertyCount($element) < $objectDefinition->minProperties) {
+                $this->addError($path, 'Must contain a minimum of ' . $objectDefinition->minProperties . ' properties', 'minProperties', array('minProperties' => $objectDefinition->minProperties));
+            }
+        }
+        // Verify maximum number of properties
+        if (isset($objectDefinition->maxProperties) && !is_object($objectDefinition->maxProperties)) {
+            if ($this->getTypeCheck()->propertyCount($element) > $objectDefinition->maxProperties) {
+                $this->addError($path, 'Must contain no more than ' . $objectDefinition->maxProperties . ' properties', 'maxProperties', array('maxProperties' => $objectDefinition->maxProperties));
+            }
+        }
+    }
+}