Skip to content

Commit 5ee49f1

Browse files
committed
TASK: Simplify generation of Specifications
1 parent 5162d1f commit 5ee49f1

9 files changed

+162
-105
lines changed

Classes/Command/NodeObjectsCommandController.php

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,13 @@ public function buildCommand(string $packageKey, string $crId = 'default'): void
9595
);
9696

9797
foreach ($nodeTypes as $nodeType) {
98-
$interfaceSpecification = NodeInterfaceSpecification::createFromPackageAndNodeType($package, $nodeType);
99-
Files::createDirectoryRecursively($interfaceSpecification->directory);
98+
$interfaceSpecification = NodeInterfaceSpecification::createFromNodeType($nodeType);
99+
Files::createDirectoryRecursively($package->getPackagePath() . DIRECTORY_SEPARATOR . $interfaceSpecification->directory);
100100
file_put_contents(
101-
$interfaceSpecification->interfaceFilename,
101+
$package->getPackagePath() . DIRECTORY_SEPARATOR . $interfaceSpecification->interfaceFilename,
102102
$interfaceSpecification->toPhpString()
103103
);
104-
$this->outputLine(' - ' . $interfaceSpecification->interfaceName->nodeTypeName . ' -> <info>' . $interfaceSpecification->interfaceName->getFullyQualifiedClassName() . '</info>');
104+
$this->outputLine(' - ' . $interfaceSpecification->interfaceName->nodeTypeName . ' -> <info>' . $interfaceSpecification->interfaceFilename . '</info>');
105105
}
106106

107107
// loop 2 build objects for all non abstract nodetypes in package
@@ -115,13 +115,13 @@ public function buildCommand(string $packageKey, string $crId = 'default'): void
115115
);
116116

117117
foreach ($nonAbstractNodeTypes as $nodeType) {
118-
$objectSpecification = NodeObjectSpecification::createFromPackageAndNodeType($package, $nodeType);
119-
Files::createDirectoryRecursively($objectSpecification->directory);
118+
$objectSpecification = NodeObjectSpecification::createFromNodeType($nodeType);
119+
Files::createDirectoryRecursively($package->getPackagePath() . DIRECTORY_SEPARATOR . $objectSpecification->directory);
120120
file_put_contents(
121-
$objectSpecification->classFilename,
121+
$package->getPackagePath() . DIRECTORY_SEPARATOR . $objectSpecification->classFilename,
122122
$objectSpecification->toPhpString()
123123
);
124-
$this->outputLine(' - ' . $objectSpecification->objectName->nodeTypeName . ' -> <info>' . $objectSpecification->objectName->getFullyQualifiedClassName() . '</info>');
124+
$this->outputLine(' - ' . $objectSpecification->objectName->nodeTypeName . ' -> <info>' . $objectSpecification->classFilename . '</info>');
125125
}
126126
}
127127

@@ -147,29 +147,29 @@ protected function getPackage(string $packageKey): FlowPackageInterface & Generi
147147
$this->quit(1);
148148
}
149149

150-
/**
151-
* @var array<int, array{namespace:string, classPath:string, mappingType:string}> $autoloadConfigurations
152-
*/
153-
$autoloadConfigurations = $package->getFlattenedAutoloadConfiguration();
154-
$namespace = null;
155-
foreach ($autoloadConfigurations as $autoloadConfiguration) {
156-
if (
157-
$autoloadConfiguration[ 'mappingType' ] === 'psr-4'
158-
&& str_ends_with($autoloadConfiguration[ 'namespace' ], '\\NodeTypes\\')
159-
&& (
160-
$autoloadConfiguration[ 'classPath' ] === $package->getPackagePath() . 'NodeTypes'
161-
|| $autoloadConfiguration[ 'classPath' ] === $package->getPackagePath() . 'NodeTypes/'
162-
)
163-
) {
164-
$namespace = $autoloadConfiguration[ 'namespace' ];
165-
break;
166-
}
167-
}
168-
169-
if ($namespace === null) {
170-
$this->outputLine('<error>No PSR4-NodeTypes namespace for the NodeTypes folder is registered via composer</error>');
171-
$this->quit(1);
172-
}
150+
// /**
151+
// * @var array<int, array{namespace:string, classPath:string, mappingType:string}> $autoloadConfigurations
152+
// */
153+
// $autoloadConfigurations = $package->getFlattenedAutoloadConfiguration();
154+
// $namespace = null;
155+
// foreach ($autoloadConfigurations as $autoloadConfiguration) {
156+
// if (
157+
// $autoloadConfiguration[ 'mappingType' ] === 'psr-4'
158+
// && str_ends_with($autoloadConfiguration[ 'namespace' ], '\\NodeTypes\\')
159+
// && (
160+
// $autoloadConfiguration[ 'classPath' ] === $package->getPackagePath() . 'NodeTypes'
161+
// || $autoloadConfiguration[ 'classPath' ] === $package->getPackagePath() . 'NodeTypes/'
162+
// )
163+
// ) {
164+
// $namespace = $autoloadConfiguration[ 'namespace' ];
165+
// break;
166+
// }
167+
// }
168+
//
169+
// if ($namespace === null) {
170+
// $this->outputLine('<error>No PSR4-NodeTypes namespace for the NodeTypes folder is registered via composer</error>');
171+
// $this->quit(1);
172+
// }
173173
return $package;
174174
}
175175
}

