Skip to content

Commit e1a6b90

Browse files
committed
feat: add more support for draft 06
1 parent 3e7a8c4 commit e1a6b90

14 files changed

+321
-11
lines changed

src/JsonSchema/ConstraintError.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ class ConstraintError extends Enum
1717
public const DIVISIBLE_BY = 'divisibleBy';
1818
public const ENUM = 'enum';
1919
public const CONSTANT = 'const';
20+
public const CONTAINS = 'contains';
2021
public const EXCLUSIVE_MINIMUM = 'exclusiveMinimum';
2122
public const EXCLUSIVE_MAXIMUM = 'exclusiveMaximum';
23+
public const FALSE = 'false';
2224
public const FORMAT_COLOR = 'colorFormat';
2325
public const FORMAT_DATE = 'dateFormat';
2426
public const FORMAT_DATE_TIME = 'dateTimeFormat';
@@ -51,6 +53,7 @@ class ConstraintError extends Enum
5153
public const PREGEX_INVALID = 'pregrex';
5254
public const PROPERTIES_MIN = 'minProperties';
5355
public const PROPERTIES_MAX = 'maxProperties';
56+
public const PROPERTY_NAMES = 'propertyNames';
5457
public const TYPE = 'type';
5558
public const UNIQUE_ITEMS = 'uniqueItems';
5659

@@ -70,8 +73,10 @@ public function getMessage()
7073
self::DIVISIBLE_BY => 'Is not divisible by %d',
7174
self::ENUM => 'Does not have a value in the enumeration %s',
7275
self::CONSTANT => 'Does not have a value equal to %s',
76+
self::CONTAINS => 'Does not have a value valid to contains schema',
7377
self::EXCLUSIVE_MINIMUM => 'Must have a minimum value greater than %d',
7478
self::EXCLUSIVE_MAXIMUM => 'Must have a maximum value less than %d',
79+
self::FALSE => 'Boolean schema false',
7580
self::FORMAT_COLOR => 'Invalid color',
7681
self::FORMAT_DATE => 'Invalid date %s, expected format YYYY-MM-DD',
7782
self::FORMAT_DATE_TIME => 'Invalid date-time %s, expected format YYYY-MM-DDThh:mm:ssZ or YYYY-MM-DDThh:mm:ss+hh:mm',
@@ -104,6 +109,7 @@ public function getMessage()
104109
self::PREGEX_INVALID => 'The pattern %s is invalid',
105110
self::PROPERTIES_MIN => 'Must contain a minimum of %d properties',
106111
self::PROPERTIES_MAX => 'Must contain no more than %d properties',
112+
self::PROPERTY_NAMES => 'Property name %s is invalid',
107113
self::TYPE => '%s value found, but %s is required',
108114
self::UNIQUE_ITEMS => 'There are no duplicates allowed in the array'
109115
];
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace JsonSchema\Constraints\Drafts\Draft06;
6+
7+
use JsonSchema\ConstraintError;
8+
use JsonSchema\Constraints\ConstraintInterface;
9+
use JsonSchema\Constraints\Factory;
10+
use JsonSchema\Entity\ErrorBagProxy;
11+
use JsonSchema\Entity\JsonPointer;
12+
13+
class AdditionalItemsConstraint implements ConstraintInterface
14+
{
15+
use ErrorBagProxy;
16+
17+
public function __construct(?Factory $factory = null)
18+
{
19+
$this->initialiseErrorBag($factory ?: new Factory());
20+
}
21+
22+
public function check(&$value, $schema = null, ?JsonPointer $path = null, $i = null): void
23+
{
24+
if (!property_exists($schema, 'additionalItems')) {
25+
return;
26+
}
27+
28+
if ($schema->additionalItems === true) {
29+
return;
30+
}
31+
32+
if (!is_array($value)) {
33+
return;
34+
}
35+
36+
$additionalItems = array_diff_key($value, $schema->items);
37+
38+
foreach ($additionalItems as $key => $_) {
39+
$this->addError(ConstraintError::ADDITIONAL_ITEMS(), $path, ['item' => $i, 'property' => $key, 'additionalItems' => $schema->additionalItems]);
40+
}
41+
42+
43+
}
44+
}

src/JsonSchema/Constraints/Drafts/Draft06/AdditionalPropertiesConstraint.php

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,20 @@
66

77
use JsonSchema\ConstraintError;
88
use JsonSchema\Constraints\ConstraintInterface;
9-
use JsonSchema\Constraints\Factory;
109
use JsonSchema\Entity\ErrorBagProxy;
1110
use JsonSchema\Entity\JsonPointer;
1211

