Skip to content

Commit ff3f49f

Browse files
authored
Merge pull request #36 from wol-soft/PatternProperties
Pattern Properties
2 parents 86d18d2 + 3b84ebe commit ff3f49f

File tree

66 files changed

+2252
-390
lines changed

Some content is hidden

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

66 files changed

+2252
-390
lines changed

.coveralls.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
service_name: travis-ci
1+
service_name: github-actions
22
coverage_clover: build/logs/clover.xml
33
json_path: build/logs/coveralls-upload.json

.github/workflows/main.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: CI
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
tests:
7+
runs-on: ubuntu-latest
8+
strategy:
9+
matrix:
10+
php: ['7.2', '7.3', '7.4', '8.0']
11+
12+
name: PHP ${{ matrix.php }} tests
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v2
16+
17+
- name: Setup PHP
18+
uses: shivammathur/setup-php@v2
19+
with:
20+
php-version: ${{ matrix.php }}
21+
extensions: mbstring, json
22+
coverage: xdebug
23+
24+
- name: Install dependencies
25+
run: composer install
26+
27+
- name: Prepare codeclimate test reporter
28+
if: ${{ matrix.php == '8.0' }}
29+
run: |
30+
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
31+
chmod +x ./cc-test-reporter
32+
./cc-test-reporter before-build
33+
34+
- name: Execute tests
35+
run: XDEBUG_MODE=coverage ./vendor/bin/phpunit --coverage-clover=build/logs/clover.xml --testdox
36+
37+
- name: Upload the reports to coveralls.io
38+
if: ${{ matrix.php == '8.0' }}
39+
run: |
40+
composer global require php-coveralls/php-coveralls
41+
php-coveralls -v
42+
env:
43+
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
44+
45+
- name: Upload the reports to codeclimate
46+
if: ${{ matrix.php == '8.0' }}
47+
run: sudo ./cc-test-reporter after-build -r $CC_TEST_REPORTER_ID
48+
env:
49+
CC_TEST_REPORTER_ID: 5e32818628fac9eb11d34e2b35289f88169610cc4a98c6f170c74923342284f1

.travis.yml

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

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ The class generation process basically splits up into three to four steps:
160160

161161
- Scan the given source directory to find all *.json files which should be processed.
162162
- Loop over all schemas which should be generated. This is the main step of the class generation. Now each schema is parsed and a Schema model class which holds the properties for the generated model is populated. All validation rules defined in the JSON-Schema are translated into plain PHP code. After the model is finished a RenderJob is generated and added to the RenderQueue. If a JSON-Schema contains nested objects or references multiple RenderJobs may be added to the RenderQueue for a given schema file.
163+
- If post processors are defined for the generation process the post processors will be applied.
163164
- After all schema files have been parsed without an error the RenderQueue will be worked off. All previous added RenderJobs will be executed and the PHP classes will be saved to the filesystem at the given destination directory.
164-
- If pretty printing is enabled the generated PHP classes will be cleaned up for a better code formatting. Done.
165165

166166
## Tests ##
167167

