Skip to content

Commit b60feea

Browse files
authored
Merge pull request #21 from wol-soft/CompositionValidationOnMutableObjects
Validation for composition validators in setter methods
2 parents a99d794 + 4886e70 commit b60feea

File tree

56 files changed

+1584
-269
lines changed

Some content is hidden

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

56 files changed

+1584
-269
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ php:
1010
- 7.2
1111
- 7.3
1212
- 7.4
13+
- nightly
1314

1415
install:
1516
# Install coveralls.phar

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ As an optional parameter you can set up a *GeneratorConfiguration* object to con
6565
```php
6666
$generator = new Generator(
6767
(new GeneratorConfiguration())
68-
->setNamespacePrefix('\MyApp\Model')
68+
->setNamespacePrefix('MyApp\Model')
6969
->setImmutable(false)
7070
);
7171

@@ -82,11 +82,11 @@ The *GeneratorConfiguration* object offers the following methods to configure th
8282

8383
Method | Configuration | Default
8484
--- | --- | ---
85-
``` setNamespacePrefix(string $prefix) ``` <br><br>Example:<br> ``` setNamespacePrefix('\MyApp\Model') ``` | Configures a namespace prefix for all generated classes. The namespaces will be extended with the directory structure of the source directory. | Empty string so no namespace prefix will be used
85+
``` setNamespacePrefix(string $prefix) ``` <br><br>Example:<br> ``` setNamespacePrefix('MyApp\Model') ``` | Configures a namespace prefix for all generated classes. The namespaces will be extended with the directory structure of the source directory. | Empty string so no namespace prefix will be used
8686
``` setImmutable(bool $immutable) ``` <br><br>Example:<br> ``` setImmutable(false) ``` | If set to true the generated model classes will be delivered without setter methods for the object properties. | true
8787
``` setImplicitNull(bool $allowImplicitNull) ``` <br><br>Example:<br> ``` setImplicitNull(true) ``` | By setting the implicit null option to true all of your object properties which aren't required will implicitly accept null. | false
8888
``` setCollectErrors(bool $collectErrors) ``` <br><br>Example:<br> ``` setCollectErrors(false) ``` | By default the complete input is validated and in case of failing validations all error messages will be thrown in a single exception. If set to false the first failing validation will throw an exception. | true
89-
``` setPrettyPrint(bool $prettyPrint) ``` <br><br>Example:<br> ``` setPrettyPrint(true) ``` | If set to false, the generated model classes won't follow coding guidelines (but the generation is faster). If enabled the package [Symplify/EasyCodingStandard](https://github.com/Symplify/EasyCodingStandard) will be used to clean up the generated code. By default pretty printing is disabled. | false
89+
``` setPrettyPrint(bool $prettyPrint) ``` <br><br>Example:<br> ``` setPrettyPrint(true) ``` | If set to false, the generated model classes won't follow coding guidelines (but the generation is faster). If enabled the package [Symplify/EasyCodingStandard](https://github.com/Symplify/EasyCodingStandard) will be used to clean up the generated code (the package must be installed manually: `composer require --dev symplify/easy-coding-standard`). By default pretty printing is disabled. | false
9090
``` setSerialization(bool $serialization) ``` <br><br>Example:<br> ``` setSerialization(true) ``` | If set to true the serialization methods `toArray` and `toJSON` will be added to the public interface of the generated classes. | false
9191
``` setOutputEnabled(bool $outputEnabled) ``` <br><br>Example:<br> ``` setOutputEnabled(false) ``` | Enable or disable output of the generation process to STDOUT | true
9292
``` setErrorRegistryClass(string $exceptionClass) ``` <br><br>Example:<br> ``` setErrorRegistryClass(CustomException::class) ``` | Define a custom exception implementing the ErrorRegistryExceptionInterface to be used. The exception will be thrown if a validation fails and error collection is **enabled** | ErrorRegistryException::class

composer.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "wol-soft/php-json-schema-model-generator",
33
"homepage": "https://github.com/wol-soft/php-json-schema-model-generator",
4-
"description": "Creates immutable PHP model classes from JSON-Schema files",
4+
"description": "Creates (immutable) PHP model classes from JSON-Schema files",
55
"type": "library",
66
"license": "MIT",
77
"authors": [
@@ -11,16 +11,18 @@
1111
}
1212
],
1313
"require": {
14-
"symplify/easy-coding-standard": "^7.2.3",
15-
"wol-soft/php-json-schema-model-generator-production": "0.14.0",
14+
"wol-soft/php-json-schema-model-generator-production": "dev-SkipSerializationOfInternalProperties",
1615
"wol-soft/php-micro-template": "^1.3.2",
1716

1817
"php": ">=7.2",
1918
"ext-json": "*",
2019
"ext-mbstring": "*"
2120
},
2221
"require-dev": {
23-
"phpunit/phpunit": "^8.5"
22+
"phpunit/phpunit": "^8.5 || ^9.4"
23+
},
24+
"suggest": {
25+
"symplify/easy-coding-standard": "Allows pretty printing of the generated code"
2426
},
2527
"autoload": {
2628
"psr-4": {

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'2019, Enno Woortmann'
23+
copyright = u'2020, Enno Woortmann'
2424
author = u'Enno Woortmann'
2525

2626
# The short X.Y version
27-
version = u''
27+
version = u'0.19'
2828
# The full version, including alpha/beta/rc tags
29-
release = u'0.6.0'
29+
release = u'0.19.0'
3030

3131

3232
# -- General configuration ---------------------------------------------------

docs/source/examples.rst

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
Examples
2+
========
3+
4+
Ebay OpenAPIv3 spec
5+
-------------------
6+
7+
The Ebay OpenAPIv3 spec for the sell-inventory API is an around 6000 lines API definition. Using a script like the example below you can create ~120 PHP classes to handle requests, responses and all nested objects from the API spec:
8+
9+
.. code-block:: php
10+
11+
$generator = new ModelGenerator((new GeneratorConfiguration())
12+
->setNamespacePrefix('Ebay')
13+
->setImmutable(false)
14+
);
15+
16+
$file = __DIR__ . '/api-definition.json';
17+
$resultDir = __DIR__ . '/result';
18+
19+
file_put_contents(
20+
$file,
21+
file_get_contents('https://developer.ebay.com/api-docs/master/sell/inventory/openapi/3/sell_inventory_v1_oas3.json')
22+
);
23+
24+
$start = microtime(true);
25+
$generator
26+
->generateModelDirectory($resultDir)
27+
->generateModels(new OpenAPIv3Provider($file), $resultDir);
28+
29+
Measured runtime of the script (Pretty printing is disabled) is around 3 seconds at a memory peak consumption between 5 and 6 MB.

docs/source/generator/postProcessor.rst

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,12 @@ Generated interface with the **PopulatePostProcessor**:
4343
.. code-block:: php
4444
4545
public function getRawModelDataInput(): array;
46-
public function populate(array $modelData): self;
4746
4847
public function setExample(float $example): self;
4948
public function getExample(): float;
5049
50+
public function populate(array $modelData): self;
51+
5152
Now let's have a look at the behaviour of the generated model:
5253

5354
.. code-block:: php
@@ -79,7 +80,7 @@ Now let's have a look at the behaviour of the generated model:
7980

8081
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>`__.
8182