Classes/Domain/NodeInterfaceNameSpecification.php

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,34 @@
1313
{
1414
public function __construct(
1515
public string $nodeTypeName,
16-
public string $phpNamespace,
17-
public string $interfaceName
16+
public string $packageNamespace,
17+
public string $localNamespace,
18+
public string $interfaceName,
1819
) {
1920
}
2021

22+
public function getFullNamespace(): string
23+
{
24+
return $this->packageNamespace . '\\' . $this->localNamespace;
25+
}
26+
2127
public function getFullyQualifiedClassName(): string
2228
{
23-
return $this->phpNamespace . '\\' . $this->interfaceName;
29+
return $this->packageNamespace . '\\' . $this->localNamespace . '\\' . $this->interfaceName;
2430
}
2531

2632
public static function createFromNodeTypeName(
2733
NodeTypeName $nodeTypeName
2834
): self {
29-
3035
list($packageKey, $nodeName) = explode(':', $nodeTypeName->value, 2);
31-
36+
$packageKeyParts = explode('.', $packageKey);
3237
$localNameParts = explode('.', $nodeName);
33-
$localName = array_pop($localNameParts);
34-
35-
$phpNamespace = str_replace(['.', ':'], ['\\', '\\NodeTypes\\'], $nodeTypeName->value);
36-
$interfaceName = str_replace('.', '\\', $localName) . 'NodeInterface';
37-
38+
$localName = $localNameParts[array_key_last($localNameParts)];
3839
return new self(
3940
$nodeTypeName->value,
40-
$phpNamespace,
41-
$interfaceName
41+
PhpNameHelper::sanitize(implode('\\', $packageKeyParts)),
42+
'NodeTypes\\' . PhpNameHelper::sanitize(implode('\\', $localNameParts)),
43+
PhpNameHelper::sanitize(str_replace('.', '\\', $localName)) . 'NodeInterface'
4244
);
4345
}
4446

Classes/Domain/NodeInterfaceNameSpecificationCollection.php

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,16 @@ public static function createFromNodeType(NodeType $nodeType, bool $checkForExis
3535
$interfaces = [
3636
NodeInterfaceNameSpecification::createFromNodeType($nodeType)
3737
];
38-
foreach ($nodeType->getDeclaredSuperTypes() as $superType) {
38+
39+
if ($nodeType->name->value === 'Vendor.Site:Content.Text') {
40+
var_dump(array_keys(self::getFlattenedSuperTypes($nodeType)));
41+
}
42+
foreach (self::getFlattenedSuperTypes($nodeType) as $superType) {
3943
$interface = NodeInterfaceNameSpecification::createFromNodeType($superType);
40-
if ($checkForExistence && interface_exists($interface->getFullyQualifiedClassName())) {
41-
$interfaces[] = $interface;
44+
if ($checkForExistence) {
45+
if (interface_exists($interface->getFullyQualifiedClassName(), true)) {
46+
$interfaces[] = $interface;
47+
}
4248
} else {
4349
$interfaces[] = $interface;
4450
}
@@ -54,4 +60,20 @@ public function asImplementsStatement(): string
5460
return 'implements ' . implode(', ', array_map(fn(NodeInterfaceNameSpecification $item)=> $item->getFullyQualifiedClassName(), $this->items));
5561
}
5662
}
63+
64+
/**
65+
* Returns a flat list of super types to inherit from.
66+
*
67+
* @return array<string,NodeType>
68+
*/
69+
protected static function getFlattenedSuperTypes(NodeType $nodeType): array
70+
{
71+
$flattenedSuperTypes = [];
72+
foreach ($nodeType->getDeclaredSuperTypes() as $superTypeName => $superType) {
73+
$flattenedSuperTypes += static::getFlattenedSuperTypes($superType);
74+
$flattenedSuperTypes[$superTypeName] = $superType;
75+
}
76+
77+
return $flattenedSuperTypes;
78+
}
5779
}

Classes/Domain/NodeInterfaceSpecification.php

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,38 +13,22 @@
1313
{
1414
public function __construct(
1515
public NodeInterfaceNameSpecification $interfaceName,
16-
public NodeInterfaceNameSpecificationCollection $interfaceNames,
1716
public NodePropertySpecificationCollection $properties,
1817
public string $directory,
1918
public string $interfaceFilename,
2019
) {
2120
}
2221

23-
public static function createFromPackageAndNodeType(
24-
FlowPackageInterface $package,
22+
public static function createFromNodeType(
2523
NodeType $nodeType,
2624
): self {
27-
28-
if (!str_starts_with($nodeType->name->value, $package->getPackageKey() . ':')) {
29-
throw new \Exception("Only nodetypes from the given package are allowed");
30-
}
31-
3225
$nameSpecification = NodeInterfaceNameSpecification::createFromNodeType($nodeType);
3326

34-
$localNameParts = explode('.', str_replace($package->getPackageKey() . ':', '', $nodeType->name->value));
35-
$localName = array_pop($localNameParts);
36-
$localNamespace = implode('.', $localNameParts);
37-
38-
$directory = $package->getPackagePath()
39-
. 'NodeTypes' . DIRECTORY_SEPARATOR
40-
. ($localNamespace ? str_replace('.', DIRECTORY_SEPARATOR, $localNamespace) . DIRECTORY_SEPARATOR : '')
41-
. $localName;
42-
27+
$directory = str_replace('\\', DIRECTORY_SEPARATOR, $nameSpecification->localNamespace);
4328
$interfaceFileName = $directory . DIRECTORY_SEPARATOR . $nameSpecification->interfaceName . '.php';
4429

4530
return new self(
4631
$nameSpecification,
47-
NodeInterfaceNameSpecificationCollection::createFromNodeType($nodeType),
4832
NodePropertySpecificationCollection::createFromNodeType($nodeType),
4933
$directory,
5034
$interfaceFileName
@@ -71,7 +55,7 @@ public function toPhpString(): ?string
7155
7256
declare(strict_types=1);
7357
74-
namespace {$this->interfaceName->phpNamespace};
58+
namespace {$this->interfaceName->getFullNamespace()};
7559
7660
use Neos\ContentRepository\Domain\Model\NodeInterface;
7761
use Neos\Flow\Annotations as Flow;

Classes/Domain/NodeObjectNameSpecification.php

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,34 @@
1313
{
1414
public function __construct(
1515
public string $nodeTypeName,
16-
public string $phpNamespace,
16+
public string $packageNamespace,
17+
public string $localNamespace,
1718
public string $className,
1819
) {
1920
}
2021

22+
public function getFullNamespace(): string
23+
{
24+
return $this->packageNamespace . '\\' . $this->localNamespace;
25+
}
26+
2127
public function getFullyQualifiedClassName(): string
2228
{
23-
return $this->phpNamespace . '\\' . $this->className;
29+
return $this->packageNamespace . '\\' . $this->localNamespace . '\\' . $this->className;
2430
}
2531

2632
public static function createFromNodeTypeName(
2733
NodeTypeName $nodeTypeName
2834
): self {
29-
3035
list($packageKey, $nodeName) = explode(':', $nodeTypeName->value, 2);
31-
36+
$packageKeyParts = explode('.', $packageKey);
3237
$localNameParts = explode('.', $nodeName);
33-
$localName = array_pop($localNameParts);
34-
35-
$phpNamespace = str_replace(['.', ':'], ['\\', '\\NodeTypes\\'], $nodeTypeName->value);
36-
$className = str_replace('.', '\\', $localName) . 'NodeObject';
37-
38+
$localName = $localNameParts[array_key_last($localNameParts)];
3839
return new self(
3940
$nodeTypeName->value,
40-
$phpNamespace,
41-
$className,
41+
PhpNameHelper::sanitize(implode('\\', $packageKeyParts)),
42+
'NodeTypes\\' . PhpNameHelper::sanitize(implode('\\', $localNameParts)),
43+
PhpNameHelper::sanitize(str_replace('.', '\\', $localName)) . 'NodeObject'
4244
);
4345
}
4446

Classes/Domain/NodeObjectSpecification.php

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,12 @@ public function __construct(
2020
) {
2121
}
2222

23-
public static function createFromPackageAndNodeType(
24-
FlowPackageInterface $package,
23+
public static function createFromNodeType(
2524
NodeType $nodeType,
2625
): self {
27-
28-
if (!str_starts_with($nodeType->name->value, $package->getPackageKey() . ':')) {
29-
throw new \Exception("Only nodetypes from the given package are allowed");
30-
}
31-
3226
$nameSpecification = NodeObjectNameSpecification::createFromNodeType($nodeType);
3327

34-
$localNameParts = explode('.', str_replace($package->getPackageKey() . ':', '', $nodeType->name->value));
35-
$localName = array_pop($localNameParts);
36-
$localNamespace = implode('.', $localNameParts);
37-
38-
$directory = $package->getPackagePath()
39-
. 'NodeTypes' . DIRECTORY_SEPARATOR
40-
. ($localNamespace ? str_replace('.', DIRECTORY_SEPARATOR, $localNamespace) . DIRECTORY_SEPARATOR : '')
41-
. $localName;
42-
28+
$directory = str_replace('\\', DIRECTORY_SEPARATOR, $nameSpecification->localNamespace);
4329
$classFilename = $directory . DIRECTORY_SEPARATOR . $nameSpecification->className . '.php';
4430

4531
return new self(
@@ -72,7 +58,7 @@ public function toPhpString(): string
7258
7359
declare(strict_types=1);
7460
75-
namespace {$this->objectName->phpNamespace};
61+
namespace {$this->objectName->getFullNamespace()};
7662
7763
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
7864
use Neos\Flow\Annotations as Flow;

Classes/Domain/PhpNameHelper.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace PackageFactory\NodeTypeObjects\Domain;
4+
5+
use Neos\ContentRepository\Core\NodeType\NodeTypeName;
6+
7+
class PhpNameHelper
8+
{
9+
public static function sanitize(string $name): string
10+
{
11+
// pure number segments are prefixed by a number
12+
/**
13+
* @var string $name
14+
*/
15+
$name = preg_replace('/(^|\\\\)([0-9]+)(\\\\|$)/us', '$1_$2$3', $name);
16+
return $name;
17+
}
18+
}

Tests/Unit/NodeInterfaceNameSpecificationTest.php

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,31 @@
1111

1212
class NodeInterfaceNameSpecificationTest extends TestCase
1313
{
14-
#[Test]
15-
public function detectionOfNamesFromNodeType(): void
14+
public static function detectionOfNamesFromNodeTypeDataProvider(): \Generator
15+
{
16+
yield [
17+
'Vendor.Example:Foo.Bar',
18+
'Vendor\Example',
19+
'NodeTypes\Foo\Bar',
20+
'BarNodeInterface'
21+
];
22+
23+
yield [
24+
'404:404',
25+
'_404',
26+
'NodeTypes\_404',
27+
'_404NodeInterface'
28+
];
29+
}
30+
31+
/**
32+
* @test
33+
* @dataProvider detectionOfNamesFromNodeTypeDataProvider
34+
*/
35+
public function detectionOfNamesFromNodeType(string $nodeTypeName, string $expectedPackageNamespace, string $expectedLocalNamespace,string $expectedInterface ): void
1636
{
1737
$nodeType = new NodeType(
18-
NodeTypeName::fromString('Vendor.Example:Foo.Bar'),
38+
NodeTypeName::fromString($nodeTypeName),
1939
[],
2040
[]
2141
);
@@ -26,9 +46,10 @@ public function detectionOfNamesFromNodeType(): void
2646

2747
$this->assertEquals(
2848
new NodeInterfaceNameSpecification(
29-
'Vendor.Example:Foo.Bar',
30-
'Vendor\Example\NodeTypes\Foo\Bar',
31-
'BarNodeInterface',
49+
$nodeTypeName,
50+
$expectedPackageNamespace,
51+
$expectedLocalNamespace,
52+
$expectedInterface,
3253
),
3354
$specification
3455
);

0 commit comments

Comments
 (0)