composer.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
}
1212
],
1313
"require": {
14-
"wol-soft/php-json-schema-model-generator-production": "^0.16.0",
14+
"wol-soft/php-json-schema-model-generator-production": "dev-PatternProperties",
1515
"wol-soft/php-micro-template": "^1.3.2",
1616

1717
"php": ">=7.2",
@@ -21,9 +21,6 @@
2121
"require-dev": {
2222
"phpunit/phpunit": "^8.5 || ^9.4"
2323
},
24-
"suggest": {
25-
"symplify/easy-coding-standard": "Allows pretty printing of the generated code"
26-
},
2724
"autoload": {
2825
"psr-4": {
2926
"PHPModelGenerator\\": "src"

docs/source/complexTypes/object.rst

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,4 +514,48 @@ Multiple violations against the schema dependency may be included.
514514
Pattern Properties
515515
------------------
516516

517-
Pattern properties are currently not supported.
517+
Using the keyword `patternProperties` further restrictions for properties matching a pattern can be defined.
518+
519+
.. hint::
520+
521+
If you define constraints via `patternProperties` you may want to use the `PatternPropertiesAccessorPostProcessor <../generator/postProcessor.html#patternpropertiesaccessorpostprocessor>`__ to access your pattern properties.
522+
523+
.. code-block:: json
524+
525+
{
526+
"$id": "example",
527+
"type": "object",
528+
"properties": {
529+
"example": {
530+
"type": "integer"
531+
}
532+
},
533+
"patternProperties": {
534+
"^a": {
535+
"type": "string"
536+
}
537+
}
538+
}
539+
540+
Possible exceptions:
541+
542+
If invalid pattern properties are provided a detailed exception will be thrown containing all violations:
543+
544+
.. code-block:: none
545+
546+
Provided JSON for Example contains invalid pattern properties.
547+
- invalid property 'a0' matching pattern '\^a'
548+
* Invalid type for pattern property. Requires string, got integer
549+
550+
The thrown exception will be a *PHPModelGenerator\\Exception\\Object\\InvalidPatternPropertiesException* which provides the following methods to get further error details:
551+
552+
.. code-block:: php
553+
554+
// returns a two-dimensional array which contains all validation exceptions grouped by property names
555+
public function getNestedExceptions(): array
556+
// get the pattern which lead to the error
557+
public function getPattern(): string
558+
// get the name of the property which failed
559+
public function getPropertyName(): string
560+
// get the value provided to the property
561+
public function getProvidedValue()

docs/source/examples.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@ The Ebay OpenAPIv3 spec for the sell-inventory API is an around 6000 lines API d
2525
->generateModelDirectory($resultDir)
2626
->generateModels(new OpenAPIv3Provider($file), $resultDir);
2727
28-
Measured runtime of the script (Pretty printing is disabled) is around 3 seconds at a memory peak consumption between 5 and 6 MB.
28+
Measured runtime of the script is around 3 seconds at a memory peak consumption between 5 and 6 MB.

docs/source/generator/postProcessor.rst

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,75 @@ Generated interface with the **AdditionalPropertiesAccessorPostProcessor**:
136136

137137
**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.
138138

139-
**setAdditionalProperty**: Adds or updates an additional property. Performs all necessary validations like property names or min and max properties validations will be performed. 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.
139+
**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.
140140

141141
**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.
142142

143143
Serialization
144144
~~~~~~~~~~~~~
145145

146-
By default additional properties are not included in serialized models. 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.
146+
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.
147+
148+
PatternPropertiesAccessorPostProcessor
149+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
150+
151+
.. code-block:: php
152+
153+
$generator = new ModelGenerator();
154+
$generator->addPostProcessor(new PatternPropertiesAccessorPostProcessor());
155+
156+
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.
157+
158+
Added methods
159+
~~~~~~~~~~~~~
160+
161+
.. code-block:: json
162+
163+
{
164+
"$id": "example",
165+
"type": "object",
166+
"properties": {
167+
"example": {
168+
"type": "string"
169+
}
170+
},
171+
"patternProperties": {
172+
"^a": {
173+
"type": "string"
174+
},
175+
"^b": {
176+
"key": "numbers"
177+
"type": "integer"
178+
},
179+
}
180+
}
181+
182+
Generated interface with the **AdditionalPropertiesAccessorPostProcessor**:
183+
184+
.. code-block:: php
185+
186+
public function getRawModelDataInput(): array;
187+
188+
public function setExample(float $example): self;
189+
public function getExample(): float;
190+
191+
public function getPatternProperties(string $key): array;
192+
193+
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.
194+
195+
.. code-block:: php
196+
197+
$myObject = new Example('a1' => 'Hello', 'b1' => 100);
198+
199+
// fetches all properties matching the pattern '^a', consequently will return ['a1' => 'Hello']
200+
$myObject->getPatternProperties('^a');
201+
202+
// fetches all properties matching the pattern '^b' (which has a defined key), consequently will return ['b1' => 100]
203+
$myObject->getPatternProperties('numbers');
204+
205+
.. note::
206+
207+
If you want to add or remove pattern properties to your object after the object instantiation you can use the `AdditionalPropertiesAccessorPostProcessor <generator/postProcessor.html#additionalpropertiesaccessorpostprocessor>`__ or the `PopulatePostProcessor <generator/postProcessor.html#populatepostprocessor>`__
147208

148209
Custom Post Processors
149210
----------------------

docs/source/gettingStarted.rst

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ The recommended way to install php-json-model-generator is through `Composer <ht
1111
composer require --dev wol-soft/php-json-schema-model-generator
1212
composer require wol-soft/php-json-schema-model-generator-production
1313
14-
To avoid adding all dependencies of the php-json-model-generator to your production dependencies it's recommended to add the library as a dev-dependency and include the php-json-model-generator-exception library. The exception library provides all classes to run the generated code. Generating the classes should either be a step done in the development environment or as a build step of your application (which is the recommended workflow).
14+
To avoid adding all dependencies of the php-json-model-generator to your production dependencies it's recommended to add the library as a dev-dependency and include the php-json-model-generator-production library. The production library provides all classes to run the generated code. Generating the classes should either be a step done in the development environment or as a build step of your application (which is the recommended workflow).
1515

1616
Generating classes
1717
------------------
@@ -254,24 +254,6 @@ If you want to customize the exception handling you can set an own ErrorRegistry
254254
(new GeneratorConfiguration())
255255
->setErrorRegistryClass(MyCustomException::class);
256256
257-
Code style of the generated classes
258-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
259-
260-
.. code-block:: php
261-
262-
setPrettyPrint(bool $prettyPrint);
263-
264-
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.
265-
266-
.. code-block:: php
267-
268-
(new GeneratorConfiguration())
269-
->setPrettyPrint(true);
270-
271-
.. warning::
272-
273-
The ECS package must be installed manually: `composer require --dev symplify/easy-coding-standard`
274-
275257
Serialization methods
276258
^^^^^^^^^^^^^^^^^^^^^
277259

src/Model/GeneratorConfiguration.php

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
use PHPModelGenerator\Exception\InvalidFilterException;
88
use PHPModelGenerator\Filter\FilterInterface;
99
use PHPModelGenerator\Filter\TransformingFilterInterface;
10-
use PHPModelGenerator\Format\FormatValidatorFromRegEx;
1110
use PHPModelGenerator\Format\FormatValidatorInterface;
1211
use PHPModelGenerator\PropertyProcessor\Filter\DateTimeFilter;
1312
use PHPModelGenerator\PropertyProcessor\Filter\NotEmptyFilter;
@@ -34,8 +33,6 @@ class GeneratorConfiguration
3433
/** @var bool */
3534
protected $denyAdditionalProperties = false;
3635
/** @var bool */
37-
protected $prettyPrint = false;
38-
/** @var bool */
3936
protected $outputEnabled = true;
4037
/** @var bool */
4138
protected $collectErrors = true;
@@ -76,7 +73,10 @@ public function __construct()
7673
public function addFilter(FilterInterface ...$additionalFilter): self
7774
{
7875
foreach ($additionalFilter as $filter) {
79-
$this->validateFilterCallback($filter->getFilter(), "Invalid filter callback for filter {$filter->getToken()}");
76+
$this->validateFilterCallback(
77+
$filter->getFilter(),
78+
"Invalid filter callback for filter {$filter->getToken()}"
79+
);
8080

8181
if ($filter instanceof TransformingFilterInterface) {
8282
$this->validateFilterCallback(
@@ -253,26 +253,6 @@ public function setDenyAdditionalProperties(bool $denyAdditionalProperties): sel
253253
return $this;
254254
}
255255

256-
/**
257-
* @return bool
258-
*/
259-
public function hasPrettyPrintEnabled(): bool
260-
{
261-
return $this->prettyPrint;
262-
}
263-
264-
/**
265-
* @param bool $prettyPrint
266-
*
267-
* @return $this
268-
*/
269-
public function setPrettyPrint(bool $prettyPrint): self
270-
{
271-
$this->prettyPrint = $prettyPrint;
272-
273-
return $this;
274-
}
275-
276256
/**
277257
* @return bool
278258
*/

src/Model/Validator/AdditionalPropertiesValidator.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,17 @@ public function __construct(
6161
$propertiesStructure->withJson($propertiesStructure->getJson()[static::ADDITIONAL_PROPERTIES_KEY])
6262
);
6363

64+
$patternProperties = array_keys($schema->getJsonSchema()->getJson()['patternProperties'] ?? []);
65+
6466
parent::__construct(
6567
new Property($propertyName ?? $schema->getClassName(), null, $propertiesStructure),
6668
DIRECTORY_SEPARATOR . 'Validator' . DIRECTORY_SEPARATOR . 'AdditionalProperties.phptpl',
6769
[
6870
'validationProperty' => $this->validationProperty,
69-
'additionalProperties' => preg_replace(
70-
'(\d+\s=>)',
71-
'',
72-
var_export(array_keys($propertiesStructure->getJson()[static::PROPERTIES_KEY] ?? []), true)
71+
'additionalProperties' => RenderHelper::varExportArray(
72+
array_keys($propertiesStructure->getJson()[static::PROPERTIES_KEY] ?? [])
7373
),
74+
'patternProperties' => $patternProperties ? RenderHelper::varExportArray($patternProperties) : null,
7475
'generatorConfiguration' => $schemaProcessor->getGeneratorConfiguration(),
7576
'viewHelper' => new RenderHelper($schemaProcessor->getGeneratorConfiguration()),
7677
// by default don't collect additional property data

src/Model/Validator/EnumValidator.php

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

77
use PHPModelGenerator\Exception\Generic\EnumException;
88
use PHPModelGenerator\Model\Property\PropertyInterface;
9+
use PHPModelGenerator\Utils\RenderHelper;
910

1011
/**
1112
* Class EnumValidator
@@ -25,9 +26,7 @@ public function __construct(PropertyInterface $property, array $allowedValues)
2526

2627
parent::__construct(
2728
$property,
28-
'!in_array($value, ' .
29-
preg_replace('(\d+\s=>)', '', var_export($allowedValues, true)) .
30-
', true)',
29+
'!in_array($value, ' . RenderHelper::varExportArray($allowedValues) . ', true)',
3130
EnumException::class,
3231
[$allowedValues]
3332
);

0 commit comments

Comments
 (0)