Skip to content

Commit 14f03c2

Browse files
committed
Support namespace (with FQCN) definition on JSON schema type - close #31
1 parent e380a75 commit 14f03c2

File tree

3 files changed

+83
-14
lines changed

3 files changed

+83
-14
lines changed

src/ValueObjectFactory.php

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -235,20 +235,29 @@ public function classBuilder(TypeDefinition $typeDefinition): ClassBuilder
235235
* @param TypeSet $typeSet
236236
* @param string $srcFolder Source folder for namespace imports
237237
* @param string|null $className Class name is used from $classBuilder if not set
238+
* @param string|null $rootSrcFolder Source folder for namespace imports with root e.g. /Building
238239
* @return void
239240
*/
240241
public function generateClasses(
241242
ClassBuilder $classBuilder,
242243
FileCollection $fileCollection,
243244
TypeSet $typeSet,
244245
string $srcFolder,
245-
string $className = null
246+
string $className = null,
247+
string $rootSrcFolder = null
246248
): void {
247249
$type = $typeSet->first();
248250

251+
if ($rootSrcFolder === null) {
252+
$rootSrcFolder = $srcFolder;
253+
}
254+
249255
$classInfo = $this->classInfoList->classInfoForPath($srcFolder);
250256
$classNamespacePath = $classInfo->getClassNamespaceFromPath($srcFolder);
251257

258+
$rootClassInfo = $this->classInfoList->classInfoForPath($rootSrcFolder);
259+
$rootClassNamespacePath = $rootClassInfo->getClassNamespaceFromPath($rootSrcFolder);
260+
252261
if ($type instanceof ReferenceType
253262
&& $refType = $type->resolvedType()
254263
) {
@@ -263,7 +272,7 @@ public function generateClasses(
263272
$propertyType = $propertyTypeSet->first();
264273

265274
$propertyClassName = ($this->classNameFilter)($propertyName);
266-
$propertyClassNamespace = $this->extractNamespace($classNamespacePath, $propertyType);
275+
$propertyClassNamespace = $this->extractNamespace($classNamespacePath, $rootClassNamespacePath, $propertyType);
267276
$propertyPropertyName = ($this->propertyNameFilter)($propertyName);
268277

269278
switch (true) {
@@ -282,7 +291,8 @@ public function generateClasses(
282291
$fileCollection,
283292
$itemTypeSet,
284293
$srcFolder,
285-
$itemPropertyName
294+
$itemPropertyName,
295+
$rootSrcFolder
286296
);
287297
}
288298
// no break
@@ -292,7 +302,8 @@ public function generateClasses(
292302
$fileCollection,
293303
$propertyTypeSet,
294304
$srcFolder,
295-
$propertyClassName
305+
$propertyClassName,
306+
$rootSrcFolder
296307
);
297308
$this->addNamespaceImport($classBuilder, $propertyClassNamespace . '\\' . $propertyClassName);
298309
$classBuilder->addProperty(
@@ -308,14 +319,15 @@ public function generateClasses(
308319
if ($propertyRefTypeSet = $propertyType->resolvedType()) {
309320
$propertyRefType = $propertyRefTypeSet->first();
310321
$propertyRefClassName = ($this->classNameFilter)($propertyRefType->name());
311-
$propertyRefClassNamespace = $this->extractNamespace($classNamespacePath, $propertyRefType);
322+
$propertyRefClassNamespace = $this->extractNamespace($classNamespacePath, $rootClassNamespacePath, $propertyRefType);
312323

313324
$this->generateClasses(
314325
ClassBuilder::fromScratch($propertyRefClassName, $propertyRefClassNamespace)->setFinal(true),
315326
$fileCollection,
316327
$propertyRefTypeSet,
317328
$srcFolder,
318-
$propertyType->name()
329+
$propertyType->name(),
330+
$rootSrcFolder
319331
);
320332
$propertyClassName = $propertyRefClassName;
321333
$propertyType = $propertyRefType;
@@ -350,27 +362,30 @@ public function generateClasses(
350362
$fileCollection->add(
351363
$this->generateValueObject(
352364
($this->classNameFilter)($className),
353-
$this->extractNamespace($classNamespacePath, $type),
365+
$this->extractNamespace($classNamespacePath, $rootClassNamespacePath, $type),
354366
$type
355367
)
356368
);
357369
break;
358370
case $type instanceof ArrayType:
359371
$arrayClassBuilder = $this->generateValueObject(
360372
($this->classNameFilter)($className),
361-
$this->extractNamespace($classNamespacePath, $type),
373+
$this->extractNamespace($classNamespacePath, $rootClassNamespacePath, $type),
362374
$type
363375
);
364-
$this->addNamespaceImportForType($arrayClassBuilder, $classNamespacePath, $type);
376+
$this->addNamespaceImportForType($arrayClassBuilder, $classNamespacePath, $rootClassNamespacePath, $type);
365377
$fileCollection->add($arrayClassBuilder);
366378
break;
367379
default:
368380
break;
369381
}
370382
}
371383

372-
private function extractNamespace(string $classNamespacePath, TypeDefinition $typeDefinition): string
373-
{
384+
private function extractNamespace(
385+
string $classNamespacePath,
386+
string $rootClassNamespacePath,
387+
TypeDefinition $typeDefinition
388+
): string {
374389
if (! $typeDefinition instanceof CustomSupport) {
375390
return $classNamespacePath;
376391
}
@@ -380,7 +395,13 @@ private function extractNamespace(string $classNamespacePath, TypeDefinition $ty
380395
$namespace = $typeDefinition->custom()['ns'] ?? '';
381396
}
382397

383-
return \trim($classNamespacePath . '\\' . $namespace, '\\');
398+
$namespace = \str_replace('/', '\\', $namespace);
399+
400+
return \trim(
401+
(\strpos($namespace, '\\') === 0
402+
? $rootClassNamespacePath
403+
: $classNamespacePath)
404+
. '\\' . \trim($namespace, '\\'), '\\');
384405
}
385406

386407
/**
@@ -450,7 +471,7 @@ private function addNamespaceImport(ClassBuilder $classBuilder, string $namespac
450471
}
451472
}
452473

453-
private function addNamespaceImportForType(ClassBuilder $classBuilder, string $classNamespacePath, TypeDefinition $typeDefinition): void
474+
private function addNamespaceImportForType(ClassBuilder $classBuilder, string $classNamespacePath, string $rootClassNamespacePath, TypeDefinition $typeDefinition): void
454475
{
455476
switch (true) {
456477
case $typeDefinition instanceof ArrayType:
@@ -471,7 +492,7 @@ private function addNamespaceImportForType(ClassBuilder $classBuilder, string $c
471492
$itemName = $refType->name();
472493
}
473494
}
474-
$namespace = $this->extractNamespace($classNamespacePath, $itemType);
495+
$namespace = $this->extractNamespace($classNamespacePath, $rootClassNamespacePath, $itemType);
475496

476497
if ($namespace === $classBuilder->getNamespace()) {
477498
continue;

tests/ValueObjectFactoryTest.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,49 @@ public function it_generates_classes_of_objects_with_namespaced_properties_short
243243
}
244244
}
245245

246+
/**
247+
* @test
248+
*/
249+
public function it_generates_classes_of_objects_with_type_namespaced_properties_shorthand(): void
250+
{
251+
$json = \file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'schema_shorthand_type_namespace.json');
252+
$decodedJson = \json_decode($json, true, 512, \JSON_BIGINT_AS_STRING | \JSON_THROW_ON_ERROR);
253+
254+
$typeSet = Type::fromShorthand($decodedJson);
255+
$srcFolder = 'tmp/ValueObject/Shopping';
256+
$rootSrcFolder = 'tmp/ValueObject';
257+
258+
$fileCollection = FileCollection::emptyList();
259+
$classBuilder = ClassBuilder::fromScratch('Order', 'Acme')->setFinal(true);
260+
261+
$this->valueObjectFactory->generateClasses($classBuilder, $fileCollection, $typeSet, $srcFolder, null, $rootSrcFolder);
262+
263+
$this->assertCount(2, $fileCollection);
264+
265+
/** @var ClassBuilder $classBuilder */
266+
foreach ($fileCollection as $classBuilder) {
267+
switch (true) {
268+
case $classBuilder->getName() === 'Order':
269+
$this->assertSame('Acme', $classBuilder->getNamespace());
270+
$this->assertArrayHasKey('Acme\ValueObject\Shopping\Billing\Address', $classBuilder->getNamespaceImports());
271+
$this->assertArrayHasKey('Acme\ValueObject\Payment\ShippingAddresses', $classBuilder->getNamespaceImports());
272+
273+
$properties = $classBuilder->getProperties();
274+
$this->assertArrayHasKey('billingAddress', $properties);
275+
$this->assertArrayHasKey('address', $properties);
276+
277+
$this->assertSame('Address', $properties['billingAddress']->getType());
278+
$this->assertSame('?ShippingAddresses', $properties['address']->getType());
279+
break;
280+
case $classBuilder->getName() === 'Uuid':
281+
$this->assertSame('Acme\ValueObject', $classBuilder->getNamespace());
282+
break;
283+
default:
284+
$this->assertTrue(false, \sprintf('Unexpected class "%s"', $classBuilder->getName()));
285+
}
286+
}
287+
}
288+
246289
private function assertOrder(ClassBuilder $classBuilder): void
247290
{
248291
$this->assertSame('Order', $classBuilder->getName());
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"uuid": "/string|format:uuid",
3+
"billing_address": "Billing/Address",
4+
"address?": "/Payment/ShippingAddresses"
5+
}

0 commit comments

Comments
 (0)