Skip to content

Commit b9935c8

Browse files
committed
split docs for post processors to multiple pages
1 parent 32a7539 commit b9935c8

File tree

11 files changed

+346
-339
lines changed

11 files changed

+346
-339
lines changed

docs/source/complexTypes/enum.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Enums can be used to define a set of constant values a property must accept.
55

66
.. hint::
77

8-
If you define constraints via `enum` you may want to use the `EnumPostProcessor <../generator/postProcessor.html#enumpostprocessor>`__ to generate PHP enums.
8+
If you define constraints via `enum` you may want to use the `EnumPostProcessor <../generator/builtin/enumPostProcessor.html>`__ to generate PHP enums.
99

1010
.. code-block:: json
1111

docs/source/complexTypes/object.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ Using the keyword `additionalProperties` the object can be limited to not contai
208208

209209
.. hint::
210210

211-
If you define constraints via `additionalProperties` you may want to use the `AdditionalPropertiesAccessorPostProcessor <../generator/postProcessor.html#additionalpropertiesaccessorpostprocessor>`__ to access and modify your additional properties.
211+
If you define constraints via `additionalProperties` you may want to use the `AdditionalPropertiesAccessorPostProcessor <../generator/builtin/additionalPropertiesAccessorPostProcessor.html>`__ to access and modify your additional properties.
212212

213213
.. code-block:: json
214214
@@ -520,7 +520,7 @@ Using the keyword `patternProperties` further restrictions for properties matchi
520520

521521
.. hint::
522522

523-
If you define constraints via `patternProperties` you may want to use the `PatternPropertiesAccessorPostProcessor <../generator/postProcessor.html#patternpropertiesaccessorpostprocessor>`__ to access your pattern properties.
523+
If you define constraints via `patternProperties` you may want to use the `PatternPropertiesAccessorPostProcessor <../generator/builtin/patternPropertiesAccessorPostProcessor.html>`__ to access your pattern properties.
524524

525525
.. code-block:: json
526526

docs/source/conf.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@
2020
# -- Project information -----------------------------------------------------
2121

2222
project = u'php-json-schema-model-generator'
23-
copyright = u'2023, Enno Woortmann'
23+
copyright = u'2025, Enno Woortmann'
2424
author = u'Enno Woortmann'
2525

2626
# The short X.Y version
27-
version = u'0.24'
27+
version = u'0.26'
2828
# The full version, including alpha/beta/rc tags
29-
release = u'0.24.0'
29+
release = u'0.26.0'
3030

3131

