Skip to content

Commit 61c9a01

Browse files
committed
Compose properties into a single model providing access to all available properties if one of the composing definitions [allOf, anyOf, oneOf] is used.
Remove SchemaPropertyProcessors and start directly with an object property. If a generation process for an object is started the object is represented by the BaseProcessor. Extend README with a small description how this stuff works (to be extended)
1 parent 8d32091 commit 61c9a01

25 files changed

+348
-279
lines changed

README.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ $generator = new Generator(
3838

3939
$generator->generateModels(__DIR__ . '/schema', __DIR__ . '/result');
4040
```
41+
42+
The generator will check the given source directory recursive and convert all found *.json files to models. All JSON-Schema files inside the source directory must provide a schema of an object.
4143
## Configuring using the GeneratorConfiguration ##
4244

4345
The *GeneratorConfiguration* object offers the following methods to configure the generator in a fluid interface:
@@ -49,10 +51,19 @@ Method | Configuration | Example | Default
4951
``` setPrettyPrint(bool $prettyPrint) ``` | If set to false, the generated model classes won't follow coding gudelines (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. | ``` setPrettyPrint(false) ``` | true
5052
``` setOutputEnabled(bool $prettyPrint) ``` | Enable or disable output of the generation process to STDOUT | ``` setOutputEnabled(false) ``` | true
5153

54+
## How the heck does this work? ##
55+
56+
The class generation process basically splits up into three to four steps:
57+
58+
- Scan the given source directory to find all *.json files which should be processed.
59+
- 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. 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.
60+
- 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.
61+
- If pretty printing is enabled the generated PHP classes will be cleaned up for a better code formatting. Done.
62+
5263
## Tests ##
5364

54-
After installing the dependencies of the library via `composer update` you can execute the tests with `./vendor/bin/phpunit` (Linux) or `vendor\bin\phpunit.bat` (Windows). The test names are optimized for the usage of the `--testdox` output.
65+
After installing the dependencies of the library via `composer update` you can execute the tests with `./vendor/bin/phpunit` (Linux) or `vendor\bin\phpunit.bat` (Windows). The test names are optimized for the usage of the `--testdox` output. Most tests are atomic integration tests which will set up a JSON-Schema file and generate a class from the schema and test the behaviour of the generated class afterwards.
5566

5667
During the execution the tests will create a directory PHPModelGeneratorTest in tmp where JSON-Schema files and PHP classes will be written to.
5768

58-
If a test which creates a PHP class from a JSON-Schema fails the JSON-Schema and the class will be dumped to `./Failed-classes`
69+
If a test which creates a PHP class from a JSON-Schema fails the JSON-Schema and the generated class(es) will be dumped to `./Failed-classes`

src/Model/Property/Property.php

Lines changed: 20 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\Schema;
78
use PHPModelGenerator\Model\Validator;
89
use PHPModelGenerator\Model\Validator\PropertyValidatorInterface;
910
use PHPModelGenerator\PropertyProcessor\Decorator\PropertyDecoratorInterface;
@@ -28,6 +29,8 @@ class Property implements PropertyInterface
2829
protected $validator = [];
2930
/** @var Property[] */
3031
protected $nestedProperties = [];
32+
/** @var Schema */
33+
protected $schema;
3134
/** @var PropertyDecoratorInterface[] */
3235
public $decorators = [];
3336

@@ -232,4 +235,21 @@ public function isRequired(): bool
232235
{
233236
return $this->isPropertyRequired;
234237
}
238+
239+
/**
240+
* @inheritdoc
241+
*/
242+
public function setNestedSchema(Schema $schema): PropertyInterface
243+
{
244+
$this->schema = $schema;
245+
return $this;
246+
}
247+
248+
/**
249+
* @inheritdoc
250+
*/
251+
public function getNestedSchema(): ?Schema
252+
{
253+
return $this->schema;
254+
}
235255
}

src/Model/Property/PropertyInterface.php

Lines changed: 17 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\Schema;
78
use PHPModelGenerator\Model\Validator;
89
use PHPModelGenerator\Model\Validator\PropertyValidatorInterface;
910
use PHPModelGenerator\PropertyProcessor\Decorator\PropertyDecoratorInterface;
@@ -119,4 +120,20 @@ public function setRequired(bool $isPropertyRequired): PropertyInterface;
119120
* @return bool
120121
*/
121122
public function isRequired(): bool;
123+
124+
/**
125+
* Set a nested schema
126+
*
127+
* @param Schema $schema
128+
*
129+
* @return PropertyInterface
130+
*/
131+
public function setNestedSchema(Schema $schema);
132+
133+
/**
134+
* Get a nested schema if a schema was appended to the property
135+
*
136+
* @return null|Schema
137+
*/
138+
public function getNestedSchema(): ?Schema;
122139
}

src/Model/Property/PropertyProxy.php

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

77
use PHPModelGenerator\Model\ResolvedDefinitionsCollection;
8+
use PHPModelGenerator\Model\Schema;
89
use PHPModelGenerator\Model\Validator\PropertyValidatorInterface;
910
use PHPModelGenerator\PropertyProcessor\Decorator\PropertyDecoratorInterface;
1011

@@ -169,4 +170,20 @@ public function isRequired(): bool
169170
{
170171
return $this->getProperty()->isRequired();
171172
}
172-
}
173+
174+
/**
175+
* @inheritdoc
176+
*/
177+
public function setNestedSchema(Schema $schema): PropertyInterface
178+
{
179+
return $this->getProperty()->setNestedSchema($schema);
180+
}
181+
182+
/**
183+
* @inheritdoc
184+
*/
185+
public function getNestedSchema(): ?Schema
186+
{
187+
return $this->getProperty()->getNestedSchema();
188+
}
189+
}

src/Model/Schema.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function __construct(array $parentDefinitions = [])
3333
}
3434

3535
/**
36-
* @return Property[]
36+
* @return PropertyInterface[]
3737
*/
3838
public function getProperties(): array
3939
{
@@ -44,10 +44,16 @@ public function getProperties(): array
4444
* @param PropertyInterface $property
4545
*
4646
* @return $this
47+
*
48+
* @throws SchemaException
4749
*/
4850
public function addProperty(PropertyInterface $property)
4951
{
50-
$this->properties[] = $property;
52+
if (isset($this->properties[$property->getName()])) {
53+
throw new SchemaException("Duplicate object property {$property->getName()}");
54+
}
55+
56+
$this->properties[$property->getName()] = $property;
5157

5258
return $this;
5359
}
@@ -115,7 +121,7 @@ public function getUseList(bool $skipGlobalNamespace): array
115121
public function addDefinition(string $key, SchemaDefinition $definition)
116122
{
117123
if (isset($this->definitions[$key])) {
118-
throw new SchemaException("Duplicate key for schema definition: $key");
124+
return;
119125
}
120126

121127
$this->definitions[$key] = $definition;

src/Model/SchemaDefinition.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ public function resolveReference(
6565
PropertyCollectionProcessor $propertyCollectionProcessor
6666
): PropertyInterface {
6767
$structure = $this->structure;
68+
$originalPath = $path;
69+
6870
while ($segment = array_shift($path)) {
6971
if (!isset($structure[$segment])) {
7072
throw new SchemaException("Unresolved path segment: $segment");
@@ -73,7 +75,7 @@ public function resolveReference(
7375
$structure = $structure[$segment];
7476
}
7577

76-
$key = implode('-', $path);
78+
$key = implode('-', $originalPath);
7779

7880
if (!$this->resolvedPaths->offsetExists($key)) {
7981
// create a dummy entry for the path first. If the path is used recursive the recursive usages will point
@@ -90,7 +92,7 @@ public function resolveReference(
9092
)
9193
);
9294
} catch (PHPModelGeneratorException $exception) {
93-
unset($this->resolvedPaths[$key]);
95+
$this->resolvedPaths->offsetUnset($key);
9496
throw $exception;
9597
}
9698
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
namespace PHPModelGenerator\Model\Validator;
4+
5+
use PHPModelGenerator\Exception\InvalidArgumentException;
6+
use PHPModelGenerator\Model\Property\PropertyInterface;
7+
8+
/**
9+
* Class ComposedPropertyValidator
10+
*
11+
* @package PHPModelGenerator\Model\Validator
12+
*/
13+
class ComposedPropertyValidator extends PropertyTemplateValidator
14+
{
15+
/** @var string */
16+
protected $composedProcessor;
17+
/** @var PropertyInterface[] */
18+
protected $composedProperties;
19+
20+
/**
21+
* ComposedPropertyValidator constructor.
22+
*
23+
* @param PropertyInterface $property
24+
* @param PropertyInterface[] $composedProperties
25+
* @param string $composedProcessor
26+
* @param array $validatorVariables
27+
*/
28+
public function __construct(
29+
PropertyInterface $property,
30+
array $composedProperties,
31+
string $composedProcessor,
32+
array $validatorVariables
33+
) {
34+
parent::__construct(
35+
InvalidArgumentException::class,
36+
"Invalid value for {$property->getName()} declined by composition constraint",
37+
DIRECTORY_SEPARATOR . 'Validator' . DIRECTORY_SEPARATOR . 'ComposedItem.phptpl',
38+
$validatorVariables
39+
);
40+
41+
$this->composedProcessor = $composedProcessor;
42+
$this->composedProperties = $composedProperties;
43+
}
44+
45+
/**
46+
* @return string
47+
*/
48+
public function getComposedProcessor(): string
49+
{
50+
return $this->composedProcessor;
51+
}
52+
53+
/**
54+
* @return PropertyInterface[]
55+
*/
56+
public function getComposedProperties(): array
57+
{
58+
return $this->composedProperties;
59+
}
60+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace PHPModelGenerator\PropertyProcessor\ComposedValue;
4+
5+
/**
6+
* Class AbstractComposedPropertiesProcessor
7+
*
8+
* @package PHPModelGenerator\PropertyProcessor\ComposedValue
9+
*/
10+
abstract class AbstractComposedPropertiesProcessor extends AbstractComposedValueProcessor
11+
{
12+
}

src/PropertyProcessor/ComposedValue/AbstractComposedValueProcessor.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
namespace PHPModelGenerator\PropertyProcessor\ComposedValue;
44

5-
use PHPModelGenerator\Exception\InvalidArgumentException;
65
use PHPModelGenerator\Model\Property\PropertyInterface;
76
use PHPModelGenerator\Model\Validator;
8-
use PHPModelGenerator\Model\Validator\PropertyTemplateValidator;
7+
use PHPModelGenerator\Model\Validator\ComposedPropertyValidator;
98
use PHPModelGenerator\Model\Validator\RequiredPropertyValidator;
109
use PHPModelGenerator\PropertyProcessor\Property\AbstractTypedValueProcessor;
1110
use PHPModelGenerator\PropertyProcessor\PropertyCollectionProcessor;
@@ -28,6 +27,7 @@ protected function generateValidators(PropertyInterface $property, array $proper
2827
$propertyFactory = new PropertyFactory(new PropertyProcessorFactory());
2928

3029
$properties = [];
30+
3131
foreach ($propertyData['composition'] as $compositionElement) {
3232
$compositionProperty = $propertyFactory
3333
->create(
@@ -48,12 +48,13 @@ protected function generateValidators(PropertyInterface $property, array $proper
4848
$availableAmount = count($properties);
4949

5050
$property->addValidator(
51-
new PropertyTemplateValidator(
52-
InvalidArgumentException::class,
53-
"Invalid value for {$property->getName()} declined by composition constraint",
54-
DIRECTORY_SEPARATOR . 'Validator' . DIRECTORY_SEPARATOR . 'ComposedItem.phptpl',
51+
new ComposedPropertyValidator(
52+
$property,
53+
$properties,
54+
static::class,
5555
[
5656
'properties' => $properties,
57+
'property' => $property,
5758
'viewHelper' => new RenderHelper(),
5859
'availableAmount' => $availableAmount,
5960
'composedValueValidation' => $this->getComposedValueValidation($availableAmount),

src/PropertyProcessor/ComposedValue/AllOfProcessor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
* @package PHPModelGenerator\PropertyProcessor\ComposedValue
99
*/
10-
class AllOfProcessor extends AbstractComposedValueProcessor
10+
class AllOfProcessor extends AbstractComposedPropertiesProcessor
1111
{
1212
/**
1313
* @inheritdoc

0 commit comments

Comments
 (0)