Skip to content

Commit 983d7ef

Browse files
author
Enno Woortmann
committed
Better class names
Detect duplicated classes
1 parent faa4748 commit 983d7ef

File tree

9 files changed

+83
-11
lines changed

9 files changed

+83
-11
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ Requires to match 3 composition elements but matched 1 elements.
157157
The class generation process basically splits up into three to four steps:
158158

159159
- Scan the given source directory to find all *.json files which should be processed.
160-
- 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.
160+
- 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.
161161
- 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.
162162
- If pretty printing is enabled the generated PHP classes will be cleaned up for a better code formatting. Done.
163163

src/Model/Schema.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
*/
2020
class Schema
2121
{
22+
/** @var string */
23+
protected $className;
2224
/** @var Property[] The properties which are part of the class */
2325
protected $properties = [];
2426
/** @var PropertyValidator[] A Collection of validators which must be applied
@@ -31,13 +33,23 @@ class Schema
3133
/**
3234
* Schema constructor.
3335
*
36+
* @param string $className
3437
* @param SchemaDefinitionDictionary $dictionary
3538
*/
36-
public function __construct(SchemaDefinitionDictionary $dictionary = null)
39+
public function __construct(string $className, SchemaDefinitionDictionary $dictionary = null)
3740
{
41+
$this->className = $className;
3842
$this->schemaDefinitionDictionary = $dictionary ?? new SchemaDefinitionDictionary('');
3943
}
4044

45+
/**
46+
* @return string
47+
*/
48+
public function getClassName(): string
49+
{
50+
return $this->className;
51+
}
52+
4153
/**
4254
* @return PropertyInterface[]
4355
*/

src/Model/SchemaDefinition/SchemaDefinitionDictionary.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,8 @@ protected function parseExternalFile(
172172
throw new SchemaException("Invalid JSON-Schema file $jsonSchemaFilePath");
173173
}
174174

175-
$schema = new Schema(new self(dirname($jsonSchemaFilePath)));
175+
// set up a dummy schema to fetch the definitions from the external file
176+
$schema = new Schema('', new self(dirname($jsonSchemaFilePath)));
176177
$schema->getSchemaDictionary()->setUpDefinitionDictionary($jsonSchema, $schemaProcessor, $schema);
177178
$this->parsedExternalFileSchemas[$jsonSchemaFile] = $schema;
178179

src/PropertyProcessor/ComposedValue/AbstractComposedValueProcessor.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,12 @@ private function createMergedProperty(
110110
array $properties,
111111
array $propertyData
112112
): PropertyInterface {
113-
$mergedPropertySchema = new Schema();
114113
$mergedClassName = sprintf(
115114
'%s_Merged_%s', $this->schemaProcessor->getCurrentClassName(),
116-
$propertyData['propertyData']['id'] ?? uniqid()
115+
$propertyData['propertyData']['id'] ?? $compositionProperty->getName()
117116
);
118117

118+
$mergedPropertySchema = new Schema($mergedClassName);
119119
$mergedProperty = new Property('MergedProperty', $mergedClassName);
120120

121121
foreach ($properties as $property) {

src/PropertyProcessor/Property/ObjectProcessor.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ public function process(string $propertyName, array $propertyData): PropertyInte
2727
$property = parent::process($propertyName, $propertyData);
2828

2929
$className = ucfirst(
30-
$propertyData['id'] ?? sprintf('%s_%s', $this->schemaProcessor->getCurrentClassName(), uniqid())
30+
$propertyData['id'] ?? str_replace(
31+
' ',
32+
'_',
33+
sprintf('%s_%s_%s', $this->schemaProcessor->getCurrentClassName(), $propertyName, uniqid())
34+
)
3135
);
3236

3337
$schema = $this->schemaProcessor->processSchema(
@@ -39,9 +43,12 @@ public function process(string $propertyName, array $propertyData): PropertyInte
3943

4044
$property
4145
->addDecorator(
42-
new ObjectInstantiationDecorator($className, $this->schemaProcessor->getGeneratorConfiguration())
46+
new ObjectInstantiationDecorator(
47+
$schema->getClassName(),
48+
$this->schemaProcessor->getGeneratorConfiguration()
49+
)
4350
)
44-
->setType($className)
51+
->setType($schema->getClassName())
4552
->setNestedSchema($schema);
4653

4754
return $property;

src/SchemaProcessor/SchemaProcessor.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class SchemaProcessor
3434
/** @var string */
3535
protected $currentClassName;
3636

37+
/** @var array Collect processed schemas to avoid duplicated classes */
38+
protected $processedSchema = [];
3739
/** @var array */
3840
protected $generatedFiles = [];
3941

@@ -131,8 +133,20 @@ protected function generateModel(
131133
array $structure,
132134
SchemaDefinitionDictionary $dictionary
133135
): Schema {
134-
$schema = new Schema($dictionary);
136+
$schemaSignature = md5(json_encode($structure));
137+
138+
if (isset($this->processedSchema[$schemaSignature])) {
139+
if ($this->generatorConfiguration->isOutputEnabled()) {
140+
// @codeCoverageIgnoreStart
141+
echo "Duplicated signature $schemaSignature for class $className." .
142+
" Redirecting to {$this->processedSchema[$schemaSignature]->getClassName()}\n";
143+
// @codeCoverageIgnoreEnd
144+
}
145+
return $this->processedSchema[$schemaSignature];
146+
}
135147

148+
$schema = new Schema($className, $dictionary);
149+
$this->processedSchema[$schemaSignature] = $schema;
136150
$structure['type'] = 'base';
137151

138152
(new PropertyFactory(new PropertyProcessorFactory()))->create(

tests/Basic/BasicSchemaGenerationTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use PHPModelGenerator\ModelGenerator;
77
use PHPModelGenerator\Model\GeneratorConfiguration;
88
use PHPModelGenerator\Tests\AbstractPHPModelGeneratorTest;
9+
use ReflectionClass;
910

1011
/**
1112
* Class BasicSchemaGenerationTest
@@ -199,4 +200,14 @@ public function testJsonSchemaWithInvalidPropertyTypeDefinitionThrowsAnException
199200

200201
$this->generateClassFromFile('JSONSchemaWithInvalidPropertyTypeDefinition.json');
201202
}
203+
204+
public function testIdenticalSchemasAreMappedToOneClass(): void
205+
{
206+
$reflection = new ReflectionClass($this->generateClassFromFile('IdenticalSubSchema.json'));
207+
208+
$this->assertSame(
209+
$reflection->getProperty('object1')->getDocComment(),
210+
$reflection->getProperty('object2')->getDocComment()
211+
);
212+
}
202213
}

tests/PropertyProcessor/PropertyProcessorFactoryTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public function testGetPropertyProcessor(string $type, string $expectedClass): v
4141
$type,
4242
new PropertyCollectionProcessor(),
4343
new SchemaProcessor('', '', new GeneratorConfiguration(), new RenderQueue()),
44-
new Schema()
44+
new Schema('')
4545
);
4646

4747
$this->assertInstanceOf($expectedClass, $propertyProcessor);
@@ -79,7 +79,7 @@ public function testGetInvalidPropertyProcessorThrowsAnException()
7979
'Hello',
8080
new PropertyCollectionProcessor(),
8181
new SchemaProcessor('', '', new GeneratorConfiguration(), new RenderQueue()),
82-
new Schema()
82+
new Schema('')
8383
);
8484
}
8585
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"type": "object",
3+
"properties": {
4+
"object1": {
5+
"type": "object",
6+
"properties": {
7+
"property1": {
8+
"type": "string"
9+
}
10+
},
11+
"required": [
12+
"property1"
13+
]
14+
},
15+
"object2": {
16+
"type": "object",
17+
"properties": {
18+
"property1": {
19+
"type": "string"
20+
}
21+
},
22+
"required": [
23+
"property1"
24+
]
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)