Skip to content

Commit 5024779

Browse files
author
Alexander Miertsch
authored
Merge pull request #3 from event-engine/feature/validation_rules
Detect validation rules
2 parents a125d6a + a205489 commit 5024779

12 files changed

+250
-28
lines changed

src/ProvidesValidationRules.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
/**
3+
* This file is part of event-engine/php-json-schema.
4+
* (c) 2018-2019 prooph software GmbH <[email protected]>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace EventEngine\JsonSchema;
13+
14+
interface ProvidesValidationRules
15+
{
16+
public static function validationRules(): array;
17+
}

src/RecordLogic/TypeDetector.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ public static function getTypeFromClass(string $classOrType, bool $allowNestedSc
2828
}
2929

3030
if($refObj->implementsInterface(JsonSchemaAwareCollection::class)) {
31-
return JsonSchema::array(\call_user_func([$classOrType, '__itemSchema']));
31+
$validation = is_callable([$classOrType, 'validationRules'])? \call_user_func([$classOrType, 'validationRules']) : null;
32+
return JsonSchema::array(\call_user_func([$classOrType, '__itemSchema']), $validation);
3233
}
3334

3435
if($scalarSchemaType = self::determineScalarTypeIfPossible($classOrType)) {
@@ -41,15 +42,18 @@ public static function getTypeFromClass(string $classOrType, bool $allowNestedSc
4142
private static function determineScalarTypeIfPossible(string $class): ?Type
4243
{
4344
if(is_callable([$class, 'fromString'])) {
44-
return JsonSchema::string();
45+
$validation = is_callable([$class, 'validationRules'])? \call_user_func([$class, 'validationRules']) : null;
46+
return JsonSchema::string($validation);
4547
}
4648

4749
if(is_callable([$class, 'fromInt'])) {
48-
return JsonSchema::integer();
50+
$validation = is_callable([$class, 'validationRules'])? \call_user_func([$class, 'validationRules']) : null;
51+
return JsonSchema::integer($validation);
4952
}
5053

5154
if(is_callable([$class, 'fromFloat'])) {
52-
return JsonSchema::float();
55+
$validation = is_callable([$class, 'validationRules'])? \call_user_func([$class, 'validationRules']) : null;
56+
return JsonSchema::float($validation);
5357
}
5458

5559
if(is_callable([$class, 'fromBool'])) {

src/Type/ArrayType.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use EventEngine\JsonSchema\AnnotatedType;
1515
use EventEngine\JsonSchema\JsonSchema;
16+
use EventEngine\JsonSchema\Type;
1617
use EventEngine\Schema\PayloadSchema;
1718
use EventEngine\Schema\TypeSchema;
1819

@@ -21,6 +22,11 @@ final class ArrayType implements AnnotatedType, PayloadSchema
2122
use NullableType,
2223
HasAnnotations;
2324

25+
public const MAX_ITEMS = 'maxItems';
26+
public const MIN_ITEMS = 'minItems';
27+
public const UNIQUE_ITEMS = 'uniqueItems';
28+
public const CONTAINS = 'contains';
29+
2430
/**
2531
* @var string|array
2632
*/
@@ -42,6 +48,58 @@ public function __construct(TypeSchema $itemSchema, array $validation = null)
4248
$this->validation = $validation;
4349
}
4450