1312
class AdditionalPropertiesConstraint implements ConstraintInterface
1413
{
1514
use ErrorBagProxy;
1615

16+
/** @var Factory */
17+
private $factory;
18+
1719
public function __construct(?Factory $factory = null)
1820
{
19-
$this->initialiseErrorBag($factory ?: new Factory());
21+
$this->factory = $factory ?: new Factory();
22+
$this->initialiseErrorBag($this->factory);
2023
}
2124

2225
public function check(&$value, $schema = null, ?JsonPointer $path = null, $i = null): void
@@ -52,8 +55,18 @@ public function check(&$value, $schema = null, ?JsonPointer $path = null, $i = n
5255
}
5356
}
5457

55-
if ($schema->additionalProperties === false && $additionalProperties !== []) {
56-
$this->addError(ConstraintError::ADDITIONAL_PROPERTIES(), $path, ['additionalProperties' => array_keys($additionalProperties)]);
58+
if (is_object($schema->additionalProperties)) {
59+
foreach ($additionalProperties as $key => $additionalPropertiesValue) {
60+
$schemaConstraint = $this->factory->createInstanceFor('schema');
61+
$schemaConstraint->check($additionalPropertiesValue, $schema->additionalProperties, $path, $i); // @todo increment path
62+
if ($schemaConstraint->isValid()) {
63+
unset($additionalProperties[$key]);
64+
}
65+
}
66+
}
67+
68+
foreach ($additionalProperties as $key => $additionalPropertiesValue) {
69+
$this->addError(ConstraintError::ADDITIONAL_PROPERTIES(), $path, ['found' => $additionalPropertiesValue]);
5770
}
5871
}
5972
}

src/JsonSchema/Constraints/Drafts/Draft06/AnyOfConstraint.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ public function check(&$value, $schema = null, ?JsonPointer $path = null, $i = n
3939
return;
4040
}
4141
} catch (ValidationException $e) {}
42-
43-
$this->addError(ConstraintError::ANY_OF(), $path);
4442
}
4543

44+
$this->addError(ConstraintError::ANY_OF(), $path);
45+
4646
}
4747
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace JsonSchema\Constraints\Drafts\Draft06;
6+
7+
use JsonSchema\ConstraintError;
8+
use JsonSchema\Constraints\ConstraintInterface;
9+
use JsonSchema\Entity\ErrorBagProxy;
10+
use JsonSchema\Entity\JsonPointer;
11+
12+
class ContainsConstraint implements ConstraintInterface
13+
{
14+
use ErrorBagProxy;
15+
16+
/** @var Factory */
17+
private $factory;
18+
public function __construct(?Factory $factory = null)
19+
{
20+
$this->factory = $factory ?: new Factory();
21+
$this->initialiseErrorBag($this->factory);
22+
}
23+
24+
public function check(&$value, $schema = null, ?JsonPointer $path = null, $i = null): void
25+
{
26+
if (!property_exists($schema, 'contains')) {
27+
return;
28+
}
29+
30+
$properties = [];
31+
if (is_array($value)) {
32+
$properties = $value;
33+
}
34+
if (is_object($value)) {
35+
$properties = get_object_vars($value);
36+
}
37+
38+
foreach ($properties as $propertyName => $propertyValue) {
39+
$schemaConstraint = $this->factory->createInstanceFor('schema');
40+
41+
$schemaConstraint->check($propertyValue, $schema->contains, $path, $i);
42+
if ($schemaConstraint->isValid()) {
43+
return;
44+
}
45+
}
46+
47+
$this->addError(ConstraintError::CONTAINS(), $path, ['contains' => $schema->contains]);
48+
}
49+
}

src/JsonSchema/Constraints/Drafts/Draft06/Draft06Constraint.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace JsonSchema\Constraints\Drafts\Draft06;
66

7+
use JsonSchema\ConstraintError;
78
use JsonSchema\Constraints\Constraint;
89
use JsonSchema\Entity\JsonPointer;
910

@@ -16,19 +17,28 @@ public function __construct()
1617

