Skip to content
This repository has been archived by the owner on May 12, 2018. It is now read-only.

Throw on invalid schemas #73

Merged
merged 1 commit into from Nov 23, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -25,4 +25,4 @@ script:
- vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover

after_script:
- if [[ $TRAVIS_PHP_VERSION != 'hhvm' && $TRAVIS_PHP_VERSION != '7.0' ]]; then php vendor/bin/ocular code-coverage:upload --format=php-clover coverage.clover; fi
- if [[ $TRAVIS_PHP_VERSION != 'hhvm' && $TRAVIS_PHP_VERSION != '7.0' && $TRAVIS_PHP_VERSION != '7.1' ]]; then php vendor/bin/ocular code-coverage:upload --format=php-clover coverage.clover; fi
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -17,6 +17,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
* Any calls to `ValidationError@getCode` need to be changed to `ValidationError@getKeyword`.
* If you are using the `ArrayAccess` interface for `ValidationError` you need to replace any usage of the `code` key with `keyword`.
* Instead of there being a different code for every format failure, they just return the keyword 'format'.
* Invalid schemas now throw an InvalidSchemaException.

### Fixed

Expand Down
75 changes: 75 additions & 0 deletions src/Assert.php
@@ -0,0 +1,75 @@
<?php

namespace League\JsonGuard;

use League\JsonGuard\Exceptions\InvalidSchemaException;

/**
* Assertions to verify a schema is valid.
*/
class Assert
{
/**
* Validate an array has at least one element.
*
* @param array $value
* @param string $keyword
* @param string|null $pointer
*/
public static function notEmpty(array $value, $keyword, $pointer = null)
{
if (!empty($value)) {
return;
}

throw InvalidSchemaException::emptyArray($keyword, $pointer);
}

/**
* Validate an integer is non-negative.
*
* @param integer $value
* @param string $keyword
* @param string|null $pointer
*/
public static function nonNegative($value, $keyword, $pointer = null)
{
if ($value >= 0) {
return;
}

throw InvalidSchemaException::negativeValue(
$value,
$keyword,
$pointer
);
}

/**
* Validate a value is one of the allowed types.
*
* @param mixed $value
* @param array|string $choices
* @param string $keyword
* @param string|null $pointer
*
* @throws InvalidSchemaException
*/
public static function type($value, $choices, $keyword, $pointer = null)
{
$actualType = gettype($value);
$choices = is_array($choices) ? $choices : [$choices];

if (in_array($actualType, $choices) ||
(is_json_number($value) && in_array('number', $choices))) {
return;
}

throw InvalidSchemaException::invalidParameterType(
$actualType,
$choices,
$keyword,
$pointer
);
}
}
4 changes: 4 additions & 0 deletions src/Constraints/AdditionalItems.php
Expand Up @@ -2,6 +2,7 @@

namespace League\JsonGuard\Constraints;

use League\JsonGuard\Assert;
use League\JsonGuard\SubSchemaValidatorFactory;
use League\JsonGuard\ValidationError;

