Skip to content

Commit 137ce72

Browse files
authored
Merge pull request #51 from Flowpack/neos9
FEATURE: Neos 9.0 compatibility
2 parents 7900bd7 + 71a3b0a commit 137ce72

File tree

52 files changed

+1297
-843
lines changed

Some content is hidden

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

52 files changed

+1297
-843
lines changed

.github/workflows/tests.yml

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,24 @@ jobs:
1919
fail-fast: false
2020
matrix:
2121
include:
22-
- php-version: 7.4
23-
neos-version: 7.3
24-
- php-version: 8.1
25-
neos-version: 8.3
22+
- php-version: "8.2"
23+
neos-version: "9.0"
24+
- php-version: "8.3"
25+
neos-version: "9.0"
26+
27+
services:
28+
mariadb:
29+
# see https://mariadb.com/kb/en/mariadb-server-release-dates/
30+
# this should be a current release, e.g. the LTS version
31+
image: mariadb:10.8
32+
env:
33+
MYSQL_USER: neos
34+
MYSQL_PASSWORD: neos
35+
MYSQL_DATABASE: neos_functional_testing
36+
MYSQL_ROOT_PASSWORD: neos
37+
ports:
38+
- "3306:3306"
39+
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
2640

2741
steps:
2842
- name: Checkout code
@@ -38,15 +52,15 @@ jobs:
3852
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
3953
shell: bash
4054

41-
- uses: actions/cache@v2
55+
- uses: actions/cache@v3
4256
with:
4357
path: ${{ steps.composer-cache.outputs.dir }}
4458
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
4559
restore-keys: ${{ runner.os }}-composer-
4660

4761
- name: Prepare Neos distribution
4862
run: |
49-
git clone --depth 1 --branch ${{ matrix.neos-version }} https://github.com/neos/neos-base-distribution.git ${FLOW_PATH_ROOT}
63+
git clone --depth 1 --branch ${{ matrix.neos-version }} https://github.com/neos/neos-development-distribution.git ${FLOW_PATH_ROOT}
5064
cd ${FLOW_PATH_ROOT}
5165
composer config --no-plugins allow-plugins.neos/composer-plugin true
5266
composer config repositories.package '{ "type": "path", "url": "../Flowpack.NodeTemplates", "options": { "symlink": false } }'
@@ -56,6 +70,7 @@ jobs:
5670
- name: Install dependencies
5771
run: |
5872
cd ${FLOW_PATH_ROOT}
73+
rm -rf composer.lock
5974
composer install --no-interaction --no-progress --prefer-dist
6075
6176
- name: Linting
@@ -66,9 +81,35 @@ jobs:
6681
- name: Run Unit tests
6782
run: |
6883
cd ${FLOW_PATH_ROOT}
69-
bin/phpunit --colors -c Build/BuildEssentials/PhpUnit/UnitTests.xml Packages/Application/Flowpack.NodeTemplates/Tests/Unit
84+
bin/phpunit -c Build/BuildEssentials/PhpUnit/UnitTests.xml Packages/Application/Flowpack.NodeTemplates/Tests/Unit
85+
86+
- name: Setup Flow configuration
87+
run: |
88+
cd ${FLOW_PATH_ROOT}
89+
rm -f Configuration/Testing/Settings.yaml
90+
cat <<EOF >> Configuration/Testing/Settings.yaml
91+
Neos:
92+
Flow:
93+
persistence:
94+
backendOptions:
95+
host: '127.0.0.1'
96+
driver: pdo_mysql
97+
user: 'neos'
98+
password: 'neos'
99+
dbname: 'neos_functional_testing'
100+
EOF
70101
71102
- name: Run Functional tests
72103
run: |
73104
cd ${FLOW_PATH_ROOT}
74-
bin/phpunit --colors -c Build/BuildEssentials/PhpUnit/FunctionalTests.xml Packages/Application/Flowpack.NodeTemplates/Tests/Functional
105+
bin/phpunit -c Build/BuildEssentials/PhpUnit/FunctionalTests.xml Packages/Application/Flowpack.NodeTemplates/Tests/Functional
106+
107+
- name: Show log on failure
108+
if: ${{ failure() }}
109+
run: |
110+
cd ${FLOW_PATH_ROOT}
111+
cat Data/Logs/System_Testing.log
112+
for file in Data/Logs/Exceptions/*; do
113+
echo $file
114+
cat $file
115+
done

Classes/Application/Command/NodeTemplateCommandController.php

Lines changed: 89 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,18 @@
88
use Flowpack\NodeTemplates\Domain\NodeCreation\NodeCreationService;
99
use Flowpack\NodeTemplates\Domain\NodeTemplateDumper\NodeTemplateDumper;
1010
use Flowpack\NodeTemplates\Domain\TemplateConfiguration\TemplateConfigurationProcessor;
11-
use Neos\ContentRepository\Domain\Model\NodeInterface;
12-
use Neos\ContentRepository\Domain\Service\ContextFactoryInterface;
13-
use Neos\ContentRepository\Domain\Service\NodeTypeManager;
11+
use Neos\ContentRepository\Core\Feature\NodeCreation\Command\CreateNodeAggregateWithNode;
12+
use Neos\ContentRepository\Core\Projection\ContentGraph\AbsoluteNodePath;
13+
use Neos\ContentRepository\Core\Projection\ContentGraph\NodePath;
14+
use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints;
15+
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId;
16+
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
17+
use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry;
1418
use Neos\Flow\Annotations as Flow;
1519
use Neos\Flow\Cli\CommandController;
16-
use Neos\Neos\Domain\Service\ContentContext;
20+
use Neos\Neos\Domain\Repository\SiteRepository;
21+
use Neos\Neos\Domain\Service\NodeTypeNameFactory;
22+
use Neos\Neos\Ui\Domain\NodeCreation\NodeCreationCommands;
1723

1824
class NodeTemplateCommandController extends CommandController
1925
{
@@ -23,12 +29,6 @@ class NodeTemplateCommandController extends CommandController
2329
*/
2430
protected $nodeCreationService;
2531

