Skip to content

Commit d7d27ce

Browse files
committed
Throw an exception on invalid property name
Add documentation for multi types and objects Optimize exception messages for object size validation
1 parent 31cd843 commit d7d27ce

File tree

13 files changed

+357
-25
lines changed

13 files changed

+357
-25
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
Multi Type
2+
==========
3+
4+
By providing an array with types for a property multiple types can be allowed.
5+
6+
.. code-block:: json
7+
8+
{
9+
"$id": "example",
10+
"type": "object",
11+
"properties": {
12+
"example": {
13+
"type": ["number", "string"]
14+
}
15+
}
16+
}
17+
18+
Generated interface (doesn't contain type hints as multiple types are allowed):
19+
20+
.. code-block:: php
21+
22+
public function setExample($example): self;
23+
public function getExample();
24+
25+
Possible exceptions:
26+
27+
* Invalid type for property. Requires [float, string], got __TYPE__
28+
29+
Additional validators
30+
---------------------
31+
32+
For each type given in the allowed types array additional validators may be added to the property:
33+
34+
.. code-block:: json
35+
36+
{
37+
"$id": "example",
38+
"type": "object",
39+
"properties": {
40+
"example": {
41+
"type": ["number", "string", "array"],
42+
"minimum": 10,
43+
"minLength": 4,
44+
"items": {
45+
"type": "string"
46+
},
47+
"minItems": 2
48+
}
49+
}
50+
}
51+
52+
The validators are applied if the given input matches the corresponding type.
53+
For example if an array **["Hello", 123, "Goodbye"]** is given the validation will fail as numbers aren't allowed in arrays:
54+
55+
.. code-block:: none
56+
57+
Invalid item in array example:
58+
- invalid item #1
59+
* Invalid type for item of array example. Requires string, got integer

docs/source/complexTypes/object.rst

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
Object
2+
======
3+
4+
Properties which contain an object will result in an additional PHP class. The PHP classes will be connected via type hinting to provide autocompletion during the development.
5+
6+
.. code-block:: json
7+
8+
{
9+
"$id": "person",
10+
"type": "object",
11+
"properties": {
12+
"name": {
13+
"type": "string"
14+
},
15+
"car": {
16+
"$id": "car",
17+
"type": "object",
18+
"properties": {
19+
"model": {
20+
"type": "string"
21+
},
22+
"ps": {
23+
"type": "integer"
24+
}
25+
}
26+
}
27+
}
28+
}
29+
30+
Generated interface:
31+
32+
.. code-block:: php
33+
34+
// class Person
35+
public function setName(?string $name): self;
36+
public function getName(): ?string;
37+
public function setCar(?Car $name): self;
38+
public function getCar(): ?Car;
39+
40+
// class Car
41+
public function setModel(?string $name): self;
42+
public function getModel(): ?string;
43+
public function setPs(?int $name): self;
44+
public function getPs(): ?int;
45+
46+
Possible exceptions:
47+
48+
* Invalid type for car. Requires object, got __TYPE__
49+
50+
The nested object will be validated in the nested class Car which may throw additional exceptions if invalid data is provided.
51+
52+
Namespaces
53+
----------
54+
55+
If a nested class is generated the nested class will be located in the same namespace as the parent class.
56+
If the nested class occurs somewhere else and has already been generated a class from another namespace may be used (compare `namespaces <../generic/namespaces.html>`__ for additional information concerning class re-usage).
57+
58+
Property Name Normalization
59+
---------------------------
60+
61+
Property names are normalized to provide valid and readable PHP code. All non alpha numeric characters will be removed.
62+
63+
.. code-block:: json
64+
65+
{
66+
"type": "object",
67+
"properties": {
68+
"underscore_property-minus": {
69+
"type": "string"
70+
},
71+
"CAPS and space 100": {
72+
"type": "string"
73+
}
74+
}
75+
}
76+
77+
Generated interface:
78+
79+
.. code-block:: php
80+
81+
public function setUnderscorePropertyMinus(?string $name): self;
82+
public function getUnderscorePropertyMinus(): ?string;
83+
public function setCapsAndSpace100(?string $name): self;
84+
public function getCapsAndSpace100(): ?string;
85+
86+
If the name normalization results in an empty attribute name (eg. '__ -- __') an exception will be thrown.
87+
88+
Required properties
89+
-------------------
90+
91+
Using the keyword `required` a list of properties may be defined which must be provided.
92+
93+
94+
.. code-block:: json
95+
96+
{
97+
"$id": "person",
98+
"type": "object",
99+
"properties": {
100+
"name": {
101+
"type": "string"
102+
},
103+
"age": {
104+
"type": "integer"
105+
}
106+
},
107+
"required": [
108+
"name"
109+
]
110+
}
111+
112+
Possible exceptions:
113+
114+
* Missing required value for name
115+
116+
.. warning::
117+
118+
Properties defined in the `required` array but not defined in the `properties` section of the object aren't validated. Consequently provided objects missing these fields may be considered valid.
119+
120+
Size
121+
----
122+
123+
With the keywords `minProperties` and `maxProperties` the number of allowed properties can be limited:
124+
125+
.. code-block:: json
126+
127+
{
128+
"$id": "person",
129+
"type": "object",
130+
"properties": {
131+
"name": {
132+
"type": "string"
133+
}
134+
},
135+
"minProperties": 2,
136+
"maxProperties": 3
137+
}
138+
139+
Possible exceptions:
140+
141+
* Provided object for person must not contain less than 2 properties
142+
* Provided object for person must not contain more than 3 properties
143+
144+
Additional Properties
145+
---------------------
146+
147+
Using the keyword `additionalProperties` the object can be limited to not contain any additional properties by providing `false`. If a schema is provided all additional properties must be valid against the provided schema. Simple checks like 'must provide a string' are possible as well as checks like 'must contain an object with a specific structure'.
148+
149+
.. code-block:: json
150+
151+
{
152+
"$id": "example",
153+
"type": "object",
154+
"properties": {
155+
"example": {
156+
"type": "integer"
157+
}
158+
},
159+
"additionalProperties": {
160+
"type": "object",
161+
"properties": {
162+
"name": {
163+
"type": "string"
164+
},
165+
"age": {
166+
"type": "integer"
167+
}
168+
}
169+
}
170+
}
171+
172+
Possible exceptions:
173+
174+
* Provided JSON contains not allowed additional properties [additional1, additional2]
175+
176+
If invalid additional properties are provided a detailed exception will be thrown containing all violations:
177+
178+
.. code-block:: none
179+
180+
Provided JSON contains invalid additional properties.
181+
- invalid additional property 'additional1'
182+
* Invalid type for name. Requires string, got integer
183+
- invalid additional property 'additional2'
184+
* Invalid type for age. Requires int, got string
185+
186+
Property Names
187+
--------------
188+
189+
With the keyword `propertyNames` rules can be defined which must be fulfilled by each given property.
190+
191+
.. code-block:: json
192+
193+
{
194+
"type": "object",
195+
"propertyNames": {
196+
"pattern": "^test[0-9]+$",
197+
"maxLength": 8
198+
}
199+
}
200+
201+
Compare `strings <../types/string.html>`__ for information concerning possible property name validators.
202+
203+
Exceptions contain detailed information about the violations:
204+
205+
.. code-block:: none
206+
207+
Provided JSON contains properties with invalid names.
208+
- invalid property 'test12345a'
209+
* Value for property name doesn't match pattern ^test[0-9]+$
210+
* Value for property name must not be longer than 8
211+
- invalid property 'test123456789'
212+
* Value for property name must not be longer than 8
213+
214+
Dependencies
215+
------------
216+
217+
Object dependencies are currently not supported.
218+
219+
Pattern Properties
220+
------------------
221+
222+
Pattern properties are currently not supported.

docs/source/toc-complexTypes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@
22
:caption: Complex Types
33
:maxdepth: 1
44

5+
complexTypes/object
56
complexTypes/array
67
complexTypes/enum
8+
complexTypes/multiType

docs/source/types/string.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,4 @@ Possible exceptions:
7979
Format
8080
------
8181

82-
String formats are currently not supported
82+
String formats are currently not supported.

src/Model/Property/Property.php

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

55
namespace PHPModelGenerator\Model\Property;
66

7+
use PHPModelGenerator\Exception\SchemaException;
78
use PHPModelGenerator\Model\Schema;
89
use PHPModelGenerator\Model\Validator;
910
use PHPModelGenerator\Model\Validator\PropertyValidatorInterface;
@@ -46,6 +47,8 @@ class Property implements PropertyInterface
4647
*
4748
* @param string $name
4849
* @param string $type
50+
*
51+
* @throws SchemaException
4952
*/
5053
public function __construct(string $name, string $type)
5154
{
@@ -217,10 +220,12 @@ public function hasDecorators(): bool
217220
* @param string $name
218221
*
219222
* @return string
223+
*
224+
* @throws SchemaException
220225
*/
221226
protected function processAttributeName(string $name): string
222227
{
223-
$name = preg_replace_callback(
228+
$attributeName = preg_replace_callback(
224229
'/([a-z][a-z0-9]*)([A-Z])/',
225230
function ($matches) {
226231
return "{$matches[1]}-{$matches[2]}";
@@ -232,10 +237,16 @@ function ($matches) {
232237
function ($element) {
233238
return ucfirst(strtolower($element));
234239
},
235-
preg_split('/[^a-z0-9]/i', $name)
240+
preg_split('/[^a-z0-9]/i', $attributeName)
236241
);
237242

238-
return lcfirst(join('', $elements));
243+
$attributeName = lcfirst(join('', $elements));
244+
245+
if (empty($attributeName)) {
246+
throw new SchemaException("Property name '$name' results in an empty attribute name");
247+
}
248+
249+
return $attributeName;
239250
}
240251

241252
/**

src/Model/RenderJob.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ protected function renderClass(GeneratorConfiguration $generatorConfiguration):
121121
: [$generatorConfiguration->getExceptionClass()]
122122
);
123123

124+
// TODO: filter out uses in the same namespace
124125
// filter out non-compound namespaces
125126
$use = array_filter($use, function ($classPath) {
126127
return strstr($classPath, '\\');

0 commit comments

Comments
 (0)