Example #1
0
 /**
  * {@inheritdoc}
  */
 public function apply($instance, stdClass $schema, Context $context, Walker $walker)
 {
     if (is_object($schema->items)) {
         // 8.2.3.1. If items is a schema, then the child instance must be
         // valid against this schema, regardless of its index, and
         // regardless of the value of "additionalItems".
         foreach ($instance as $index => $item) {
             $context->enterNode($index);
             $walker->applyConstraints($item, $schema->items, $context);
             $context->leaveNode();
         }
     } else {
         // "items" is an array
         $itemSize = count($schema->items);
         foreach ($instance as $index => $item) {
             $context->enterNode($index);
             // 8.2.3.2.  If the index is less than, or equal to, the size of
             // "items", the child instance must be valid against the
             // corresponding schema in the "items" array; otherwise, it must
             // be valid against the schema defined by "additionalItems".
             //
             // NOTE: this is adapted for 0-based indexation.
             if ($index < $itemSize) {
                 $walker->applyConstraints($item, $schema->items[$index], $context);
             } elseif ($schema->additionalItems === false) {
                 $context->addViolation('additional items are not allowed');
             } else {
                 $walker->applyConstraints($item, $schema->additionalItems, $context);
             }
             $context->leaveNode();
         }
     }
 }
Example #2
0
 /**
  * {@inheritdoc}
  */
 public function apply($instance, stdClass $schema, Context $context, Walker $walker)
 {
     $accumulatingContext = $context->duplicate(false);
     $hasMatch = false;
     $hasDoubleMatch = false;
     foreach ($schema->oneOf as $subSchema) {
         $subContext = $context->duplicate(false);
         $walker->applyConstraints($instance, $subSchema, $subContext);
         if ($subContext->countViolations() === 0) {
             if (!$hasMatch) {
                 $hasMatch = true;
             } else {
                 $hasDoubleMatch = true;
                 break;
             }
         } else {
             $accumulatingContext->mergeViolations($subContext);
         }
     }
     if (!$hasMatch) {
         $context->mergeViolations($accumulatingContext);
     }
     if (!$hasMatch || $hasDoubleMatch) {
         $context->addViolation('instance must match exactly one of the schemas listed in oneOf');
     }
 }
Example #3
0
 /**
  * {@inheritdoc}
  */
 public function apply($instance, stdClass $schema, Context $context, Walker $walker)
 {
     $length = extension_loaded('mbstring') ? mb_strlen($instance, mb_detect_encoding($instance)) : strlen($instance);
     if ($length > $schema->maxLength) {
         $context->addViolation('should be lesser than or equal to %s characters', [$schema->maxLength]);
     }
 }
Example #4
0
 /**
  * {@inheritdoc}
  */
 public function normalize(stdClass $schema, Context $context, Walker $walker)
 {
     $context->enterNode('dependencies');
     if (!is_object($schema->dependencies)) {
         throw new InvalidTypeException($context, Types::TYPE_OBJECT);
     }
     foreach ($schema->dependencies as $property => $value) {
         $context->enterNode($property);
         if (is_object($value)) {
             $walker->parseSchema($value, $context);
         } elseif (is_array($value)) {
             if (0 === ($propertyCount = count($value))) {
                 throw new EmptyArrayException($context);
             }
             foreach ($value as $index => $subProperty) {
                 if (!is_string($subProperty)) {
                     $context->enterNode($index);
                     throw new InvalidTypeException($context, Types::TYPE_STRING);
                 }
             }
             if (count(array_unique($value)) !== $propertyCount) {
                 throw new NotUniqueException($context);
             }
         } else {
             throw new InvalidTypeException($context, [Types::TYPE_OBJECT, Types::TYPE_ARRAY]);
         }
         $context->leaveNode();
     }
     $context->leaveNode();
 }