26-
/**
27-
* @Flow\Inject
28-
* @var ContextFactoryInterface
29-
*/
30-
protected $contextFactory;
31-
3232
/**
3333
* @Flow\Inject
3434
* @var NodeTemplateDumper
@@ -42,30 +42,52 @@ class NodeTemplateCommandController extends CommandController
4242
protected $templateConfigurationProcessor;
4343

4444
/**
45+
* @var SiteRepository
4546
* @Flow\Inject
46-
* @var NodeTypeManager
4747
*/
48-
protected $nodeTypeManager;
48+
protected $siteRepository;
49+
50+
/**
51+
* @var ContentRepositoryRegistry
52+
* @Flow\Inject
53+
*/
54+
protected $contentRepositoryRegistry;
4955

5056
/**
5157
* Dump the node tree structure into a NodeTemplate YAML structure.
5258
* References to Nodes and non-primitive property values are commented out in the YAML.
5359
*
5460
* @param string $startingNodeId specified root node of the node tree.
61+
* @param string|null $site the Neos site, which determines the content repository. Defaults to the first available one.
5562
* @param string $workspaceName custom workspace to dump from. Defaults to 'live'.
5663
* @return void
5764
*/
58-
public function createFromNodeSubtreeCommand(string $startingNodeId, string $workspaceName = 'live'): void
65+
public function createFromNodeSubtreeCommand(string $startingNodeId, ?string $site = null, string $workspaceName = 'live'): void
5966
{
60-
$subgraph = $this->contextFactory->create([
61-
'workspaceName' => $workspaceName
62-
]);
63-
/** @var ?NodeInterface $node */
64-
$node = $subgraph->getNodeByIdentifier($startingNodeId);
67+
$siteInstance = $site
68+
? $this->siteRepository->findOneByNodeName($site)
69+
: $this->siteRepository->findDefault();
70+
71+
if (!$siteInstance) {
72+
$this->outputLine(sprintf('<error>Site "%s" does not exist.</error>', $site));
73+
$this->quit(2);
74+
}
75+
76+
$siteConfiguration = $siteInstance->getConfiguration();
77+
78+
$contentRepository = $this->contentRepositoryRegistry->get($siteConfiguration->contentRepositoryId);
79+
80+
// default context? https://github.com/neos/neos-development-collection/issues/5113
81+
$subgraph = $contentRepository->getContentGraph(WorkspaceName::fromString($workspaceName))->getSubgraph(
82+
$siteConfiguration->defaultDimensionSpacePoint,
83+
VisibilityConstraints::default()
84+
);
85+
86+
$node = $subgraph->findNodeById(NodeAggregateId::fromString($startingNodeId));
6587
if (!$node) {
6688
throw new \InvalidArgumentException("Node $startingNodeId doesnt exist in workspace $workspaceName.");
6789
}
68-
echo $this->nodeTemplateDumper->createNodeTemplateYamlDumpFromSubtree($node);
90+
echo $this->nodeTemplateDumper->createNodeTemplateYamlDumpFromSubtree($node, $contentRepository);
6991
}
7092