82-
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.
83+
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.
8384

8485
AdditionalPropertiesAccessorPostProcessor
8586
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -170,10 +171,16 @@ What can you do inside your custom post processor?
170171

171172
* Add additional traits and interfaces to your models
172173
* Add additional methods and properties to your models
173-
* Hook via SchemaHooks into the generated source code and add your snippets at defined places inside the model:
174+
* Hook via **SchemaHooks** into the generated source code and add your snippets at defined places inside the model:
174175

175176
* Implement the **ConstructorBeforeValidationHookInterface** to add code to the beginning of your constructor
176177
* Implement the **ConstructorAfterValidationHookInterface** to add code to the end of your constructor
177178
* Implement the **GetterHookInterface** to add code to your getter methods
178179
* Implement the **SetterBeforeValidationHookInterface** to add code to the beginning of your setter methods
179180
* Implement the **SetterAfterValidationHookInterface** to add code to the end of your setter methods
181+
182+
.. warning::
183+
184+
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.
185+
186+
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>`__

docs/source/gettingStarted.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ As an optional parameter you can set up a *GeneratorConfiguration* object to con
4040
4141
$generator = new Generator(
4242
(new GeneratorConfiguration())
43-
->setNamespacePrefix('\MyApp\Model')
43+
->setNamespacePrefix('MyApp\Model')
4444
->setImmutable(false)
4545
);
4646
@@ -138,7 +138,7 @@ Further information about the generated namespaces can be found at `Namespaces <
138138
.. code-block:: php
139139
140140
(new GeneratorConfiguration())
141-
->setNamespacePrefix('\MyApp\Model');
141+
->setNamespacePrefix('MyApp\Model');
142142
143143
Immutable classes
144144
^^^^^^^^^^^^^^^^^
@@ -225,6 +225,10 @@ If set to false, the generated model classes won't follow coding guidelines (but
225225
(new GeneratorConfiguration())
226226
->setPrettyPrint(true);
227227
228+
.. warning::
229+
230+
The ECS package must be installed manually: `composer require --dev symplify/easy-coding-standard`
231+
228232
Serialization methods
229233
^^^^^^^^^^^^^^^^^^^^^
230234