Example #5
0
 /**
  * {@inheritdoc}
  */
 public function apply($instance, stdClass $schema, Context $context, Walker $walker)
 {
     if (!is_string($instance)) {
         $context->addViolation('should be a string');
     } elseif ($schema->format === 'date-time') {
         // PHP support for RFC3339 doesn't include fractional time
         // (milliseconds) so we must add another check if needed
         if (!$this->isDateTimeValid($instance, DATE_RFC3339) && !$this->isDateTimeValid($instance, 'Y-m-d\\TH:i:s.uP')) {
             $context->addViolation('should be a valid date-time (RFC3339)');
         }
     } elseif ($schema->format === 'email') {
         if (!filter_var($instance, FILTER_VALIDATE_EMAIL)) {
             $context->addViolation('should be a valid email');
         }
     } elseif ($schema->format === 'hostname') {
         if (!preg_match(self::HOSTNAME_REGEX, $instance)) {
             $context->addViolation('should be a valid hostname');
         }
     } elseif ($schema->format === 'ipv4') {
         if (!filter_var($instance, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
             $context->addViolation('should be a valid IPv4 address');
         }
     } elseif ($schema->format === 'ipv6') {
         if (!filter_var($instance, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
             $context->addViolation('should be a valid IPv6 address');
         }
     } elseif ($schema->format === 'uri') {
         if (!preg_match(self::URI_REGEX, $instance)) {
             $context->addViolation('should be a valid URI (RFC3986)');
         }
     }
 }
Example #6
0
 /**
  * {@inheritdoc}
  */
 public function apply($instance, stdClass $schema, Context $context, Walker $walker)
 {
     $altContext = $context->duplicate();
     $walker->applyConstraints($instance, $schema->not, $altContext);
     if ($altContext->countViolations() === $context->countViolations()) {
         $context->addViolation('should not match schema in "not"');
     }
 }
Example #7
0
 /**
  * {@inheritdoc}
  */
 public function apply($instance, stdClass $schema, Context $context, Walker $walker)
 {
     foreach ($schema->required as $property) {
         if (!property_exists($instance, $property)) {
             $context->addViolation('property "%s" is missing', [$property]);
         }
     }
 }
Example #8
0
 /**
  * {@inheritdoc}
  */
 public function apply($instance, stdClass $schema, Context $context, Walker $walker)
 {
     if ($schema->exclusiveMaximum === false) {
         if ($instance > $schema->maximum) {
             $context->addViolation('should be lesser than or equal to %s', [$schema->maximum]);
         }
     } elseif ($instance >= $schema->maximum) {
         $context->addViolation('should be lesser than %s', [$schema->maximum]);
     }
 }
Example #9
0
 /**
  * {@inheritdoc}
  */
 public function apply($instance, stdClass $schema, Context $context, Walker $walker)
 {
     $originalCount = $context->countViolations();
     foreach ($schema->allOf as $subSchema) {
         $walker->applyConstraints($instance, $subSchema, $context);
     }
     if ($context->countViolations() > $originalCount) {
         $context->addViolation('instance must match all the schemas listed in allOf');
     }
 }
Example #10
0
 /**
  * {@inheritdoc}
  */
 public function apply($instance, stdClass $schema, Context $context, Walker $walker)
 {
     if (is_string($schema->type)) {
         if (!Types::isA($instance, $schema->type)) {
             $context->addViolation('instance must be of type %s', [$schema->type]);
         }
     } else {
         if (!Types::isOneOf($instance, $schema->type)) {
             $context->addViolation('instance does not match any of the expected types');
         }
     }
 }
Example #11
0
 /**
  * {@inheritdoc}
  */
 public function normalize(stdClass $schema, Context $context, Walker $walker)
 {
     $keyword = $this->keywords()[0];
     $context->enterNode($keyword);
     if (!is_int($schema->{$keyword})) {
         throw new InvalidTypeException($context, Types::TYPE_INTEGER);
     }
     if ($schema->{$keyword} < 0) {
         throw new LessThanZeroException($context);
     }
     $context->leaveNode();
 }
Example #12
0
 /**
  * {@inheritdoc}
  */
 public function apply($instance, stdClass $schema, Context $context, Walker $walker)
 {
     if ($schema->uniqueItems === true) {
         foreach ($instance as $i => $aItem) {
             foreach ($instance as $j => $bItem) {
                 if ($i !== $j && Utils::areEqual($aItem, $bItem)) {
                     $context->addViolation('elements must be unique');
                     break 2;
                 }
             }
         }
     }
 }
Example #13
0
 /**
  * @dataProvider fileDataProvider
  *
  * @param string    $file
  * @param string    $title
  * @param mixed     $instance
  * @param \stdClass $schema
  * @param bool      $isInstanceValid
  * @param array     $expectedErrors
  */
 public function testApply($file, $title, $instance, \stdClass $schema, $isInstanceValid, array $expectedErrors)
 {
     $constraint = $this->getConstraint();
     $schemaContext = new Context();
     $validationContext = new Context();
     $walker = new Walker(new Registry(), new Resolver());
     $pathBefore = $schemaContext->getCurrentPath();
     $constraint->normalize($schema, $schemaContext, $walker);
     $this->assertSame($pathBefore, $schemaContext->getCurrentPath());
     $constraint->apply($instance, $schema, $validationContext, $walker);
     $actualErrors = $validationContext->getViolations();
     $this->assertValidationResult($file, $title, $instance, $schema, $isInstanceValid, $expectedErrors, $actualErrors);
 }
Example #14
0
 /**
  * {@inheritdoc}
  */
 public function apply($instance, stdClass $schema, Context $context, Walker $walker)
 {
     $hasMatch = false;
     foreach ($schema->enum as $value) {
         if (Utils::areEqual($instance, $value)) {
             $hasMatch = true;
             break;
         }
     }
     if (!$hasMatch) {
         $context->addViolation('should match one element in enum');
     }
 }
Example #15
0
 /**
  * {@inheritdoc}
  */
 public function apply($instance, stdClass $schema, Context $context, Walker $walker)
 {
     $divider = $schema->multipleOf;
     $modulus = fmod($instance, $divider);
     $precision = abs(1.0E-10);
     $diff = (double) ($modulus - $divider);
     if (-$precision < $diff && $diff < $precision) {
         $fMod = 0.0;
     } else {
         $decimals1 = mb_strpos($instance, '.') ? mb_strlen($instance) - mb_strpos($instance, '.') - 1 : 0;
         $decimals2 = mb_strpos($divider, '.') ? mb_strlen($divider) - mb_strpos($divider, '.') - 1 : 0;
         $fMod = (double) round($modulus, max($decimals1, $decimals2));
     }
     if ($fMod != 0) {
         $context->addViolation('should be a multiple of %s', [$divider]);
     }
 }
Example #16
0
 /**
  * {@inheritdoc}
  */
 public function apply($instance, stdClass $schema, Context $context, Walker $walker)
 {
     $accumulatingContext = $context->duplicate();
     $hasMatch = false;
     foreach ($schema->anyOf as $subSchema) {
         $originalCount = $accumulatingContext->countViolations();
         $walker->applyConstraints($instance, $subSchema, $accumulatingContext);
         if ($accumulatingContext->countViolations() === $originalCount) {
             $hasMatch = true;
             break;
         }
     }
     if (!$hasMatch) {
         $context->mergeViolations($accumulatingContext);
         $context->addViolation('instance must match at least one of the schemas listed in anyOf');
     }
 }
Example #17
0
 /**
  * {@inheritdoc}
  */
 public function normalize(stdClass $schema, Context $context, Walker $walker)
 {
     $property = $this->keywords()[0];
     $secondaryProperty = $this->keywords()[1];
     if (!property_exists($schema, $property)) {
         throw new MissingKeywordException($context, $property);
     }
     if (!property_exists($schema, $secondaryProperty)) {
         $schema->{$secondaryProperty} = false;
     }
     if (!Types::isA($schema->{$property}, Types::TYPE_NUMBER)) {
         $context->enterNode($property);
         throw new InvalidTypeException($context, Types::TYPE_NUMBER);
     }
     if (!is_bool($schema->{$secondaryProperty})) {
         $context->enterNode($secondaryProperty);
         throw new InvalidTypeException($context, Types::TYPE_BOOLEAN);
     }
 }
Example #18
0
 /**
  * {@inheritdoc}
  */
 public function normalize(stdClass $schema, Context $context, Walker $walker)
 {
     $keyword = $this->keywords()[0];
     $context->enterNode($keyword);
     if (!is_array($schema->{$keyword})) {
         throw new InvalidTypeException($context, Types::TYPE_ARRAY);
     }
     if (count($schema->{$keyword}) === 0) {
         throw new EmptyArrayException($context);
     }
     foreach ($schema->{$keyword} as $index => $subSchema) {
         $context->enterNode($index);
         if (!is_object($subSchema)) {
             throw new InvalidTypeException($context, Types::TYPE_OBJECT);
         }
         $walker->parseSchema($subSchema, $context);
         $context->leaveNode();
     }
     $context->leaveNode();
 }
Example #19
0
 /**
  * @return string
  */
 public function getPath()
 {
     return $this->context->getCurrentPath();
 }
Example #20
0
 private function parsePatternPropertiesProperty(stdClass $schema, Context $context, Walker $walker)
 {
     if (!is_object($schema->patternProperties)) {
         throw new InvalidTypeException($context, Types::TYPE_OBJECT);
     }
     foreach ($schema->patternProperties as $regex => $value) {
         $context->enterNode($regex);
         if (!Utils::isValidRegex($regex)) {
             throw new InvalidRegexException($context);
         }
         if (!is_object($value)) {
             throw new InvalidTypeException($context, Types::TYPE_OBJECT);
         }
         $walker->parseSchema($value, $context);
         $context->leaveNode();
     }
 }
Example #21
0
 /**
  * {@inheritdoc}
  */
 public function apply($instance, stdClass $schema, Context $context, Walker $walker)
 {
     if (!Utils::matchesRegex($instance, $schema->pattern)) {
         $context->addViolation('should match regex "%s"', [$schema->pattern]);
     }
 }
Example #22
0
 /**
  * {@inheritdoc}
  */
 public function apply($instance, stdClass $schema, Context $context, Walker $walker)
 {
     if (count(get_object_vars($instance)) < $schema->minProperties) {
         $context->addViolation('number of properties should be greater than or equal to %s', [$schema->minProperties]);
     }
 }
Example #23
0
 /**
  * {@inheritdoc}
  */
 public function apply($instance, stdClass $schema, Context $context, Walker $walker)
 {
     if (count($instance) < $schema->minItems) {
         $context->addViolation('number of items should be greater than or equal to %s', [$schema->minItems]);
     }
 }