Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
0a50e2f
WIP: FEATURE: Neos 9.0 Prototype
mhsdesign Jun 2, 2023
489eeca
FEATURE: First working draft. 1 functional Test passes ;)
mhsdesign Jun 9, 2023
5c916d4
FEATURE: Add support for setting references
mhsdesign Jun 9, 2023
358a33f
TASK: re-enable exception handling
mhsdesign Jun 10, 2023
7879e55
TASK: ensure node has uri path segment
mhsdesign Jun 10, 2023
e3e9020
TASK: Speed up tests by running in synchronous mode, and use own test…
mhsdesign Jun 10, 2023
cac831d
TASK: Re-enable other tests
mhsdesign Jun 10, 2023
f418051
TASK: Check for invalid node-constraints and update snapshots
mhsdesign Jun 10, 2023
df9b2fd
TASK: Update snapshot to contain `null` property value
mhsdesign Jun 10, 2023
cc9a6ed
TASK: Adjust to NeosUI commands->first update and expose parentNode i…
mhsdesign Jun 24, 2023
3312620
Upmerge nodetemplates version 2 changes into version 3-dev
mhsdesign Jun 24, 2023
85f19f7
TASK: Hackily fix test
mhsdesign Jul 5, 2023
ea14c42
Upmerge remote-tracking branch 'origin/feature/separateNodeCreationWi…
mhsdesign Jul 5, 2023
7b4b938
Merge remote-tracking branch 'origin/feature/separateNodeCreationWith…
mhsdesign Jul 17, 2023
d538e4d
Merge remote-tracking branch 'origin/2.0' into neos9
mhsdesign Jul 22, 2023
d0d6c24
TASK: Prepare tests for neos 9
mhsdesign Jul 22, 2023
2ca5e4e
TASK: Test patch neos stuff
mhsdesign Jul 22, 2023
a3ec2a6
TASK: Make nodeId deterministic for testing
mhsdesign Jul 23, 2023
8ddb961
TASK: Remove dependency to WIP branch and copy code
mhsdesign Aug 2, 2023
bede22e
TASK: Adjust to changes in Neos
mhsdesign Aug 2, 2023
94437e6
TASK: Fix generateUriPathSegment
mhsdesign Aug 2, 2023
80da04d
TASK: Fix uriPathSegment if it depends on the title of the node creat…
mhsdesign Aug 2, 2023
6e67fb6
Merge remote-tracking branch 'origin/2.0' into neos9
mhsdesign Oct 17, 2023
386ed35
TASK: Adjust to changes in neos 9 dev (with phpstan)
mhsdesign Oct 17, 2023
68dee0b
TASK: Fix ci distribution installation
mhsdesign Oct 17, 2023
157c85e
TASK: Use dev distribution in ci because sub splits are broken atm
mhsdesign Oct 18, 2023
3b9bee2
TASK: Adjust unit and functional tests to changes in neos 9 dev
mhsdesign Oct 18, 2023
e7f15bd
TASK: Use tetheredDescendantNodeAggregateIds instead of deterministic…
mhsdesign Oct 18, 2023
7b14b18
Merge remote-tracking branch 'origin/2.0' into neos9
mhsdesign Oct 18, 2023
50d4834
BUGFIX: Nested tethered nodes
mhsdesign Oct 18, 2023
357a93a
TASK: Level up Phpstan to 6
mhsdesign Oct 18, 2023
6db6c7e
Merge remote-tracking branch 'origin/2.0' into neos9
mhsdesign Oct 18, 2023
06fdf68
TASK: Level up ++ phpstan
mhsdesign Oct 18, 2023
9ca7918
TASK: Level up ++ phpstan to 8
mhsdesign Oct 18, 2023
91ade24
TASK: Update to adjustments in Neos and Neos.Ui
mhsdesign Jan 18, 2024
8dda881
TASK: Simplify `ContentRepositoryTestTrait`
mhsdesign Jan 18, 2024
706f343
TASK: Adjust to changes in the NeosUi
mhsdesign Feb 17, 2024
f4b07d3
Merge remote-tracking branch 'origin/2.0' into neos9
mhsdesign Feb 21, 2024
8671cd6
TASK: Adjust to changes in UI
mhsdesign Feb 24, 2024
5f3b21b
FEATURE: Neos9-Beta10 compatibility
mhsdesign Jun 21, 2024
4d1ccfa
BUGFIX: Add workaround for unsetting properties with default values
mhsdesign Jun 21, 2024
6b9fc67
TASK: Remove patches from CI after merge of 3519
mhsdesign Jun 21, 2024
e9c5b29
Merge remote-tracking branch 'origin/2.0' into neos9
mhsdesign Jun 21, 2024
383d614
TASK: Introduce `site` variable in Neos 9
mhsdesign Jun 21, 2024
88b623e
FEATURE: Neos9 support for `flow nodeTemplate:validate`
mhsdesign Jun 21, 2024
a5be69e
TASK: Unskip test after merge of core bugfix
mhsdesign Jun 21, 2024
96bd529
FEATURE: Migrate `flow nodeTemplate:createFromNodeSubtree` to Neos9
mhsdesign Jun 21, 2024
44c0f22
TASK: Use FlowEntitiesTrait::truncateAndSetupFlowEntities to reset pe…
mhsdesign Jun 21, 2024
feeec56
TASK: Run tests also on PHP8.3
mhsdesign Jun 21, 2024
f37b6c4
TASK: Hotfix for transaction errors in CI
mhsdesign Jun 21, 2024
0d6ae5b
TASK: Improve documentation of `nodeTemplate` CLI commands
mhsdesign Jun 21, 2024
90d7a69
TASK: Small cosmetic adjustment
mhsdesign Jun 21, 2024
3f0bad4
Merge remote-tracking branch 'origin/2.0' into neos9
mhsdesign Jun 21, 2024
f35a583
TASK: Improve DI for `TemplateNodeCreationHandler` and early return i…
mhsdesign Jun 22, 2024
67abdde
Adjust to Neos9 Beta15
Nov 11, 2024
773f5cb
Adjust tests to beta15
Nov 11, 2024
88c37a7
Adjust to beta 16
Dec 16, 2024
b95c437
TASK: Adjust testing setup to boot after content repository changes
mhsdesign Mar 6, 2025
e5afd23
TASK: Avoid issuing `SetNodeProperties` if its a noop
mhsdesign Mar 6, 2025
1bc15ad
TASK: Update unit tests to adjusted node type manager constructor
mhsdesign Mar 6, 2025
4ce59f6
TASK: Leverage new `Commands` class instead of passing `NodeCreationC…
mhsdesign Mar 6, 2025
28a9a95
TASK: Use new UI warning
mhsdesign Apr 4, 2025
4da027c
TASK: Update `actions/cache@v3`
mhsdesign Apr 4, 2025
71a3b0a
TASK: Fix CI `cr:setup` does not work because nodetypes are not initi…
mhsdesign Apr 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 49 additions & 8 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,24 @@ jobs:
fail-fast: false
matrix:
include:
- php-version: 7.4
neos-version: 7.3
- php-version: 8.1
neos-version: 8.3
- php-version: "8.2"
neos-version: "9.0"
- php-version: "8.3"
neos-version: "9.0"

services:
mariadb:
# see https://mariadb.com/kb/en/mariadb-server-release-dates/
# this should be a current release, e.g. the LTS version
image: mariadb:10.8
env:
MYSQL_USER: neos
MYSQL_PASSWORD: neos
MYSQL_DATABASE: neos_functional_testing
MYSQL_ROOT_PASSWORD: neos
ports:
- "3306:3306"
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3

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

- uses: actions/cache@v2
- uses: actions/cache@v3
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-composer-

- name: Prepare Neos distribution
run: |
git clone --depth 1 --branch ${{ matrix.neos-version }} https://github.com/neos/neos-base-distribution.git ${FLOW_PATH_ROOT}
git clone --depth 1 --branch ${{ matrix.neos-version }} https://github.com/neos/neos-development-distribution.git ${FLOW_PATH_ROOT}
cd ${FLOW_PATH_ROOT}
composer config --no-plugins allow-plugins.neos/composer-plugin true
composer config repositories.package '{ "type": "path", "url": "../Flowpack.NodeTemplates", "options": { "symlink": false } }'
Expand All @@ -56,6 +70,7 @@ jobs:
- name: Install dependencies
run: |
cd ${FLOW_PATH_ROOT}
rm -rf composer.lock
composer install --no-interaction --no-progress --prefer-dist

- name: Linting
Expand All @@ -66,9 +81,35 @@ jobs:
- name: Run Unit tests
run: |
cd ${FLOW_PATH_ROOT}
bin/phpunit --colors -c Build/BuildEssentials/PhpUnit/UnitTests.xml Packages/Application/Flowpack.NodeTemplates/Tests/Unit
bin/phpunit -c Build/BuildEssentials/PhpUnit/UnitTests.xml Packages/Application/Flowpack.NodeTemplates/Tests/Unit

- name: Setup Flow configuration
run: |
cd ${FLOW_PATH_ROOT}
rm -f Configuration/Testing/Settings.yaml
cat <<EOF >> Configuration/Testing/Settings.yaml
Neos:
Flow:
persistence:
backendOptions:
host: '127.0.0.1'
driver: pdo_mysql
user: 'neos'
password: 'neos'
dbname: 'neos_functional_testing'
EOF

- name: Run Functional tests
run: |
cd ${FLOW_PATH_ROOT}
bin/phpunit --colors -c Build/BuildEssentials/PhpUnit/FunctionalTests.xml Packages/Application/Flowpack.NodeTemplates/Tests/Functional
bin/phpunit -c Build/BuildEssentials/PhpUnit/FunctionalTests.xml Packages/Application/Flowpack.NodeTemplates/Tests/Functional

- name: Show log on failure
if: ${{ failure() }}
run: |
cd ${FLOW_PATH_ROOT}
cat Data/Logs/System_Testing.log
for file in Data/Logs/Exceptions/*; do
echo $file
cat $file
done
117 changes: 89 additions & 28 deletions Classes/Application/Command/NodeTemplateCommandController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@
use Flowpack\NodeTemplates\Domain\NodeCreation\NodeCreationService;
use Flowpack\NodeTemplates\Domain\NodeTemplateDumper\NodeTemplateDumper;
use Flowpack\NodeTemplates\Domain\TemplateConfiguration\TemplateConfigurationProcessor;
use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\ContentRepository\Domain\Service\ContextFactoryInterface;
use Neos\ContentRepository\Domain\Service\NodeTypeManager;
use Neos\ContentRepository\Core\Feature\NodeCreation\Command\CreateNodeAggregateWithNode;
use Neos\ContentRepository\Core\Projection\ContentGraph\AbsoluteNodePath;
use Neos\ContentRepository\Core\Projection\ContentGraph\NodePath;
use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId;
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Cli\CommandController;
use Neos\Neos\Domain\Service\ContentContext;
use Neos\Neos\Domain\Repository\SiteRepository;
use Neos\Neos\Domain\Service\NodeTypeNameFactory;
use Neos\Neos\Ui\Domain\NodeCreation\NodeCreationCommands;

class NodeTemplateCommandController extends CommandController
{
Expand All @@ -23,12 +29,6 @@ class NodeTemplateCommandController extends CommandController
*/
protected $nodeCreationService;

/**
* @Flow\Inject
* @var ContextFactoryInterface
*/
protected $contextFactory;

/**
* @Flow\Inject
* @var NodeTemplateDumper
Expand All @@ -42,30 +42,52 @@ class NodeTemplateCommandController extends CommandController
protected $templateConfigurationProcessor;

/**
* @var SiteRepository
* @Flow\Inject
* @var NodeTypeManager
*/
protected $nodeTypeManager;
protected $siteRepository;

/**
* @var ContentRepositoryRegistry
* @Flow\Inject
*/
protected $contentRepositoryRegistry;

/**
* Dump the node tree structure into a NodeTemplate YAML structure.
* References to Nodes and non-primitive property values are commented out in the YAML.
*
* @param string $startingNodeId specified root node of the node tree.
* @param string|null $site the Neos site, which determines the content repository. Defaults to the first available one.
* @param string $workspaceName custom workspace to dump from. Defaults to 'live'.
* @return void
*/
public function createFromNodeSubtreeCommand(string $startingNodeId, string $workspaceName = 'live'): void
public function createFromNodeSubtreeCommand(string $startingNodeId, ?string $site = null, string $workspaceName = 'live'): void
{
$subgraph = $this->contextFactory->create([
'workspaceName' => $workspaceName
]);
/** @var ?NodeInterface $node */
$node = $subgraph->getNodeByIdentifier($startingNodeId);
$siteInstance = $site
? $this->siteRepository->findOneByNodeName($site)
: $this->siteRepository->findDefault();

if (!$siteInstance) {
$this->outputLine(sprintf('<error>Site "%s" does not exist.</error>', $site));
$this->quit(2);
}

$siteConfiguration = $siteInstance->getConfiguration();

$contentRepository = $this->contentRepositoryRegistry->get($siteConfiguration->contentRepositoryId);

// default context? https://github.com/neos/neos-development-collection/issues/5113
$subgraph = $contentRepository->getContentGraph(WorkspaceName::fromString($workspaceName))->getSubgraph(
$siteConfiguration->defaultDimensionSpacePoint,
VisibilityConstraints::default()
);

$node = $subgraph->findNodeById(NodeAggregateId::fromString($startingNodeId));
if (!$node) {
throw new \InvalidArgumentException("Node $startingNodeId doesnt exist in workspace $workspaceName.");
}
echo $this->nodeTemplateDumper->createNodeTemplateYamlDumpFromSubtree($node);
echo $this->nodeTemplateDumper->createNodeTemplateYamlDumpFromSubtree($node, $contentRepository);
}

/**
Expand All @@ -74,25 +96,54 @@ public function createFromNodeSubtreeCommand(string $startingNodeId, string $wor
*
* We process and build all configured NodeType templates. No nodes will be created in the Content Repository.
*
* @param string|null $site the Neos site, which determines the content repository. Defaults to the first available one.
*/
public function validateCommand(): void
public function validateCommand(?string $site = null): void
{
$siteInstance = $site
? $this->siteRepository->findOneByNodeName($site)
: $this->siteRepository->findDefault();

if (!$siteInstance) {
$this->outputLine(sprintf('<error>Site "%s" does not exist.</error>', $site));
$this->quit(2);
}

$siteConfiguration = $siteInstance->getConfiguration();

$contentRepository = $this->contentRepositoryRegistry->get($siteConfiguration->contentRepositoryId);

$templatesChecked = 0;
/**
* nodeTypeNames as index
* @var array<string, array{processingErrors: ProcessingErrors, dataWasAccessed: bool}> $faultyNodeTypeTemplates
*/
$faultyNodeTypeTemplates = [];

foreach ($this->nodeTypeManager->getNodeTypes(false) as $nodeType) {
// default context? https://github.com/neos/neos-development-collection/issues/5113
$subgraph = $contentRepository->getContentGraph(WorkspaceName::forLive())->getSubgraph(
$siteConfiguration->defaultDimensionSpacePoint,
VisibilityConstraints::default()
);

$sitesNode = $subgraph->findRootNodeByType(NodeTypeNameFactory::forSites());
$siteNode = $sitesNode ? $subgraph->findNodeByPath(
$siteInstance->getNodeName()->toNodeName(),
$sitesNode->aggregateId
) : null;

if (!$siteNode) {
$this->outputLine(sprintf('<error>Could not resolve site node for site "%s".</error>', $siteInstance->getNodeName()->value));
$this->quit(3);
}

foreach ($contentRepository->getNodeTypeManager()->getNodeTypes(false) as $nodeType) {
$templateConfiguration = $nodeType->getOptions()['template'] ?? null;
if (!$templateConfiguration) {
continue;
}
$processingErrors = ProcessingErrors::create();

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

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

$siteNode = $subgraph->getCurrentSiteNode();

$template = $this->templateConfigurationProcessor->processTemplateConfiguration(
$templateConfiguration,
[
'data' => $observableEmptyData,
'triggeringNode' => $siteNode, // @deprecated
'site' => $siteNode,
'parentNode' => $siteNode,
],
$processingErrors
);

$this->nodeCreationService->createMutatorsForRootTemplate($template, $nodeType, $this->nodeTypeManager, $subgraph, $processingErrors);
$fakeNodeCreationCommands = NodeCreationCommands::fromFirstCommand(
CreateNodeAggregateWithNode::create(
$siteNode->workspaceName,
NodeAggregateId::create(),
$nodeType->name,
$siteNode->originDimensionSpacePoint,
$siteNode->aggregateId
),
$contentRepository->getNodeTypeManager()
);

$this->nodeCreationService->apply($template, $fakeNodeCreationCommands, $contentRepository->getNodeTypeManager(), $subgraph, $nodeType, $processingErrors);

if ($processingErrors->hasError()) {
$faultyNodeTypeTemplates[$nodeType->getName()] = ['processingErrors' => $processingErrors, 'dataWasAccessed' => $observableEmptyData->dataWasAccessed];
$faultyNodeTypeTemplates[$nodeType->name->value] = ['processingErrors' => $processingErrors, 'dataWasAccessed' => $observableEmptyData->dataWasAccessed];
}
$templatesChecked++;
}

$this->output(sprintf('<comment>Content repository "%s": </comment>', $contentRepository->id->value));

if ($templatesChecked === 0) {
$this->outputLine('<comment>No NodeType templates found.</comment>');
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class ErrorHandlingConfiguration
{
/**
* @Flow\InjectConfiguration(package="Flowpack.NodeTemplates", path="errorHandling")
* @var array<mixed>
*/
protected array $configuration;

Expand Down
20 changes: 10 additions & 10 deletions Classes/Domain/ErrorHandling/ProcessingErrorHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

namespace Flowpack\NodeTemplates\Domain\ErrorHandling;

use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\ContentRepository\Core\NodeType\NodeType;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Log\ThrowableStorageInterface;
use Neos\Flow\Log\Utility\LogEnvironment;
use Neos\Neos\Ui\Domain\Model\Feedback\Messages\Error;
use Neos\Neos\Ui\Domain\Model\Feedback\Messages\Warning;
use Neos\Neos\Ui\Domain\Model\FeedbackCollection;
use Psr\Log\LoggerInterface;

Expand Down Expand Up @@ -39,7 +41,7 @@ class ProcessingErrorHandler
/**
* @return bool if to continue or abort
*/
public function handleAfterTemplateConfigurationProcessing(ProcessingErrors $processingErrors, NodeInterface $node): bool
public function handleAfterTemplateConfigurationProcessing(ProcessingErrors $processingErrors, NodeType $nodeType, NodeAggregateId $nodeAggregateId): bool
{
if (!$processingErrors->hasError()) {
return true;
Expand All @@ -49,9 +51,8 @@ public function handleAfterTemplateConfigurationProcessing(ProcessingErrors $pro
return true;
}

assert(method_exists($node, '__toString'));
$templateNotCreatedException = new TemplateNotCreatedException(
sprintf('Template for "%s" was not applied. Only %s was created.', $node->getNodeType()->getLabel(), (string)$node),
sprintf('Template for "%s" was not applied. Only %s was created.', $nodeType->getLabel(), $nodeAggregateId->value),
1686135532992,
$processingErrors->first()->getException(),
);
Expand All @@ -64,15 +65,14 @@ public function handleAfterTemplateConfigurationProcessing(ProcessingErrors $pro
/**
* @return bool if to continue or abort
*/
public function handleAfterNodeCreation(ProcessingErrors $processingErrors, NodeInterface $node): bool
public function handleAfterNodeCreation(ProcessingErrors $processingErrors, NodeType $nodeType, NodeAggregateId $nodeAggregateId): bool
{
if (!$processingErrors->hasError()) {
return true;
}

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

foreach ($messages as $message) {
$error = new Error();
$error->setMessage($message);
$warning = new Warning();
$warning->setMessage($message);
$this->feedbackCollection->add(
$error
$warning
);
}
}
Expand Down
5 changes: 2 additions & 3 deletions Classes/Domain/ErrorHandling/ProcessingErrors.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

namespace Flowpack\NodeTemplates\Domain\ErrorHandling;

use Neos\Flow\Annotations as Flow;

/** @Flow\Proxy(false) */
/** @implements \IteratorAggregate<int, ProcessingError> */
class ProcessingErrors implements \IteratorAggregate
{
/** @var array<int, ProcessingError> */
Expand All @@ -19,6 +17,7 @@ public static function create(): self
return new self();
}

/** @phpstan-assert-if-true !null $this->first() */
public function hasError(): bool
{
return $this->errors !== [];
Expand Down
Loading