You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The first parameter of the *generateModels* method must be a class implementing the *SchemaProviderInterface*. The provider fetches the JSON schema files and provides them for the generator. The following providers are available:
54
+
55
+
Provider | Description
56
+
--- | ---
57
+
RecursiveDirectoryProvider | Fetches all *.json files from the given source directory. Each file must contain a JSON Schema object definition on the top level
58
+
OpenAPIv3Provider | Fetches all objects defined in the `#/components/schemas section` of an Open API v3 spec file
59
+
60
+
The second parameter must point to an existing and empty directory (you may use the `generateModelDirectory` helper method to create your destination directory). This directory will contain the generated PHP classes after the generator is finished.
53
61
54
62
As an optional parameter you can set up a *GeneratorConfiguration* object to configure your Generator and/or use the method *generateModelDirectory* to generate your model directory (will generate the directory if it doesn't exist; if it exists, all contained files and folders will be removed for a clean generation process):
Copy file name to clipboardExpand all lines: docs/source/gettingStarted.rst
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -32,7 +32,7 @@ RecursiveDirectoryProvider Fetches all *.json files from the given source direc
32
32
OpenAPIv3Provider Fetches all objects defined in the #/components/schemas section of an Open API v3 spec file
33
33
=========================== ===========
34
34
35
-
The second parameter must point to an existing and empty directory. This directory will contain the generated PHP classes after the generator is finished.
35
+
The second parameter must point to an existing and empty directory (you may use the *generateModelDirectory* helper method to create your destination directory). This directory will contain the generated PHP classes after the generator is finished.
36
36
37
37
As an optional parameter you can set up a *GeneratorConfiguration* object to configure your Generator and/or use the method *generateModelDirectory* to generate your model directory (will generate the directory if it doesn't exist; if it exists, all contained files and folders will be removed for a clean generation process):
Copy file name to clipboardExpand all lines: docs/source/nonStandardExtensions/filter.rst
+262-2Lines changed: 262 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -23,6 +23,73 @@ Filters can be either supplied as a string or as a list of filters (multiple fil
23
23
}
24
24
}
25
25
26
+
If the implementation of a filter throws an exception this exception will be caught by the generated model. The model will either throw the exception directly or insert it into the error collection based on your GeneratorConfiguration (compare `collecting errors <../gettingStarted.html#collect-errors-vs-early-return>`__). This behaviour also allows you to hook into the validation process and execute extended validations on the provided property.
27
+
28
+
If multiple filters are applied to a single property they will be executed in the order of their definition inside the JSON Schema.
29
+
30
+
If a list is used filters may include additional option parameters. In this case a single filter must be provided as an object with the key **filter** defining the filter:
31
+
32
+
.. code-block:: json
33
+
34
+
{
35
+
"type": "object",
36
+
"properties": {
37
+
"created": {
38
+
"type": "string",
39
+
"filter": [
40
+
{
41
+
"filter": "dateTime",
42
+
"denyEmptyValue": true
43
+
}
44
+
]
45
+
}
46
+
}
47
+
}
48
+
49
+
Array filter
50
+
------------
51
+
52
+
Filters may be applied to arrays. In this case the filter operates on the whole array.
53
+
54
+
.. code-block:: json
55
+
56
+
{
57
+
"type": "object",
58
+
"properties": {
59
+
"names": {
60
+
"type": "array",
61
+
"filter": "notEmpty",
62
+
"items": {
63
+
"type": "string",
64
+
"filter": "trim"
65
+
}
66
+
}
67
+
}
68
+
}
69
+
70
+
The array filter is executed before the items are processed. Consequently strings which aren't empty at the beginning but are empty after the trim filter is applied to each element won't be filtered out in the example given above.
71
+
72
+
It is not possible to use transforming filters on arrays.
73
+
74
+
Transforming filter
75
+
-------------------
76
+
77
+
.. warning::
78
+
79
+
Read this section carefully and understand it if you want to use filters which transform the type of the property without breaking your bones
80
+
81
+
You may keep it simple and skip this for your first tries and only experiment with non-transforming filters like the trim filter
82
+
83
+
Filters may change the type of the property. For example the builtin filter **dateTime** creates a DateTime object. Consequently further validations like pattern checks for the string property won't be performed.
84
+
85
+
As the required check is executed before the filter a filter may transform a required value into a null value. Be aware when writing custom filters which transform values to not break your validation rules by adding filters to a property.
86
+
87
+
Only one transforming filter per property is allowed. may be positioned anywhere in the filter chain of a single property. If multiple filters are applied and a transforming filter is among them you have to make sure the property types are compatible.
88
+
89
+
If you write a custom transforming filter you must define the return type of your filter function as the implementation uses Reflection methods to determine to which type a value is transformed by a filter.
90
+
91
+
The return type of the transforming filter will be used to define the type of the property inside the generated model (in the example one section above given above the method **getCreated** will return a DateTime object). Additionally the generated model also accepts the transformed type as input type. So **setCreated** will accept a string and a DateTime object. If an already transformed value is provided the filter which transforms the value will **not** be executed. Also all filters which are defined before the transformation will **not** be executed (eg. a trim filter before a dateTime filter will not be executed if a DateTime object is provided).
92
+
26
93
Builtin filter
27
94
--------------
28
95
@@ -62,14 +129,115 @@ Let's have a look how the generated model behaves:
62
129
// the raw model data input is not affected by the filter
63
130
$person->getRawModelDataInput(); // returns ['name' => ' Albert ']
64
131
65
-
// If setters are generated the setters also perform validations.
132
+
// If setters are generated the setters also execute the filter and perform validations.
66
133
// Exception: 'Value for name must not be shorter than 2'
67
134
$person->setName(' D ');
68
135
69
136
If the filter trim is used for a property which doesn't require a string value and a non string value is provided an exception will be thrown:
70
137
71
138
* Filter trim is not compatible with property type __TYPE__ for property __PROPERTY_NAME__
72
139
140
+
notEmpty
141
+
^^^^^^^^
142
+
143
+
The dateTime filter is only valid for array properties.
144
+
145
+
.. code-block:: json
146
+
147
+
{
148
+
"$id": "family",
149
+
"type": "object",
150
+
"properties": {
151
+
"members": {
152
+
"type": "array",
153
+
"filter": "notEmpty"
154
+
}
155
+
}
156
+
}
157
+
158
+
Let's have a look how the generated model behaves:
159
+
160
+
.. code-block:: php
161
+
162
+
// valid, the name will be NULL as the name is not required
163
+
$family = new Person([]);
164
+
165
+
// A valid example
166
+
$family = new Family(['members' => [null, null]]]);
167
+
$family->getMembers(); // returns an empty array
168
+
// the raw model data input is not affected by the filter
// Another valid example with an already transformed value
222
+
$car = new Car(['productionDate' => $myDateTimeObject]);
223
+
224
+
Additional options
225
+
~~~~~~~~~~~~~~~~~~
226
+
227
+
======================= ============= ===========
228
+
Option Default value Description
229
+
======================= ============= ===========
230
+
convertNullToNow false If null is provided a DateTime object with the current time will be created (works only if the property isn't required as null would be denied otherwise before the filter is executed)
231
+
convertEmptyValueToNull false If an empty string is provided and this option is set to true the property will contain null after the filter has been applied
232
+
denyEmptyValue false An empty string value will be denied (by default an empty string value will result in a DateTime object with the current time)
233
+
createFromFormat null Provide a pattern which is used to parse the provided value (DateTime object will be created via DateTime::createFromFormat if a format is provided)
234
+
outputFormat DATE_ISO8601 The output format if serialization is enabled and toArray or toJSON is called on a transformed property. If a createFromFormat is defined but no outputFormat the createFromFormat value will override the default value
235
+
======================= ============= ===========
236
+
237
+
.. hint::
238
+
239
+
If the dateTime filter is used without the createFromFormat option the string will be passed into the DateTime constructor. Consequently also strings like '+1 day' will be converted to the corresponding DateTime objects.
240
+
73
241
Custom filter
74
242
-------------
75
243
@@ -83,7 +251,7 @@ You can implement custom filter and use them in your schema files. You must add
83
251
);
84
252
85
253
Your filter must implement the interface **PHPModelGenerator\\PropertyProcessor\\Filter\\FilterInterface**. Make sure the given callable array returned by **getFilter** is accessible as well during the generation process as during code execution using the generated model.
86
-
The callable filter method must be a static method. Internally it will be called via *call_user_func*. A custom filter may look like:
254
+
The callable filter method must be a static method. Internally it will be called via *call_user_func_array*. A custom filter may look like:
87
255
88
256
.. code-block:: php
89
257
@@ -101,6 +269,8 @@ The callable filter method must be a static method. Internally it will be called
101
269
102
270
public function getAcceptedTypes(): array
103
271
{
272
+
// return an array of types which can be handled by the filter.
@@ -117,6 +287,9 @@ The callable filter method must be a static method. Internally it will be called
117
287
118
288
If the custom filter is added to the generator configuration you can now use the filter in your schema and the generator will resolve the function:
119
289
290
+
.. hint::
291
+
292
+
If a filter with the token of your custom filter already exists the existing filter will be overwritten when adding the filter to the generator configuration. By overwriting filters you may change the behaviour of builtin filters by replacing them with your custom implementation.
120
293
121
294
.. code-block:: json
122
295
@@ -138,3 +311,90 @@ If the custom filter is added to the generator configuration you can now use the
138
311
139
312
$person = new Person(['name' => ' Albert ']);
140
313
$person->getName(); // returns 'ALBERT'
314
+
315
+
Accessing additional filter options
316
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
317
+
318
+
Filters may handle additional configuration options like the builtin dateTime-filter. The options will be passed as an array as the second argument of your filter function. Let's assume you want to add additional options to your uppercase-filter you'd add the options parameter to your static filter implementation:
319
+
320
+
.. code-block:: php
321
+
322
+
public static function uppercase(?string $value, array $options): ?string
323
+
{
324
+
// do something with a custom option
325
+
if ($options['onlyVocals'] ?? false) {
326
+
// uppercase only the vocals of the provided value
327
+
}
328
+
329
+
// ... default implementation
330
+
}
331
+
332
+
The option will be available if your JSON-Schema uses the object-notation for the filter:
333
+
334
+
.. code-block:: json
335
+
336
+
{
337
+
"$id": "person",
338
+
"type": "object",
339
+
"properties": {
340
+
"name": {
341
+
"type": "string",
342
+
"filter": [
343
+
{
344
+
"filter": "uppercase",
345
+
"onlyVocals": true
346
+
},
347
+
"trim"
348
+
]
349
+
}
350
+
}
351
+
}
352
+
353
+
Custom transforming filter
354
+
^^^^^^^^^^^^^^^^^^^^^^^^^^
355
+
356
+
If you want to provide a custom filter which transforms a value (eg. redirect data into a manually written model, transforming between data types [eg. accepting values as an integer but handle them internally as binary strings]) you must implement the **PHPModelGenerator\\PropertyProcessor\\Filter\\TransformingFilterInterface**. This interface adds the **getSerializer** method to your filter. The method is similar to the **getFilter** method. It must return a callable which is available during the render process as well as during code execution. The returned callable must return null or a string and undo a transformation (eg. the serializer method of the builtin **dateTime** filter transforms a DateTime object back into a formatted string). The serializer method will be called with the current value of the property as the first argument and with the (optionally provided) additional options of the filter as the second argument. Your custom transforming filter might look like:
357
+
358
+
.. code-block:: php
359
+
360
+
namespace MyApp\Model\Generator\Filter;
361
+
362
+
use MyApp\Model\ManuallyWrittenModels\Customer;
363
+
use PHPModelGenerator\PropertyProcessor\Filter\TransformingFilterInterface;
364
+
365
+
class CustomerFilter implements TransformingFilterInterface
366
+
{
367
+
// Let's assume you have written a Customer model manually eg. due to advanced validations
368
+
// and you want to use the Customer model as a part of your generated model
369
+
public static function instantiateCustomer(?array $data, array $additionalOptions): ?Customer
370
+
{
371
+
return $data !== null ? new Customer($data, $additionalOptions) : null;
372
+
}
373
+
374
+
// $customer will contain the current value of the property the filter is applied to
375
+
// $additionalOptions will contain all additional options from the JSON Schema
376
+
public static function instantiateCustomer(?Customer $customer, array $additionalOptions): ?string
0 commit comments