3232
# -- General configuration ---------------------------------------------------
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
AdditionalPropertiesAccessorPostProcessor
2+
=========================================
3+
4+
.. code-block:: php
5+
6+
$generator = new ModelGenerator();
7+
$generator->addPostProcessor(new AdditionalPropertiesAccessorPostProcessor(true));
8+
9+
The **AdditionalPropertiesAccessorPostProcessor** adds methods to your model to work with `additional properties <../complexTypes/object.html#additional-properties>`__ on your objects. By default the post processor only adds methods to objects from a schema which defines constraints for additional properties. If the first constructor parameter *$addForModelsWithoutAdditionalPropertiesDefinition* is set to true the methods will also be added to objects generated from a schema which doesn't define additional properties constraints. If the *additionalProperties* keyword in a schema is set to false the methods will never be added.
10+
11+
.. note::
12+
13+
If the `deny additional properties setting <../gettingStarted.html#deny-additional-properties>`__ is set to true the setting *$addForModelsWithoutAdditionalPropertiesDefinition* is ignored as all objects which don't define additional properties are restricted to the defined properties
14+
15+
Added methods
16+
~~~~~~~~~~~~~
17+
18+
.. code-block:: json
19+
20+
{
21+
"$id": "example",
22+
"type": "object",
23+
"properties": {
24+
"example": {
25+
"type": "string"
26+
}
27+
},
28+
"additionalProperties": {
29+
"type": "string"
30+
}
31+
}
32+
33+
Generated interface with the **AdditionalPropertiesAccessorPostProcessor**:
34+
35+
.. code-block:: php
36+
37+
public function getRawModelDataInput(): array;
38+
39+
public function setExample(float $example): self;
40+
public function getExample(): float;
41+
42+
public function getAdditionalProperties(): array;
43+
public function getAdditionalProperty(string $property): ?string;
44+
public function setAdditionalProperty(string $property, string $value): self;
45+
public function removeAdditionalProperty(string $property): bool;
46+
47+
.. note::
48+
49+
The methods **setAdditionalProperty** and **removeAdditionalProperty** are only added if the `immutable setting <../gettingStarted.html#immutable-classes>`__ is set to false.
50+
51+
**getAdditionalProperties**: This method returns all additional properties which are currently part of the model as key-value pairs where the key is the property name and the value the current value stored in the model. All other properties which are part of the object (in this case the property *example*) will not be included. In opposite to the *getRawModelDataInput* the values provided via this method are the processed values. This means if the schema provides an object-schema for additional properties an array of object instances will be returned. If the additional properties schema contains `filter <../nonStandardExtensions/filter.html>`__ the filtered (and in case of transforming filter transformed) values will be returned.
52+
53+
**getAdditionalProperty**: Returns the current value of a single additional property. If the requested property doesn't exist null will be returned. Returns as well as *getAdditionalProperties* the processed values.
54+
55+
**setAdditionalProperty**: Adds or updates an additional property. Performs all necessary validations like property names or min and max properties validations. If the additional properties are processed via a transforming filter an already transformed value will be accepted. If a property which is regularly defined in the schema a *RegularPropertyAsAdditionalPropertyException* will be thrown. If the change is valid and performed also the output of *getRawModelDataInput* will be updated.
56+
57+
**removeAdditionalProperty**: Removes an existing additional property from the model. Returns true if the additional property has been removed, false otherwise (if no additional property with the requested key exists). May throw a *MinPropertiesException* if the change would result in an invalid model state. If the change is valid and performed also the output of *getRawModelDataInput* will be updated.
58+
59+
Serialization
60+
~~~~~~~~~~~~~
61+
62+
By default additional properties are only included in the serialized models if the *additionalProperties* field is set to true or contains further restrictions. If the option *$addForModelsWithoutAdditionalPropertiesDefinition* is set to true also additional properties for entities which don't define the *additionalProperties* field will be included in the serialization result. If the **AdditionalPropertiesAccessorPostProcessor** is applied and `serialization <../gettingStarted.html#serialization-methods>`__ is enabled the additional properties will be merged into the serialization result. If the additional properties are processed via a transforming filter each value will be serialized via the serialisation method of the transforming filter.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
EnumPostProcessor
2+
=================
3+
4+
.. warning::
5+
6+
Requires at least PHP 8.1
7+
8+
.. code-block:: php
9+
10+
$generator = new ModelGenerator();
11+
$generator->addPostProcessor(new EnumPostProcessor(__DIR__ . '/generated/enum/', '\\MyApp\\Enum'));
12+
13+
The **EnumPostProcessor** generates a `PHP enum <https://www.php.net/manual/en/language.enumerations.basics.php>`_ for each `enum <../../complexTypes/enum.html>`__ found in the processed schemas.
14+
Enums which contain only integer values or only string values will be rendered into a `backed enum <https://www.php.net/manual/en/language.enumerations.backed.php>`_.
15+
Other enums will provide the following interface similar to the capabilities of a backed enum:
16+
17+
.. code-block:: php
18+
19+
public static function from(mixed $value): self;
20+
public static function tryFrom(mixed $value): ?self;
21+
22+
public function value(): mixed;
23+
24+
Let's have a look at the most simple case of a string-only enum:
25+
26+
.. code-block:: json
27+
28+
{
29+
"$id": "offer",
30+
"type": "object",
31+
"properties": {
32+
"state": {
33+
"enum": ["open", "sold", "cancelled"]
34+
}
35+
}
36+
}
37+
38+
The provided schema will generate the following enum:
39+
40+
.. code-block:: php
41+
42+
enum OfferState: string {
43+
case Open = 'open';
44+
case Sold = 'sold';
45+
case Cancelled = 'cancelled';
46+
}
47+
48+
The type hints and annotations of the generated class will be changed to match the generated enum:
49+
50+
.. code-block:: php
51+
52+
/**
53+
* @param OfferState|string|null $state
54+
*/
55+
public function setState($state): self;
56+
public function getState(): ?OfferState;
57+
58+
Mapping
59+
~~~~~~~
60+
61+
Each enum which is not a string-only enum must provide a mapping in the **enum-map** property, for example an integer-only enum:
62+
63+
.. code-block:: json
64+
65+
{
66+
"$id": "offer",
67+
"type": "object",
68+
"properties": {
69+
"state": {
70+
"enum": [0, 1, 2],
71+
"enum-map": {
72+
"open": 0,
73+
"sold": 1,
74+
"cancelled": 2
75+
}
76+
}
77+
}
78+
}
79+
80+
The provided schema will generate the following enum:
81+
82+
.. code-block:: php
83+
84+
enum OfferState: int {
85+
case Open = 0;
86+
case Sold = 1;
87+
case Cancelled = 2;
88+
}
89+
90+
If an enum which requires a mapping is found but no mapping is provided a **SchemaException** will be thrown.
91+
92+
.. note::
93+
94+
By enabling the *$skipNonMappedEnums* option of the **EnumPostProcessor** you can skip enums which require a mapping but don't provide a mapping. Those enums will provide the default `enum <../complexTypes/enum.html>`__ behaviour.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
PatternPropertiesAccessorPostProcessor
2+
======================================
3+
4+
.. code-block:: php
5+
6+
$generator = new ModelGenerator();
7+
$generator->addPostProcessor(new PatternPropertiesAccessorPostProcessor());
8+
9+
The **PatternPropertiesAccessorPostProcessor** adds methods to your model to work with `pattern properties <../complexTypes/object.html#pattern-properties>`__ on your objects. The methods will only be added if the schema for the object defines pattern properties.
10+
11+
Added methods
12+
~~~~~~~~~~~~~
13+
14+
.. code-block:: json
15+
16+
{
17+
"$id": "example",
18+
"type": "object",
19+
"properties": {
20+
"example": {
21+
"type": "string"
22+
}
23+
},
24+
"patternProperties": {
25+
"^a": {
26+
"type": "string"
27+
},
28+
"^b": {
29+
"key": "numbers"
30+
"type": "integer"
31+
},
32+
}
33+
}
34+
35+
Generated interface with the **PatternPropertiesAccessorPostProcessor**:
36+
37+
.. code-block:: php
38+
39+
public function getRawModelDataInput(): array;
40+
41+
public function setExample(float $example): self;
42+
public function getExample(): float;
43+
44+
public function getPatternProperties(string $key): array;
45+
46+
The added method **getPatternProperties** can be used to fetch a list of all properties matching the given pattern. As *$key* you have to provide the pattern you want to fetch. Alternatively you can define a key in your schema and use the key to fetch the properties.
47+
48+
.. code-block:: php
49+
50+
$myObject = new Example('a1' => 'Hello', 'b1' => 100);
51+
52+
// fetches all properties matching the pattern '^a', consequently will return ['a1' => 'Hello']
53+
$myObject->getPatternProperties('^a');
54+
55+
// fetches all properties matching the pattern '^b' (which has a defined key), consequently will return ['b1' => 100]
56+
$myObject->getPatternProperties('numbers');
57+
58+
.. note::
59+
60+
If you want to modify your object by adding or removing pattern properties after the object instantiation you can use the `AdditionalPropertiesAccessorPostProcessor <additionalPropertiesAccessorPostProcessor.html>`__ or the `PopulatePostProcessor <populatePostProcessor.html>`__
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
PopulatePostProcessor
2+
=====================
3+
4+
.. code-block:: php
5+
6+
$generator = new ModelGenerator();
7+
$generator->addPostProcessor(new PopulatePostProcessor());
8+
9+
The **PopulatePostProcessor** adds a populate method to your generated model. The populate method accepts an array which might contain any subset of the model's properties. All properties present in the provided array will be validated according to the validation rules from the JSON-Schema. If all values are valid the properties will be updated otherwise an exception will be thrown (if error collection is enabled an exception containing all violations, otherwise on the first occurring error, compare `collecting errors <../gettingStarted.html#collect-errors-vs-early-return>`__). Also basic model constraints like `minProperties`, `maxProperties` or `propertyNames` will be validated as the provided array may add additional properties to the model. If the model is updated also the values which can be fetched via `getRawModelDataInput` will be updated.
10+
11+
.. code-block:: json
12+
13+
{
14+
"$id": "example",
15+
"type": "object",
16+
"properties": {
17+
"example": {
18+
"type": "string"
19+
}
20+
}
21+
}
22+
23+
Generated interface with the **PopulatePostProcessor**:
24+
25+
.. code-block:: php
26+
27+
public function getRawModelDataInput(): array;
28+
29+
public function setExample(float $example): self;
30+
public function getExample(): float;
31+
32+
public function populate(array $modelData): self;
33+
34+
Now let's have a look at the behaviour of the generated model:
35+
36+
.. code-block:: php
37+
38+
// initialize the model with a valid value
39+
$example = new Example(['value' => 'Hello World']);
40+
$example->getRawModelDataInput(); // returns ['value' => 'Hello World']
41+
42+
// add an additional property to the model.
43+
// if additional property constraints are defined in your JSON-Schema
44+
// each additional property will be validated against the defined constraints.
45+
$example->populate(['additionalValue' => 12]);
46+
$example->getRawModelDataInput(); // returns ['value' => 'Hello World', 'additionalValue' => 12]
47+
48+
// update an existing property with a valid value
49+
$example->populate(['value' => 'Good night!']);
50+
$example->getRawModelDataInput(); // returns ['value' => 'Good night!', 'additionalValue' => 12]
51+
52+
// update an existing property with an invalid value which will throw an exception
53+
try {
54+
$example->populate(['value' => false]);
55+
} catch (Exception $e) {
56+
// perform error handling
57+
}
58+
// if the update of the model fails no values will be updated
59+
$example->getRawModelDataInput(); // returns ['value' => 'Good night!', 'additionalValue' => 12]
60+
61+
.. warning::
62+
63+
If the **PopulatePostProcessor** is added to your model generator the populate method will be added to the model independently of the `immutable setting <../gettingStarted.html#immutable-classes>`__.
64+
65+
The **PopulatePostProcessor** will also resolve all hooks which are applied to setters. Added code will be executed for all properties changed by a populate call. Schema hooks which implement the **SetterAfterValidationHookInterface** will only be executed if all provided properties pass the validation.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
Custom Post Processors
2+
======================
3+
4+
You can implement custom post processors to accomplish your tasks. Each post processor must extend the class **PHPModelGenerator\\SchemaProcessor\\PostProcessor\\PostProcessor**. If you have implemented a post processor add the post processor to your `ModelGenerator` and the post processor will be executed for each class.
5+
6+
A custom post processor which adds a custom trait to the generated model (eg. a trait adding methods for an active record pattern implementation) may look like:
7+
8+
.. code-block:: php
9+
10+
namespace MyApp\Model\Generator\PostProcessor;
11+
12+
use MyApp\Model\ActiveRecordTrait;
13+
use PHPModelGenerator\SchemaProcessor\PostProcessor\PostProcessor;
14+
15+
class ActiveRecordPostProcessor extends PostProcessor
16+
{
17+
public function process(Schema $schema, GeneratorConfiguration $generatorConfiguration): void
18+
{
19+
$schema->addTrait(ActiveRecordTrait::class);
20+
}
21+
}
22+
23+
.. hint::
24+
25+
For examples how to implement a custom post processor have a look at the built in post processors located at **src/SchemaProcessor/PostProcessor/**
26+
27+
What can you do inside your custom post processor?
28+
29+
* Add additional traits and interfaces to your models
30+
* Add additional methods and properties to your models
31+
* Hook via **SchemaHooks** into the generated source code and add your snippets at defined places inside the model:
32+
33+
* Implement the **ConstructorBeforeValidationHookInterface** to add code to the beginning of your constructor
34+
* Implement the **ConstructorAfterValidationHookInterface** to add code to the end of your constructor
35+
* Implement the **GetterHookInterface** to add code to your getter methods
36+
* Implement the **SetterBeforeValidationHookInterface** to add code to the beginning of your setter methods
37+
* Implement the **SetterAfterValidationHookInterface** to add code to the end of your setter methods
38+
* Implement the **SerializationHookInterface** to add code to the end of your serialization process
39+
40+
.. warning::
41+
42+
If a setter for a property is called with the same value which is already stored internally (consequently no update of the property is required), the setters will return directly and as a result of that the setter hooks will not be executed.
43+
44+
This behaviour also applies also to properties changed via the *populate* method added by the `PopulatePostProcessor <#populatepostprocessor>`__ and the *setAdditionalProperty* method added by the `AdditionalPropertiesAccessorPostProcessor <#additionalpropertiesaccessorpostprocessor>`__
45+
46+
To execute code before/after the processing of the schemas override the methods **preProcess** and **postProcess** inside your custom post processor.

0 commit comments

Comments
 (0)