Skip to content

Commit 6547053

Browse files
authored
Merge pull request #16 from wol-soft/PostProcessor
Merge Post Processor implementation
2 parents f87b9b4 + ef2314a commit 6547053

File tree

71 files changed

+1409
-487
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+1409
-487
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
Post Processor
2+
==============
3+
4+
Post processors provide an easy way to extend your generated code. A post processor can be added to your `ModelGenerator` object:
5+
6+
.. code-block:: php
7+
8+
$generator = new ModelGenerator();
9+
$generator->addPostProcessor(new PopulatePostProcessor());
10+
11+
$files = $generator->generateModelDirectory(__DIR__ . '/result')
12+
->generateModels(new RecursiveDirectoryProvider(__DIR__ . '/schema'), __DIR__ . '/result');
13+
14+
All added post processors will be executed after a schema was processed and before a model is rendered. Consequently a post processor can be used to change the generated class or to extend the class. Also additional tasks which don't change the rendered code may be executed (eg. create a documentation file for the class, create SQL create statements for tables representing the class, ...).
15+
16+
Builtin Post Processors
17+
-----------------------
18+
19+
PopulatePostProcessor
20+
^^^^^^^^^^^^^^^^^^^^^
21+
22+
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.
23+
24+
.. code-block:: json
25+
26+
{
27+
"$id": "example",
28+
"type": "object",
29+
"properties": {
30+
"value": {
31+
"type": "string"
32+
}
33+
}
34+
}
35+
36+
Generated interface with the **PopulatePostProcessor**:
37+
38+
.. code-block:: php
39+
40+
public function getRawModelDataInput(): array;
41+
public function populate(array $modelData): self;
42+
43+
public function setExample(float $example): self;
44+
public function getExample(): float;
45+
46+
Now let's have a look at the behaviour of the generated model:
47+
48+
.. code-block:: php
49+
50+
// initialize the model with a valid value
51+
$example = new Example(['value' => 'Hello World']);
52+
$example->getRawModelDataInput(); // returns ['value' => 'Hello World']
53+
54+
// add an additional property to the model.
55+
// if additional property constraints are defined in your JSON-Schema
56+
// each additional property will be validated against the defined constraints.
57+
$example->populate(['additionalValue' => 12]);
58+
$example->getRawModelDataInput(); // returns ['value' => 'Hello World', 'additionalValue' => 12]
59+
60+
// update an existing property with a valid value
61+
$example->populate(['value' => 'Good night!']);
62+
$example->getRawModelDataInput(); // returns ['value' => 'Good night!', 'additionalValue' => 12]
63+
64+
// update an existing property with an invalid value which will throw an exception
65+
try {
66+
$example->populate(['value' => false]);
67+
} catch (Exception $e) {
68+
// perform error handling
69+
}
70+
// if the update of the model fails no values will be updated
71+
$example->getRawModelDataInput(); // returns ['value' => 'Good night!', 'additionalValue' => 12]
72+
73+
.. warning::
74+
75+
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>`__.
76+
77+
Custom Post Processors
78+
----------------------
79+
80+
You can implement custom post processors to accomplish your tasks. Each post processor must implement the **PHPModelGenerator\\SchemaProcessor\\PostProcessor\\PostProcessorInterface**. If you have implemented a post processor add the post processor to your `ModelGenerator` and the post processor will be executed for each class.
81+
82+
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:
83+
84+
.. code-block:: php
85+
86+
namespace MyApp\Model\Generator\PostProcessor;
87+
88+
use MyApp\Model\ActiveRecordTrait;
89+
use PHPModelGenerator\SchemaProcessor\PostProcessor\PostProcessorInterface;
90+
91+
class ActiveRecordPostProcessor implements PostProcessorInterface
92+
{
93+
public function process(Schema $schema, GeneratorConfiguration $generatorConfiguration): void
94+
{
95+
$schema->addTrait(ActiveRecordTrait::class);
96+
}
97+
}
98+
99+
.. hint::
100+
101+
For examples how to implement a custom post processor have a look at the built in post processors located at **src/SchemaProcessor/PostProcessor/**

docs/source/gettingStarted.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,3 +280,8 @@ Custom filter
280280
addFilter(FilterInterface $customFilter);
281281
282282
Add a custom filter to the generator. For more details see `Filter <nonStandardExtensions/filter.html>`__.
283+
284+
Post Processors
285+
---------------
286+
287+
Additionally to the described generator configuration options you can add post processors to your model generator object to change or extend the generated code. For more details see `post processors <generator/postProcessor.html>`__.

docs/source/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ Generates PHP model classes from JSON-Schema files including validation and prov
1212
.. include:: toc-types.rst
1313
.. include:: toc-complexTypes.rst
1414
.. include:: toc-combinedSchemas.rst
15+
.. include:: toc-generator.rst
1516
.. include:: toc-nonStandardExtensions.rst

docs/source/toc-generator.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.. toctree::
2+
:caption: Extending the generator
3+
:maxdepth: 1
4+
5+
generator/postProcessor

src/Model/GeneratorConfiguration.php

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
use PHPModelGenerator\Utils\ClassNameGenerator;
1414
use PHPModelGenerator\Utils\ClassNameGeneratorInterface;
1515
use PHPModelGenerator\Exception\ErrorRegistryException;
16-
use PHPModelGenerator\Exception\ValidationException;
1716

1817
/**
1918
* Class GeneratorConfiguration
@@ -67,22 +66,13 @@ public function __construct()
6766
*/
6867
public function addFilter(FilterInterface $filter): self
6968
{
70-
if (!(count($filter->getFilter()) === 2) ||
71-
!is_string($filter->getFilter()[0]) ||
72-
!is_string($filter->getFilter()[1]) ||
73-
!is_callable($filter->getFilter())
74-
) {
75-
throw new InvalidFilterException("Invalid filter callback for filter {$filter->getToken()}");
76-
}
69+
$this->validateFilterCallback($filter->getFilter(), "Invalid filter callback for filter {$filter->getToken()}");
7770

7871
if ($filter instanceof TransformingFilterInterface) {
79-
if (!(count($filter->getSerializer()) === 2) ||
80-
!is_string($filter->getSerializer()[0]) ||
81-
!is_string($filter->getSerializer()[1]) ||
82-
!is_callable($filter->getSerializer())
83-
) {
84-
throw new InvalidFilterException("Invalid serializer callback for filter {$filter->getToken()}");
85-
}
72+
$this->validateFilterCallback(
73+
$filter->getSerializer(),
74+
"Invalid serializer callback for filter {$filter->getToken()}"
75+
);
8676
}
8777

8878
foreach ($filter->getAcceptedTypes() as $acceptedType) {
@@ -98,6 +88,23 @@ public function addFilter(FilterInterface $filter): self
9888
return $this;
9989
}
10090

91+
/**
92+
* @param array $callback
93+
* @param string $message
94+
*
95+
* @throws InvalidFilterException
96+
*/
97+
private function validateFilterCallback(array $callback, string $message): void
98+
{
99+
if (!(count($callback) === 2) ||
100+
!is_string($callback[0]) ||
101+
!is_string($callback[1]) ||
102+
!is_callable($callback)
103+
) {
104+
throw new InvalidFilterException($message);
105+
}
106+
}
107+
101108
/**
102109
* Get a filter by the given token
103110
*

src/Model/MethodInterface.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace PHPModelGenerator\Model;
6+
7+
interface MethodInterface
8+
{
9+
/**
10+
* Returns the code of the method including the function signature
11+
*
12+
* @return string
13+
*/
14+
public function getCode(): string;
15+
}

src/Model/Property/Property.php

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
use PHPModelGenerator\Exception\SchemaException;
88
use PHPModelGenerator\Model\Schema;
9+
use PHPModelGenerator\Model\SchemaDefinition\JsonSchema;
10+
use PHPModelGenerator\Model\SchemaDefinition\JsonSchemaTrait;
911
use PHPModelGenerator\Model\Validator;
1012
use PHPModelGenerator\Model\Validator\PropertyValidatorInterface;
1113
use PHPModelGenerator\PropertyProcessor\Decorator\Property\PropertyDecoratorInterface;
@@ -18,6 +20,8 @@
1820
*/
1921
class Property implements PropertyInterface
2022
{
23+
use JsonSchemaTrait;
24+
2125
/** @var string */
2226
protected $name = '';
2327
/** @var string */
@@ -49,16 +53,19 @@ class Property implements PropertyInterface
4953
*
5054
* @param string $name
5155
* @param string $type
56+
* @param JsonSchema $jsonSchema
5257
* @param string $description
5358
*
5459
* @throws SchemaException
5560
*/
56-
public function __construct(string $name, string $type, string $description = '')
61+
public function __construct(string $name, string $type, JsonSchema $jsonSchema, string $description = '')
5762
{
58-
$this->attribute = $this->processAttributeName($name);
5963
$this->name = $name;
6064
$this->type = $type;
65+
$this->jsonSchema = $jsonSchema;
6166
$this->description = $description;
67+
68+
$this->attribute = $this->processAttributeName($name);
6269
}
6370

6471
/**
@@ -254,7 +261,13 @@ function ($element) {
254261
$attributeName = lcfirst(join('', $elements));
255262

256263
if (empty($attributeName)) {
257-
throw new SchemaException("Property name '$name' results in an empty attribute name");
264+
throw new SchemaException(
265+
sprintf(
266+
"Property name '%s' results in an empty attribute name in file %s",
267+
$name,
268+
$this->jsonSchema->getFile()
269+
)
270+
);
258271
}
259272

260273
return $attributeName;

src/Model/Property/PropertyInterface.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace PHPModelGenerator\Model\Property;
66

77
use PHPModelGenerator\Model\Schema;
8+
use PHPModelGenerator\Model\SchemaDefinition\JsonSchema;
89
use PHPModelGenerator\Model\Validator;
910
use PHPModelGenerator\Model\Validator\PropertyValidatorInterface;
1011
use PHPModelGenerator\PropertyProcessor\Decorator\Property\PropertyDecoratorInterface;
@@ -179,4 +180,11 @@ public function setNestedSchema(Schema $schema);
179180
* @return null|Schema
180181
*/
181182
public function getNestedSchema(): ?Schema;
183+
184+
/**
185+
* Get the JSON schema used to set up the property
186+
*
187+
* @return JsonSchema
188+
*/
189+
public function getJsonSchema(): JsonSchema;
182190
}

src/Model/Property/PropertyProxy.php

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

55
namespace PHPModelGenerator\Model\Property;
66

7+
use PHPModelGenerator\Model\SchemaDefinition\JsonSchema;
78
use PHPModelGenerator\Model\SchemaDefinition\ResolvedDefinitionsCollection;
89
use PHPModelGenerator\Model\Schema;
910
use PHPModelGenerator\Model\Validator\PropertyValidatorInterface;
@@ -219,4 +220,12 @@ public function getNestedSchema(): ?Schema
219220
{
220221
return $this->getProperty()->getNestedSchema();
221222
}
223+
224+
/**
225+
* @inheritdoc
226+
*/
227+
public function getJsonSchema(): JsonSchema
228+
{
229+
return $this->getProperty()->getJsonSchema();
230+
}
222231
}

src/Model/Property/Serializer/TransformingFilterSerializer.php

Lines changed: 0 additions & 69 deletions
This file was deleted.

0 commit comments

Comments
 (0)