7193
/**
@@ -74,25 +96,54 @@ public function createFromNodeSubtreeCommand(string $startingNodeId, string $wor
7496
*
7597
* We process and build all configured NodeType templates. No nodes will be created in the Content Repository.
7698
*
99+
* @param string|null $site the Neos site, which determines the content repository. Defaults to the first available one.
77100
*/
78-
public function validateCommand(): void
101+
public function validateCommand(?string $site = null): void
79102
{
103+
$siteInstance = $site
104+
? $this->siteRepository->findOneByNodeName($site)
105+
: $this->siteRepository->findDefault();
106+
107+
if (!$siteInstance) {
108+
$this->outputLine(sprintf('<error>Site "%s" does not exist.</error>', $site));
109+
$this->quit(2);
110+
}
111+
112+
$siteConfiguration = $siteInstance->getConfiguration();
113+
114+
$contentRepository = $this->contentRepositoryRegistry->get($siteConfiguration->contentRepositoryId);
115+
80116
$templatesChecked = 0;
81117
/**
82118
* nodeTypeNames as index
83119
* @var array<string, array{processingErrors: ProcessingErrors, dataWasAccessed: bool}> $faultyNodeTypeTemplates
84120
*/
85121
$faultyNodeTypeTemplates = [];
86122

87-
foreach ($this->nodeTypeManager->getNodeTypes(false) as $nodeType) {
123+
// default context? https://github.com/neos/neos-development-collection/issues/5113
124+
$subgraph = $contentRepository->getContentGraph(WorkspaceName::forLive())->getSubgraph(
125+
$siteConfiguration->defaultDimensionSpacePoint,
126+
VisibilityConstraints::default()
127+
);
128+
129+
$sitesNode = $subgraph->findRootNodeByType(NodeTypeNameFactory::forSites());
130+
$siteNode = $sitesNode ? $subgraph->findNodeByPath(
131+
$siteInstance->getNodeName()->toNodeName(),
132+
$sitesNode->aggregateId
133+
) : null;
134+
135+
if (!$siteNode) {
136+
$this->outputLine(sprintf('<error>Could not resolve site node for site "%s".</error>', $siteInstance->getNodeName()->value));
137+
$this->quit(3);
138+
}
139+
140+
foreach ($contentRepository->getNodeTypeManager()->getNodeTypes(false) as $nodeType) {
88141
$templateConfiguration = $nodeType->getOptions()['template'] ?? null;
89142
if (!$templateConfiguration) {
90143
continue;
91144
}
92145
$processingErrors = ProcessingErrors::create();
93146

94-
/** @var ContentContext $subgraph */
95-
$subgraph = $this->contextFactory->create();
96147

97148
$observableEmptyData = new class ([]) extends \ArrayObject
98149
{
@@ -104,27 +155,37 @@ public function offsetExists($key): bool
104155
}
105156
};
106157

107-
$siteNode = $subgraph->getCurrentSiteNode();
108-
109158
$template = $this->templateConfigurationProcessor->processTemplateConfiguration(
110159
$templateConfiguration,
111160
[
112161
'data' => $observableEmptyData,
113-
'triggeringNode' => $siteNode, // @deprecated
114162
'site' => $siteNode,
115163
'parentNode' => $siteNode,
116164
],
117165
$processingErrors
118166
);
119167

120-
$this->nodeCreationService->createMutatorsForRootTemplate($template, $nodeType, $this->nodeTypeManager, $subgraph, $processingErrors);
168+
$fakeNodeCreationCommands = NodeCreationCommands::fromFirstCommand(
169+
CreateNodeAggregateWithNode::create(
170+
$siteNode->workspaceName,
171+
NodeAggregateId::create(),
172+
$nodeType->name,
173+
$siteNode->originDimensionSpacePoint,
174+
$siteNode->aggregateId
175+
),
176+
$contentRepository->getNodeTypeManager()
177+
);
178+
179+
$this->nodeCreationService->apply($template, $fakeNodeCreationCommands, $contentRepository->getNodeTypeManager(), $subgraph, $nodeType, $processingErrors);
121180

122181
if ($processingErrors->hasError()) {
123-
$faultyNodeTypeTemplates[$nodeType->getName()] = ['processingErrors' => $processingErrors, 'dataWasAccessed' => $observableEmptyData->dataWasAccessed];
182+
$faultyNodeTypeTemplates[$nodeType->name->value] = ['processingErrors' => $processingErrors, 'dataWasAccessed' => $observableEmptyData->dataWasAccessed];
124183
}
125184
$templatesChecked++;
126185
}
127186

187+
$this->output(sprintf('<comment>Content repository "%s": </comment>', $contentRepository->id->value));
188+
128189
if ($templatesChecked === 0) {
129190
$this->outputLine('<comment>No NodeType templates found.</comment>');
130191
return;

Classes/Domain/ErrorHandling/ErrorHandlingConfiguration.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ class ErrorHandlingConfiguration
88
{
99
/**
1010
* @Flow\InjectConfiguration(package="Flowpack.NodeTemplates", path="errorHandling")
11+
* @var array<mixed>
1112
*/
1213
protected array $configuration;
1314

Classes/Domain/ErrorHandling/ProcessingErrorHandler.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
namespace Flowpack\NodeTemplates\Domain\ErrorHandling;
44

5-
use Neos\ContentRepository\Domain\Model\NodeInterface;
5+
use Neos\ContentRepository\Core\NodeType\NodeType;
6+
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId;
67
use Neos\Flow\Annotations as Flow;
78
use Neos\Flow\Log\ThrowableStorageInterface;
89
use Neos\Flow\Log\Utility\LogEnvironment;
910
use Neos\Neos\Ui\Domain\Model\Feedback\Messages\Error;
11+
use Neos\Neos\Ui\Domain\Model\Feedback\Messages\Warning;
1012
use Neos\Neos\Ui\Domain\Model\FeedbackCollection;
1113
use Psr\Log\LoggerInterface;
1214

@@ -39,7 +41,7 @@ class ProcessingErrorHandler
3941
/**
4042
* @return bool if to continue or abort
4143
*/
42-
public function handleAfterTemplateConfigurationProcessing(ProcessingErrors $processingErrors, NodeInterface $node): bool
44+
public function handleAfterTemplateConfigurationProcessing(ProcessingErrors $processingErrors, NodeType $nodeType, NodeAggregateId $nodeAggregateId): bool
4345
{
4446
if (!$processingErrors->hasError()) {
4547
return true;
@@ -49,9 +51,8 @@ public function handleAfterTemplateConfigurationProcessing(ProcessingErrors $pro
4951
return true;
5052
}
5153

52-
assert(method_exists($node, '__toString'));
5354
$templateNotCreatedException = new TemplateNotCreatedException(
54-
sprintf('Template for "%s" was not applied. Only %s was created.', $node->getNodeType()->getLabel(), (string)$node),
55+
sprintf('Template for "%s" was not applied. Only %s was created.', $nodeType->getLabel(), $nodeAggregateId->value),
5556
1686135532992,
5657
$processingErrors->first()->getException(),
5758
);
@@ -64,15 +65,14 @@ public function handleAfterTemplateConfigurationProcessing(ProcessingErrors $pro
6465
/**
6566
* @return bool if to continue or abort
6667
*/
67-
public function handleAfterNodeCreation(ProcessingErrors $processingErrors, NodeInterface $node): bool
68+
public function handleAfterNodeCreation(ProcessingErrors $processingErrors, NodeType $nodeType, NodeAggregateId $nodeAggregateId): bool
6869
{
6970
if (!$processingErrors->hasError()) {
7071
return true;
7172
}
7273

73-
assert(method_exists($node, '__toString'));
7474
$templatePartiallyCreatedException = new TemplatePartiallyCreatedException(
75-
sprintf('Template for "%s" only partially applied. Please check the newly created nodes beneath %s.', $node->getNodeType()->getLabel(), (string)$node),
75+
sprintf('Template for "%s" only partially applied. Please check the newly created nodes beneath %s.', $nodeType->getLabel(), $nodeAggregateId->value),
7676
1686135564160,
7777
$processingErrors->first()->getException(),
7878
);
@@ -106,10 +106,10 @@ private function logProcessingErrors(ProcessingErrors $processingErrors, \Domain
106106
);
107107

108108
foreach ($messages as $message) {
109-
$error = new Error();
110-
$error->setMessage($message);
109+
$warning = new Warning();
110+
$warning->setMessage($message);
111111
$this->feedbackCollection->add(
112-
$error
112+
$warning
113113
);
114114
}
115115
}

Classes/Domain/ErrorHandling/ProcessingErrors.php

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

33
namespace Flowpack\NodeTemplates\Domain\ErrorHandling;
44

5-
use Neos\Flow\Annotations as Flow;
6-
7-
/** @Flow\Proxy(false) */
5+
/** @implements \IteratorAggregate<int, ProcessingError> */
86
class ProcessingErrors implements \IteratorAggregate
97
{
108
/** @var array<int, ProcessingError> */
@@ -19,6 +17,7 @@ public static function create(): self
1917
return new self();
2018
}
2119

20+
/** @phpstan-assert-if-true !null $this->first() */
2221
public function hasError(): bool
2322
{
2423
return $this->errors !== [];

0 commit comments

Comments
 (0)