Skip to content

Commit a3684ba

Browse files
authored
!!! FEATURE: NodeTemplates Version 2.0 #53
!!! FEATURE: NodeTemplates Version 2.0
2 parents 92d5735 + e24eed0 commit a3684ba

File tree

58 files changed

+3199
-700
lines changed

Some content is hidden

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

58 files changed

+3199
-700
lines changed

Classes/Command/NodeTemplateCommandController.php renamed to Classes/Application/Command/NodeTemplateCommandController.php

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

33
declare(strict_types=1);
44

5-
namespace Flowpack\NodeTemplates\Command;
5+
namespace Flowpack\NodeTemplates\Application\Command;
66

7-
use Flowpack\NodeTemplates\NodeTemplateDumper\NodeTemplateDumper;
7+
use Flowpack\NodeTemplates\Domain\NodeTemplateDumper\NodeTemplateDumper;
88
use Neos\Flow\Annotations as Flow;
99
use Neos\Flow\Cli\CommandController;
1010
use Neos\Neos\Domain\Service\ContentContextFactory;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Flowpack\NodeTemplates\Domain;
5+
6+
use Neos\ContentRepository\Domain\Model\NodeInterface;
7+
use Neos\Flow\Annotations as Flow;
8+
use Neos\Neos\Ui\NodeCreationHandler\DocumentTitleNodeCreationHandler;
9+
use Neos\Neos\Ui\NodeCreationHandler\NodeCreationHandlerInterface;
10+
11+
/**
12+
* Augments the original neos ui document title node creation handler, which takes care of setting the "uriPathSegment" based of the title.
13+
* This handler steps in when a node has a node template with the property `uriPathSegment`.
14+
* In this case we will prevent the original handler from being called, as we handle setting the `uriPathSegment` ourselves and the original handler will just override our `uriPathSegment` again.
15+
*
16+
* @todo once we have sorting with https://github.com/neos/neos-ui/pull/3511 we can put our handler at the end instead.
17+
*/
18+
class DelegatingDocumentTitleNodeCreationHandler implements NodeCreationHandlerInterface
19+
{
20+
/**
21+
* @Flow\Inject
22+
* @var DocumentTitleNodeCreationHandler
23+
*/
24+
protected $originalDocumentTitleNodeCreationHandler;
25+
26+
/**
27+
* @throws \Neos\Eel\Exception
28+
* @throws \Neos\Neos\Exception
29+
*/
30+
public function handle(NodeInterface $node, array $data): void
31+
{
32+
$template = $node->getNodeType()->getOptions()['template'] ?? null;
33+
if (
34+
!$template
35+
|| !isset($template['properties']['uriPathSegment'])
36+
) {
37+
$this->originalDocumentTitleNodeCreationHandler->handle($node, $data);
38+
return;
39+
}
40+
41+
// do nothing, as we handle this already when applying the template
42+
}
43+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
namespace Flowpack\NodeTemplates\Domain\ExceptionHandling;
4+
5+
6+
use Neos\Flow\Annotations as Flow;
7+
8+
/**
9+
* @Flow\Proxy(false)
10+
*/
11+
class CaughtException
12+
{
13+
private \Throwable $exception;
14+
15+
private ?string $origin;
16+
17+
private function __construct(\Throwable $exception, ?string $origin)
18+
{
19+
$this->exception = $exception;
20+
$this->origin = $origin;
21+
}
22+
23+
public static function fromException(\Throwable $exception): self
24+
{
25+
return new self($exception, null);
26+
}
27+
28+
public function withOrigin(string $origin): self
29+
{
30+
return new self($this->exception, $origin);
31+
}
32+
33+
public function getException(): \Throwable
34+
{
35+
return $this->exception;
36+
}
37+
38+
public function getOrigin(): ?string
39+
{
40+
return $this->origin;
41+
}
42+
43+
public function toMessage(): string
44+
{
45+
$messageLines = [];
46+
47+
if ($this->origin) {
48+
$messageLines[] = $this->origin;
49+
}
50+
51+
$level = 0;
52+
$exception = $this->exception;
53+
do {
54+
$level++;
55+
if ($level >= 8) {
56+
$messageLines[] = '...Recursion';
57+
break;
58+
}
59+
60+
$reflexception = new \ReflectionClass($exception);
61+
$shortExceptionName = $reflexception->getShortName();
62+
if ($shortExceptionName === 'Exception') {
63+
$secondPartOfPackageName = explode('\\', $reflexception->getNamespaceName())[1] ?? '';
64+
$shortExceptionName = $secondPartOfPackageName . $shortExceptionName;
65+
}
66+
$messageLines[] = sprintf('%s(%s, %s)', $shortExceptionName, $exception->getMessage(), $exception->getCode());
67+
} while ($exception = $exception->getPrevious());
68+
69+
return join(' | ', $messageLines);
70+
}
71+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
namespace Flowpack\NodeTemplates\Domain\ExceptionHandling;
4+
5+
use Flowpack\NodeTemplates\Domain\ExceptionHandling\CaughtException;
6+
use Neos\Flow\Annotations as Flow;
7+
8+
/** @Flow\Proxy(false) */
9+
class CaughtExceptions implements \IteratorAggregate
10+
{
11+
/** @var array<int, CaughtException> */
12+
private array $exceptions = [];
13+
14+
private function __construct()
15+
{
16+
}
17+
18+
public static function create(): self
19+
{
20+
return new self();
21+
}
22+
23+
public function hasExceptions(): bool
24+
{
25+
return $this->exceptions !== [];
26+
}
27+
28+
public function add(CaughtException $exception): void
29+
{
30+
$this->exceptions[] = $exception;
31+
}
32+
33+
public function first(): ?CaughtException
34+
{
35+
return $this->exceptions[0] ?? null;
36+
}
37+
38+
/**
39+
* @return \Traversable<int, CaughtException>|CaughtException[]
40+
*/
41+
public function getIterator()
42+
{
43+
yield from $this->exceptions;
44+
}
45+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
3+
namespace Flowpack\NodeTemplates\Domain\ExceptionHandling;
4+
5+
use Neos\ContentRepository\Domain\Model\NodeInterface;
6+
use Neos\Flow\Annotations as Flow;
7+
use Neos\Flow\Log\ThrowableStorageInterface;
8+
use Neos\Flow\Log\Utility\LogEnvironment;
9+
use Neos\Neos\Ui\Domain\Model\Feedback\Messages\Error;
10+
use Neos\Neos\Ui\Domain\Model\FeedbackCollection;
11+
use Psr\Log\LoggerInterface;
12+
13+
class ExceptionHandler
14+
{
15+
/**
16+
* @var FeedbackCollection
17+
* @Flow\Inject(lazy=false)
18+
*/
19+
protected $feedbackCollection;
20+
21+
/**
22+
* @var LoggerInterface
23+
* @Flow\Inject
24+
*/
25+
protected $logger;
26+
27+
/**
28+
* @var ThrowableStorageInterface
29+
* @Flow\Inject
30+
*/
31+
protected $throwableStorage;
32+
33+
/**
34+
* @var ExceptionHandlingConfiguration
35+
* @Flow\Inject
36+
*/
37+
protected $configuration;
38+
39+
public function handleAfterTemplateConfigurationProcessing(CaughtExceptions $caughtExceptions, NodeInterface $node): void
40+
{
41+
if (!$caughtExceptions->hasExceptions()) {
42+
return;
43+
}
44+
45+
if (!$this->configuration->shouldStopOnExceptionAfterTemplateConfigurationProcessing()) {
46+
return;
47+
}
48+
49+
$templateNotCreatedException = new TemplateNotCreatedException(
50+
sprintf('Template for "%s" was not applied. Only %s was created.', $node->getNodeType()->getLabel(), (string)$node),
51+
1686135532992,
52+
$caughtExceptions->first()->getException(),
53+
);
54+
55+
$this->logCaughtExceptions($caughtExceptions, $templateNotCreatedException);
56+
57+
throw $templateNotCreatedException;
58+
}
59+
60+
public function handleAfterNodeCreation(CaughtExceptions $caughtExceptions, NodeInterface $node): void
61+
{
62+
if (!$caughtExceptions->hasExceptions()) {
63+
return;
64+
}
65+
66+
$templatePartiallyCreatedException = new TemplatePartiallyCreatedException(
67+
sprintf('Template for "%s" only partially applied. Please check the newly created nodes beneath %s.', $node->getNodeType()->getLabel(), (string)$node),
68+
1686135564160,
69+
$caughtExceptions->first()->getException(),
70+
);
71+
72+
$this->logCaughtExceptions($caughtExceptions, $templatePartiallyCreatedException);
73+
74+
throw $templatePartiallyCreatedException;
75+
}
76+
77+
/**
78+
* @param TemplateNotCreatedException|TemplatePartiallyCreatedException $templateCreationException
79+
*/
80+
private function logCaughtExceptions(CaughtExceptions $caughtExceptions, \DomainException $templateCreationException): void
81+
{
82+
$messages = [];
83+
foreach ($caughtExceptions as $index => $caughtException) {
84+
$messages[sprintf('CaughtException (%s)', $index)] = $caughtException->toMessage();
85+
}
86+
87+
// log exception
88+
$messageWithReference = $this->throwableStorage->logThrowable($templateCreationException, $messages);
89+
$this->logger->warning($messageWithReference, LogEnvironment::fromMethodName(__METHOD__));
90+
91+
// neos ui logging
92+
$nodeTemplateError = new Error();
93+
$nodeTemplateError->setMessage($templateCreationException->getMessage());
94+
95+
$this->feedbackCollection->add(
96+
$nodeTemplateError
97+
);
98+
99+
foreach ($messages as $message) {
100+
$error = new Error();
101+
$error->setMessage($message);
102+
$this->feedbackCollection->add(
103+
$error
104+
);
105+
}
106+
}
107+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Flowpack\NodeTemplates\Domain\ExceptionHandling;
4+
5+
use Neos\Flow\Annotations as Flow;
6+
7+
class ExceptionHandlingConfiguration
8+
{
9+
/**
10+
* @Flow\InjectConfiguration(package="Flowpack.NodeTemplates", path="exceptionHandling")
11+
*/
12+
protected array $exceptionHandlingConfiguration;
13+
14+
public function shouldStopOnExceptionAfterTemplateConfigurationProcessing(): bool
15+
{
16+
return $this->exceptionHandlingConfiguration['templateConfigurationProcessing']['stopOnException'] ?? false;
17+
}
18+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Flowpack\NodeTemplates\Domain\ExceptionHandling;
4+
5+
/**
6+
* Thrown if the templateConfigurationProcessing was unsuccessful (due to an invalid EEL expression f.x),
7+
* and the {@see ExceptionHandlingConfiguration} is configured not to continue
8+
*/
9+
class TemplateNotCreatedException extends \DomainException
10+
{
11+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace Flowpack\NodeTemplates\Domain\ExceptionHandling;
4+
5+
/**
6+
* Thrown in the following cases:
7+
* - the templateConfigurationProcessing was unsuccessful (due to an invalid EEL expression f.x)
8+
* - the nodeCreation was unsuccessful (f.x. due to constrains from the cr)
9+
*/
10+
class TemplatePartiallyCreatedException extends \DomainException
11+
{
12+
}

0 commit comments

Comments
 (0)