51+
public function withMaxItems(int $maxItems): self
52+
{
53+
$cp = clone $this;
54+
55+
$validation = (array) $this->validation;
56+
57+
$validation[self::MAX_ITEMS] = $maxItems;
58+
59+
$cp->validation = $validation;
60+
61+
return $cp;
62+
}
63+
64+
public function withMinItems(int $minItems): self
65+
{
66+
$cp = clone $this;
67+
68+
$validation = (array) $this->validation;
69+
70+
$validation[self::MIN_ITEMS] = $minItems;
71+
72+
$cp->validation = $validation;
73+
74+
return $cp;
75+
}
76+
77+
public function withUniqueItems(): self
78+
{
79+
$cp = clone $this;
80+
81+
$validation = (array) $this->validation;
82+
83+
$validation[self::UNIQUE_ITEMS] = true;
84+
85+
$cp->validation = $validation;
86+
87+
return $cp;
88+
}
89+
90+
public function withContains(TypeSchema $itemSchema): self
91+
{
92+
$cp = clone $this;
93+
94+
$validation = (array) $this->validation;
95+
96+
$validation[self::CONTAINS] = $itemSchema->toArray();
97+
98+
$cp->validation = $validation;
99+
100+
return $cp;
101+
}
102+
45103
public function toArray(): array
46104
{
47105
return \array_merge([

src/Type/BoolType.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ final class BoolType implements AnnotatedType
1919
use NullableType,
2020
HasAnnotations;
2121

22+
public const CONST = 'const';
23+
2224
/**
2325
* @var string|array
2426
*/

src/Type/FloatType.php

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ class FloatType implements AnnotatedType
1919
use NullableType,
2020
HasAnnotations;
2121

22+
public const MINIMUM = 'minimum';
23+
public const MAXIMUM = 'maximum';
24+
public const MULTIPLE_OF = 'multipleOf';
25+
public const EXCLUSIVE_MAXIMUM = 'exclusiveMaximum';
26+
public const EXCLUSIVE_MINIMUM = 'exclusiveMinimum';
27+
public const ENUM = 'enum';
28+
public const CONST = 'const';
29+
2230
/**
2331
* @var string|array
2432
*/
@@ -45,7 +53,20 @@ public function withMinimum(float $min): self
4553

4654
$validation = (array) $this->validation;
4755

48-
$validation['minimum'] = $min;
56+
$validation[self::MINIMUM] = $min;
57+
58+
$cp->validation = $validation;
59+
60+
return $cp;
61+
}
62+
63+
public function withExclusiveMinimum(float $exclusiveMin): self
64+
{
65+
$cp = clone $this;
66+
67+
$validation = (array) $this->validation;
68+
69+
$validation[self::EXCLUSIVE_MINIMUM] = $exclusiveMin;
4970

5071
$cp->validation = $validation;
5172

@@ -58,7 +79,20 @@ public function withMaximum(float $max): self
5879

5980
$validation = (array) $this->validation;
6081

61-
$validation['maximum'] = $max;
82+
$validation[self::MAXIMUM] = $max;
83+
84+
$cp->validation = $validation;
85+
86+
return $cp;
87+
}
88+
89+
public function withExclusiveMaximum(float $exclusiveMax): self
90+
{
91+
$cp = clone $this;
92+
93+
$validation = (array) $this->validation;
94+
95+
$validation[self::EXCLUSIVE_MAXIMUM] = $exclusiveMax;
6296

6397
$cp->validation = $validation;
6498

@@ -71,8 +105,21 @@ public function withRange(float $min, float $max): self
71105

72106
$validation = (array) $this->validation;
73107

74-
$validation['minimum'] = $min;
75-
$validation['maximum'] = $max;
108+
$validation[self::MINIMUM] = $min;
109+
$validation[self::MAXIMUM] = $max;
110+
111+
$cp->validation = $validation;
112+
113+
return $cp;
114+
}
115+
116+
public function withMultipleOf(float $multipleOf): self
117+
{
118+
$cp = clone $this;
119+
120+
$validation = (array) $this->validation;
121+
122+
$validation[self::MULTIPLE_OF] = $multipleOf;
76123

77124
$cp->validation = $validation;
78125

src/Type/IntType.php

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ class IntType implements AnnotatedType
1919
use NullableType,
2020
HasAnnotations;
2121

22+
public const MINIMUM = 'minimum';
23+
public const MAXIMUM = 'maximum';
24+
public const MULTIPLE_OF = 'multipleOf';
25+
public const EXCLUSIVE_MAXIMUM = 'exclusiveMaximum';
26+
public const EXCLUSIVE_MINIMUM = 'exclusiveMinimum';
27+
public const ENUM = 'enum';
28+
public const CONST = 'const';
29+
30+
2231
/**
2332
* @var string|array
2433
*/
@@ -45,7 +54,20 @@ public function withMinimum(int $min): self
4554

4655
$validation = (array) $this->validation;
4756

48-
$validation['minimum'] = $min;
57+
$validation[self::MINIMUM] = $min;
58+
59+
$cp->validation = $validation;
60+
61+
return $cp;
62+
}
63+
64+
public function withExclusiveMinimum(int $exclusiveMin): self
65+
{
66+
$cp = clone $this;
67+
68+
$validation = (array) $this->validation;
69+
70+
$validation[self::EXCLUSIVE_MINIMUM] = $exclusiveMin;
4971

5072
$cp->validation = $validation;
5173

@@ -58,7 +80,20 @@ public function withMaximum(int $max): self
5880

5981
$validation = (array) $this->validation;
6082

61-
$validation['maximum'] = $max;
83+
$validation[self::MAXIMUM] = $max;
84+
85+
$cp->validation = $validation;
86+
87+
return $cp;
88+
}
89+
90+
public function withExclusiveMaximum(int $exclusiveMax): self
91+
{
92+
$cp = clone $this;
93+
94+
$validation = (array) $this->validation;
95+
96+
$validation[self::EXCLUSIVE_MAXIMUM] = $exclusiveMax;
6297

6398
$cp->validation = $validation;
6499

@@ -71,8 +106,21 @@ public function withRange(int $min, int $max): self
71106

72107
$validation = (array) $this->validation;
73108

74-
$validation['minimum'] = $min;
75-
$validation['maximum'] = $max;
109+
$validation[self::MINIMUM] = $min;
110+
$validation[self::MAXIMUM] = $max;
111+
112+
$cp->validation = $validation;
113+
114+
return $cp;
115+
}
116+
117+
public function withMultipleOf(float $multipleOf): self
118+
{
119+
$cp = clone $this;
120+
121+
$validation = (array) $this->validation;
122+
123+
$validation[self::MULTIPLE_OF] = $multipleOf;
76124

77125
$cp->validation = $validation;
78126

src/Type/StringType.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ class StringType implements AnnotatedType
1919
use NullableType,
2020
HasAnnotations;
2121

22+
public const PATTERN = 'pattern';
23+
public const FORMAT = 'format';
24+
public const MIN_LENGTH = 'minLength';
25+
public const MAX_LENGTH = 'maxLength';
26+
public const ENUM = 'enum';
27+
public const CONST = 'const';
28+
29+
2230
private $type = JsonSchema::TYPE_STRING;
2331

2432
/**
@@ -34,15 +42,23 @@ public function __construct(array $validation = null)
3442
public function withMinLength(int $minLength): self
3543
{
3644
$cp = clone $this;
37-
$cp->validation['minLength'] = $minLength;
45+
$cp->validation[self::MIN_LENGTH] = $minLength;
46+
47+
return $cp;
48+
}
49+
50+
public function withMaxLength(int $maxLength): self
51+
{
52+
$cp = clone $this;
53+
$cp->validation[self::MAX_LENGTH] = $maxLength;
3854

3955
return $cp;
4056
}
4157

4258
public function withPattern(string $pattern): self
4359
{
4460
$cp = clone $this;
45-
$cp->validation['pattern'] = $pattern;
61+
$cp->validation[self::PATTERN] = $pattern;
4662

4763
return $cp;
4864
}

tests/JsonSchemaAwareRecordLogicTest.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
namespace EventEngineTest\JsonSchema;
55

66
use EventEngine\JsonSchema\JsonSchema;
7-
use EventEngine\JsonSchema\Type\TypeRef;
87
use EventEngineTest\JsonSchema\Stub\ArrayItemRecord;
98
use EventEngineTest\JsonSchema\Stub\CollectionItemAllowNestedRecord;
109
use EventEngineTest\JsonSchema\Stub\CollectionItemRecord;
@@ -13,6 +12,7 @@
1312
use EventEngineTest\JsonSchema\Stub\NullableScalarPropsRecord;
1413
use EventEngineTest\JsonSchema\Stub\ScalarPropsRecord;
1514
use EventEngineTest\JsonSchema\Stub\VoOptionalPropsRecord;
15+
use EventEngineTest\JsonSchema\Stub\VoProp\UserId;
1616
use EventEngineTest\JsonSchema\Stub\VoPropsRecord;
1717

1818
final class JsonSchemaAwareRecordLogicTest extends BasicTestCase
@@ -100,7 +100,7 @@ public function it_uses_item_schema_from_collection()
100100
$schema = CollectionItemRecord::__schema();
101101

102102
$expected = JsonSchema::object([
103-
'friends' => JsonSchema::array(JsonSchema::typeRef(ScalarPropsRecord::__type()))
103+
'friends' => JsonSchema::array(JsonSchema::typeRef(ScalarPropsRecord::__type()))->withMaxItems(10)
104104
]);
105105

106106
$this->assertEquals($expected->toArray(), $schema->toArray());
@@ -127,10 +127,10 @@ public function it_detects_scalar_types_through_method_analysis_of_vo_classes()
127127
$schema = VoPropsRecord::__schema();
128128

129129
$expected = JsonSchema::object([
130-
'userId' => JsonSchema::string(),
131-
'age' => JsonSchema::integer(),
130+
'userId' => JsonSchema::string()->withPattern(UserId::PATTERN),
131+
'age' => JsonSchema::integer()->withRange(0, 150),
132132
'member' => JsonSchema::boolean(),
133-
'score' => JsonSchema::float()
133+
'score' => JsonSchema::float()->withRange(0.1, 1),
134134
]);
135135

136136
$this->assertEquals($expected->toArray(), $schema->toArray());
@@ -144,11 +144,11 @@ public function it_respects_optional_properties()
144144
$schema = VoOptionalPropsRecord::__schema();
145145

146146
$expected = JsonSchema::object([
147-
'userId' => JsonSchema::string(),
148-
'age' => JsonSchema::integer(),
147+
'userId' => JsonSchema::string()->withPattern(UserId::PATTERN),
148+
'age' => JsonSchema::integer()->withRange(0, 150),
149149
'member' => JsonSchema::boolean(),
150150
], [
151-
'score' => JsonSchema::float()
151+
'score' => JsonSchema::float()->withRange(0.1, 1),
152152
]);
153153

154154
$this->assertEquals($expected->toArray(), $schema->toArray());

0 commit comments

Comments
 (0)