1718
public function check(&$value, $schema = null, ?JsonPointer $path = null, $i = null): void
1819
{
20+
if (is_bool($schema)) {
21+
if ($schema === false) {
22+
$this->addError(ConstraintError::FALSE(), $path, []);
23+
}
24+
return;
25+
}
26+
1927
// Apply defaults
2028
$this->checkForKeyword('required', $value, $schema, $path, $i);
29+
$this->checkForKeyword('contains', $value, $schema, $path, $i);
30+
$this->checkForKeyword('propertyNames', $value, $schema, $path, $i);
31+
$this->checkForKeyword('patternProperties', $value, $schema, $path, $i);
2132
$this->checkForKeyword('type', $value, $schema, $path, $i);
2233
// Not
2334
$this->checkForKeyword('dependencies', $value, $schema, $path, $i);
2435
// allof
2536
$this->checkForKeyword('anyOf', $value, $schema, $path, $i);
2637
// oneof
2738

28-
// array
29-
// object
30-
// string
3139
$this->checkForKeyword('additionalProperties', $value, $schema, $path, $i);
40+
$this->checkForKeyword('items', $value, $schema, $path, $i);
41+
$this->checkForKeyword('additionalItems', $value, $schema, $path, $i);
3242
$this->checkForKeyword('uniqueItems', $value, $schema, $path, $i);
3343
$this->checkForKeyword('minItems', $value, $schema, $path, $i);
3444
$this->checkForKeyword('minProperties', $value, $schema, $path, $i);

src/JsonSchema/Constraints/Drafts/Draft06/Factory.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class Factory extends \JsonSchema\Constraints\Factory
1212
protected $constraintMap = [
1313
'schema' => Draft06Constraint::class,
1414
'additionalProperties' => AdditionalPropertiesConstraint::class,
15+
'additionalItems' => AdditionalItemsConstraint::class,
1516
'dependencies' => DependenciesConstraint::class,
1617
'type' => TypeConstraint::class,
1718
'const' => ConstConstraint::class,
@@ -31,5 +32,9 @@ class Factory extends \JsonSchema\Constraints\Factory
3132
'required' => RequiredConstraint::class,
3233
'format' => FormatConstraint::class,
3334
'anyOf' => AnyOfConstraint::class,
35+
'contains' => ContainsConstraint::class,
36+
'propertyNames' => PropertiesNamesConstraint::class,
37+
'patternProperties' => PatternPropertiesConstraint::class,
38+
'items' => ItemsConstraint::class,
3439
];
3540
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace JsonSchema\Constraints\Drafts\Draft06;
6+
7+
use JsonSchema\ConstraintError;
8+
use JsonSchema\Constraints\ConstraintInterface;
9+
use JsonSchema\Constraints\Factory;
10+
use JsonSchema\Entity\ErrorBagProxy;
11+
use JsonSchema\Entity\JsonPointer;
12+
use JsonSchema\Rfc3339;
13+
use JsonSchema\Tool\Validator\RelativeReferenceValidator;
14+
use JsonSchema\Tool\Validator\UriValidator;
15+
16+
class ItemsConstraint implements ConstraintInterface
17+
{
18+
use ErrorBagProxy;
19+
20+
/** @var \JsonSchema\Constraints\Drafts\Draft06\Factory */
21+
private $factory;
22+
public function __construct(?Factory $factory = null)
23+
{
24+
$this->factory = $factory ?: new Factory();
25+
$this->initialiseErrorBag($this->factory);
26+
}
27+
28+
public function check(&$value, $schema = null, ?JsonPointer $path = null, $i = null): void
29+
{
30+
if (!property_exists($schema, 'items')) {
31+
return;
32+
}
33+
34+
$properties = [];
35+
if (is_object($value)) {
36+
$properties = get_object_vars($value);
37+
}
38+
if (is_array($value)) {
39+
$properties = $value;
40+
}
41+
if (is_object($schema->items)) {
42+
foreach ($properties as $propertyName => $propertyValue) {
43+
$schemaConstraint = $this->factory->createInstanceFor('schema');
44+
$schemaConstraint->check($propertyValue, $schema->items, $path, $i);
45+
if ($schemaConstraint->isValid()) {
46+
continue;
47+
}
48+
49+
$this->addErrors($schemaConstraint->getErrors());
50+
}
51+
}
52+
}
53+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace JsonSchema\Constraints\Drafts\Draft06;
6+
7+
use JsonSchema\ConstraintError;
8+
use JsonSchema\Constraints\ConstraintInterface;
9+
use JsonSchema\Entity\ErrorBagProxy;
10+
use JsonSchema\Entity\JsonPointer;
11+
12+
class PatternPropertiesConstraint implements ConstraintInterface
13+
{
14+
use ErrorBagProxy;
15+
16+
/** @var Factory */
17+
private $factory;
18+
19+
public function __construct(?Factory $factory = null)
20+
{
21+
$this->factory = $factory ?: new Factory();
22+
$this->initialiseErrorBag($this->factory);
23+
}
24+
25+
public function check(&$value, $schema = null, ?JsonPointer $path = null, $i = null): void
26+
{
27+
if (!property_exists($schema, 'patternProperties')) {
28+
return;
29+
}
30+
31+
$properties = get_object_vars($value);
32+
33+
34+
foreach ($properties as $propertyName => $propertyValue) {
35+
foreach ($schema->patternProperties as $patternPropertyRegex => $patternPropertySchema) {
36+
if (preg_match('/' . str_replace('/', '\/', $patternPropertyRegex) . '/', $propertyName)) {
37+
$schemaConstraint = $this->factory->createInstanceFor('schema');
38+
$schemaConstraint->check($propertyValue, $patternPropertySchema, $path, $i);
39+
if ($schemaConstraint->isValid()) {
40+
continue 2;
41+
}
42+
43+
$this->addErrors($schemaConstraint->getErrors());
44+
}
45+
}
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)