docs/source/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Generates PHP model classes from JSON-Schema files including validation and prov
77
:maxdepth: 2
88

99
gettingStarted
10+
examples
1011

1112
.. include:: toc-generic.rst
1213
.. include:: toc-types.rst

phpunit.xml

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
3-
<phpunit backupGlobals="false"
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
backupGlobals="false"
44
backupStaticAttributes="false"
55
colors="true"
66
convertErrorsToExceptions="true"
77
convertWarningsToExceptions="true"
88
convertNoticesToExceptions="true"
99
processIsolation="false"
1010
stopOnFailure="false"
11-
bootstrap="tests/bootstrap.php">
12-
13-
<testsuite name="PHPModelGenerator">
14-
<directory>tests</directory>
15-
<exclude>tests/manual</exclude>
16-
</testsuite>
17-
18-
<filter>
19-
<whitelist>
20-
<directory>src</directory>
21-
</whitelist>
22-
</filter>
23-
</phpunit>
11+
bootstrap="tests/bootstrap.php"
12+
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
13+
>
14+
<coverage>
15+
<include>
16+
<directory>src</directory>
17+
</include>
18+
</coverage>
19+
<testsuite name="PHPModelGenerator">
20+
<directory>tests</directory>
21+
<exclude>tests/manual</exclude>
22+
</testsuite>
23+
</phpunit>

src/Model/Property/Property.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class Property implements PropertyInterface
3434
protected $isPropertyRequired = true;
3535
/** @var bool */
3636
protected $isPropertyReadOnly = false;
37+
/** @var bool */
38+
protected $isPropertyInternal = false;
3739
/** @var string */
3840
protected $description = '';
3941
/** @var mixed */
@@ -81,7 +83,7 @@ public function getName(): string
8183
*/
8284
public function getAttribute(): string
8385
{
84-
return $this->attribute;
86+
return ($this->isInternal() ? '_' : '') . $this->attribute;
8587
}
8688

8789
/**
@@ -343,4 +345,21 @@ public function getNestedSchema(): ?Schema
343345
{
344346
return $this->schema;
345347
}
348+
349+
/**
350+
* @inheritdoc
351+
*/
352+
public function setInternal(bool $isPropertyInternal): PropertyInterface
353+
{
354+
$this->isPropertyInternal = $isPropertyInternal;
355+
return $this;
356+
}
357+
358+
/**
359+
* @inheritdoc
360+
*/
361+
public function isInternal(): bool
362+
{
363+
return $this->isPropertyInternal;
364+
}
346365
}

0 commit comments

Comments
 (0)