Expand All @@ -19,10 +20,13 @@ public static function validate(
SubSchemaValidatorFactory $validatorFactory,
$pointer = null
) {
Assert::type($parameter, ['boolean', 'object'], self::KEYWORD, $pointer);

if (!is_array($data) || $parameter === true) {
return null;
}


if (!is_array($items = self::getItems($schema))) {
return null;
}
Expand Down
4 changes: 4 additions & 0 deletions src/Constraints/AdditionalProperties.php
Expand Up @@ -3,6 +3,7 @@
namespace League\JsonGuard\Constraints;

use League\JsonGuard;
use League\JsonGuard\Assert;
use League\JsonGuard\SubSchemaValidatorFactory;
use League\JsonGuard\ValidationError;

Expand All @@ -20,10 +21,13 @@ public static function validate(
SubSchemaValidatorFactory $validatorFactory,
$pointer = null
) {
Assert::type($parameter, ['object', 'boolean'], self::KEYWORD, $pointer);

if (!is_object($data)) {
return null;
}


$diff = self::getDiff($data, $schema);

if (count($diff) === 0) {
Expand Down
6 changes: 3 additions & 3 deletions src/Constraints/AllOf.php
Expand Up @@ -2,6 +2,7 @@

namespace League\JsonGuard\Constraints;

use League\JsonGuard\Assert;
use League\JsonGuard\SubSchemaValidatorFactory;

class AllOf implements ContainerInstanceConstraint
Expand All @@ -13,9 +14,8 @@ class AllOf implements ContainerInstanceConstraint
*/
public static function validate($data, $parameter, SubSchemaValidatorFactory $validatorFactory, $pointer = null)
{
if (!is_array($parameter)) {
return null;
}
Assert::type($parameter, 'array', self::KEYWORD, $pointer);
Assert::notEmpty($parameter, self::KEYWORD, $pointer);

$errors = [];

Expand Down
6 changes: 3 additions & 3 deletions src/Constraints/AnyOf.php
Expand Up @@ -2,6 +2,7 @@

namespace League\JsonGuard\Constraints;

use League\JsonGuard\Assert;
use League\JsonGuard\SubSchemaValidatorFactory;
use League\JsonGuard\ValidationError;

Expand All @@ -14,9 +15,8 @@ class AnyOf implements ContainerInstanceConstraint
*/
public static function validate($data, $parameter, SubSchemaValidatorFactory $validatorFactory, $pointer = null)
{
if (!is_array($parameter)) {
return null;
}
Assert::type($parameter, 'array', self::KEYWORD, $pointer);
Assert::notEmpty($parameter, self::KEYWORD, $pointer);

foreach ($parameter as $schema) {
$validator = $validatorFactory->makeSubSchemaValidator($data, $schema, $pointer);
Expand Down
3 changes: 3 additions & 0 deletions src/Constraints/Dependencies.php
Expand Up @@ -3,6 +3,7 @@
namespace League\JsonGuard\Constraints;

use League\JsonGuard;
use League\JsonGuard\Assert;
use League\JsonGuard\SubSchemaValidatorFactory;
use League\JsonGuard\ValidationError;

Expand All @@ -15,6 +16,8 @@ class Dependencies implements ContainerInstanceConstraint
*/
public static function validate($data, $parameter, SubSchemaValidatorFactory $validatorFactory, $pointer = null)
{
Assert::type($parameter, ['object', 'array'], self::KEYWORD, $pointer);

$errors = [];
foreach ($parameter as $property => $dependencies) {
if (!is_object($data) || !property_exists($data, $property)) {
Expand Down
6 changes: 2 additions & 4 deletions src/Constraints/Enum.php
Expand Up @@ -2,8 +2,8 @@

namespace League\JsonGuard\Constraints;

use League\JsonGuard\Assert;
use League\JsonGuard\ValidationError;
use League\JsonGuard;

class Enum implements PropertyConstraint
{
Expand All @@ -14,9 +14,7 @@ class Enum implements PropertyConstraint
*/
public static function validate($value, $parameter, $pointer = null)
{
if (!is_array($parameter)) {
return null;
}
Assert::type($parameter, 'array', self::KEYWORD, $pointer);

if (in_array($value, $parameter, true)) {
return null;
Expand Down
3 changes: 3 additions & 0 deletions src/Constraints/Format.php
Expand Up @@ -3,6 +3,7 @@
namespace League\JsonGuard\Constraints;

use League\JsonGuard;
use League\JsonGuard\Assert;
use League\JsonGuard\ValidationError;

class Format implements PropertyConstraint
Expand All @@ -20,6 +21,8 @@ class Format implements PropertyConstraint
*/
public static function validate($value, $parameter, $pointer = null)
{
Assert::type($parameter, 'string', self::KEYWORD, $pointer);

switch ($parameter) {
case 'date-time':
return self::validateRegex(
Expand Down
3 changes: 3 additions & 0 deletions src/Constraints/Items.php
Expand Up @@ -2,6 +2,7 @@

namespace League\JsonGuard\Constraints;

use League\JsonGuard\Assert;
use League\JsonGuard\SubSchemaValidatorFactory;

class Items implements ContainerInstanceConstraint
Expand All @@ -13,6 +14,8 @@ class Items implements ContainerInstanceConstraint
*/
public static function validate($data, $parameter, SubSchemaValidatorFactory $validatorFactory, $pointer = null)
{
Assert::type($parameter, ['array', 'object'], self::KEYWORD, $pointer);

if (!is_array($data)) {
return null;
}
Expand Down
7 changes: 5 additions & 2 deletions src/Constraints/Max.php
Expand Up @@ -3,18 +3,21 @@
namespace League\JsonGuard\Constraints;

use League\JsonGuard;
use League\JsonGuard\Assert;
use League\JsonGuard\ValidationError;

class Max implements ParentSchemaAwarePropertyConstraint
{
const KEYWORD = 'max';
const EXCLUSIVE_KEYWORD = 'exclusiveMax';
const KEYWORD = 'maximum';
const EXCLUSIVE_KEYWORD = 'exclusiveMaximum';

/**
* {@inheritdoc}
*/
public static function validate($value, $schema, $parameter, $pointer = null)
{
Assert::type($parameter, 'number', self::KEYWORD, $pointer);

if (isset($schema->exclusiveMaximum) && $schema->exclusiveMaximum === true) {
return self::validateExclusiveMax($value, $parameter, $pointer);
}
Expand Down
4 changes: 4 additions & 0 deletions src/Constraints/MaxItems.php
Expand Up @@ -3,6 +3,7 @@
namespace League\JsonGuard\Constraints;

use League\JsonGuard;
use League\JsonGuard\Assert;
use League\JsonGuard\ValidationError;

class MaxItems implements PropertyConstraint
Expand All @@ -14,6 +15,9 @@ class MaxItems implements PropertyConstraint
*/
public static function validate($value, $parameter, $pointer = null)
{
Assert::type($parameter, 'integer', self::KEYWORD, $pointer);
Assert::nonNegative($parameter, self::KEYWORD, $pointer);

if (!is_array($value) || count($value) <= $parameter) {
return null;
}
Expand Down
4 changes: 4 additions & 0 deletions src/Constraints/MaxLength.php
Expand Up @@ -3,6 +3,7 @@
namespace League\JsonGuard\Constraints;

use League\JsonGuard;
use League\JsonGuard\Assert;
use League\JsonGuard\ValidationError;

class MaxLength implements PropertyConstraint
Expand All @@ -14,6 +15,9 @@ class MaxLength implements PropertyConstraint
*/
public static function validate($value, $parameter, $pointer = null)
{
Assert::type($parameter, 'number', self::KEYWORD, $pointer);
Assert::nonNegative($parameter, self::KEYWORD, $pointer);

if (!is_string($value) || JsonGuard\strlen($value) <= $parameter) {
return null;
}
Expand Down
4 changes: 4 additions & 0 deletions src/Constraints/MaxProperties.php
Expand Up @@ -3,6 +3,7 @@
namespace League\JsonGuard\Constraints;

use League\JsonGuard;
use League\JsonGuard\Assert;
use League\JsonGuard\ValidationError;

class MaxProperties implements PropertyConstraint
Expand All @@ -14,6 +15,9 @@ class MaxProperties implements PropertyConstraint
*/
public static function validate($value, $parameter, $pointer = null)
{
Assert::type($parameter, 'integer', self::KEYWORD, $pointer);
Assert::nonNegative($parameter, self::KEYWORD, $pointer);

if (!is_object($value) || count(get_object_vars($value)) <= $parameter) {
return null;
}
Expand Down
7 changes: 5 additions & 2 deletions src/Constraints/Min.php
Expand Up @@ -3,18 +3,21 @@
namespace League\JsonGuard\Constraints;

use League\JsonGuard;
use League\JsonGuard\Assert;
use League\JsonGuard\ValidationError;

class Min implements ParentSchemaAwarePropertyConstraint
{
const KEYWORD = 'min';
const EXCLUSIVE_KEYWORD = 'exclusiveMin';
const KEYWORD = 'minimum';
const EXCLUSIVE_KEYWORD = 'exclusiveMinimum';

/**
* {@inheritdoc}
*/
public static function validate($value, $schema, $parameter, $pointer = null)
{
Assert::type($parameter, 'number', self::KEYWORD, $pointer);

if (isset($schema->exclusiveMinimum) && $schema->exclusiveMinimum === true) {
return self::validateExclusiveMin($value, $parameter, $pointer);
}
Expand Down
4 changes: 4 additions & 0 deletions src/Constraints/MinItems.php
Expand Up @@ -3,6 +3,7 @@
namespace League\JsonGuard\Constraints;

use League\JsonGuard;
use League\JsonGuard\Assert;
use League\JsonGuard\ValidationError;

class MinItems implements PropertyConstraint
Expand All @@ -14,6 +15,9 @@ class MinItems implements PropertyConstraint
*/
public static function validate($value, $parameter, $pointer = null)
{
Assert::type($parameter, 'integer', self::KEYWORD, $pointer);
Assert::nonNegative($parameter, self::KEYWORD, $pointer);

if (!is_array($value) || count($value) >= $parameter) {
return null;
}
Expand Down
4 changes: 4 additions & 0 deletions src/Constraints/MinLength.php
Expand Up @@ -3,6 +3,7 @@
namespace League\JsonGuard\Constraints;

use League\JsonGuard;
use League\JsonGuard\Assert;
use League\JsonGuard\ValidationError;

class MinLength implements PropertyConstraint
Expand All @@ -14,6 +15,9 @@ class MinLength implements PropertyConstraint
*/
public static function validate($value, $parameter, $pointer = null)
{
Assert::type($parameter, 'number', self::KEYWORD, $pointer);
Assert::nonNegative($parameter, self::KEYWORD, $pointer);

if (!is_string($value) || JsonGuard\strlen($value) >= $parameter) {
return null;
}
Expand Down