Skip to content

Commit 314536e

Browse files
committed
TASK: Extract logic into ExceptionHandler
1 parent d11d513 commit 314536e

11 files changed

+179
-128
lines changed

Classes/Domain/ExceptionHandling/CaughtExceptions.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ public function add(CaughtException $exception): void
3030
$this->exceptions[] = $exception;
3131
}
3232

33+
public function first(): ?CaughtException
34+
{
35+
return $this->exceptions[0] ?? null;
36+
}
37+
3338
/**
3439
* @return \Traversable<int, CaughtException>|CaughtException[]
3540
*/
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
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+
* @Flow\Inject
35+
*/
36+
protected ExceptionHandlingConfiguration $configuration;
37+
38+
public function handleAfterTemplateConfigurationProcessing(CaughtExceptions $caughtExceptions, NodeInterface $node): void
39+
{
40+
if (!$caughtExceptions->hasExceptions()) {
41+
return;
42+
}
43+
44+
if (!$this->configuration->shouldStopOnExceptionAfterTemplateConfigurationProcessing()) {
45+
return;
46+
}
47+
48+
$templateNotCreatedException = new TemplateNotCreatedException(
49+
sprintf('Template for "%s" was not applied. Only %s was created.', $node->getNodeType()->getLabel(), (string)$node),
50+
1686135532992,
51+
$caughtExceptions->first()->getException(),
52+
);
53+
54+
$this->logCaughtExceptions($caughtExceptions, $templateNotCreatedException);
55+
56+
throw $templateNotCreatedException;
57+
}
58+
59+
public function handleAfterNodeCreation(CaughtExceptions $caughtExceptions, NodeInterface $node): void
60+
{
61+
if (!$caughtExceptions->hasExceptions()) {
62+
return;
63+
}
64+
65+
$templatePartiallyCreatedException = new TemplatePartiallyCreatedException(
66+
sprintf('Template for "%s" only partially applied. Please check the newly created nodes beneath %s.', $node->getNodeType()->getLabel(), (string)$node),
67+
1686135564160,
68+
$caughtExceptions->first()->getException(),
69+
);
70+
71+
$this->logCaughtExceptions($caughtExceptions, $templatePartiallyCreatedException);
72+
73+
throw $templatePartiallyCreatedException;
74+
}
75+
76+
/**
77+
* @param TemplateNotCreatedException|TemplatePartiallyCreatedException $templateCreationException
78+
*/
79+
private function logCaughtExceptions(CaughtExceptions $caughtExceptions, \DomainException $templateCreationException): void
80+
{
81+
$messages = [];
82+
foreach ($caughtExceptions as $index => $caughtException) {
83+
$messages[sprintf('CaughtException (%s)', $index)] = $caughtException->toMessage();
84+
}
85+
86+
// log exception
87+
$messageWithReference = $this->throwableStorage->logThrowable($templateCreationException, $messages);
88+
$this->logger->warning($messageWithReference, LogEnvironment::fromMethodName(__METHOD__));
89+
90+
// neos ui logging
91+
$nodeTemplateError = new Error();
92+
$nodeTemplateError->setMessage($templateCreationException->getMessage());
93+
94+
$this->feedbackCollection->add(
95+
$nodeTemplateError
96+
);
97+
98+
foreach ($messages as $message) {
99+
$error = new Error();
100+
$error->setMessage($message);
101+
$this->feedbackCollection->add(
102+
$error
103+
);
104+
}
105+
}
106+
}
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+
}

Classes/Domain/ExceptionHandling/ExceptionHandlingStrategy.php

Lines changed: 0 additions & 34 deletions
This file was deleted.
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+
}

Classes/Domain/ExceptionHandling/TemplatePartiallyAppliedException.php

Lines changed: 0 additions & 7 deletions
This file was deleted.
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+
}

Classes/Domain/TemplateNodeCreationHandler.php

Lines changed: 13 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,34 @@
33
namespace Flowpack\NodeTemplates\Domain;
44

55
use Flowpack\NodeTemplates\Domain\ExceptionHandling\CaughtExceptions;
6-
use Flowpack\NodeTemplates\Domain\ExceptionHandling\ExceptionHandlingStrategy;
7-
use Flowpack\NodeTemplates\Domain\ExceptionHandling\TemplatePartiallyAppliedException;
8-
use Flowpack\NodeTemplates\Domain\TemplateConfiguration\TemplateConfigurationProcessor;
6+
use Flowpack\NodeTemplates\Domain\ExceptionHandling\ExceptionHandler;
7+
use Flowpack\NodeTemplates\Domain\ExceptionHandling\TemplateNotCreatedException;
8+
use Flowpack\NodeTemplates\Domain\ExceptionHandling\TemplatePartiallyCreatedException;
99
use Flowpack\NodeTemplates\Domain\NodeCreation\NodeCreationService;
10+
use Flowpack\NodeTemplates\Domain\TemplateConfiguration\TemplateConfigurationProcessor;
1011
use Neos\ContentRepository\Domain\Model\NodeInterface;
1112
use Neos\Flow\Annotations as Flow;
12-
use Neos\Flow\Log\ThrowableStorageInterface;
13-
use Neos\Flow\Log\Utility\LogEnvironment;
14-
use Neos\Neos\Ui\Domain\Model\Feedback\Messages\Error;
15-
use Neos\Neos\Ui\Domain\Model\FeedbackCollection;
1613
use Neos\Neos\Ui\NodeCreationHandler\NodeCreationHandlerInterface;
17-
use Psr\Log\LoggerInterface;
1814

1915
class TemplateNodeCreationHandler implements NodeCreationHandlerInterface
2016
{
2117
/**
2218
* @var TemplateConfigurationProcessor
2319
* @Flow\Inject
2420
*/
25-
protected $templateFactory;
21+
protected $templateConfigurationProcessor;
2622

2723
/**
2824
* @var NodeCreationService
2925
* @Flow\Inject
3026
*/
31-
protected $contentRepositoryTemplateHandler;
27+
protected $nodeCreationService;
3228

3329
/**
34-
* @var FeedbackCollection
35-
* @Flow\Inject(lazy=false)
36-
*/
37-
protected $feedbackCollection;
38-
39-
/**
40-
* @var LoggerInterface
30+
* @var ExceptionHandler
4131
* @Flow\Inject
4232
*/
43-
protected $logger;
44-
45-
/**
46-
* @var ThrowableStorageInterface
47-
* @Flow\Inject
48-
*/
49-
protected $throwableStorage;
50-
51-
/**
52-
* @Flow\InjectConfiguration(package="Flowpack.NodeTemplates", path="exceptionHandlingStrategy")
53-
*/
54-
public array $exceptionHandlingStrategyConfiguration;
33+
protected $exceptionHandler;
5534

5635
/**
5736
* Create child nodes and change properties upon node creation
@@ -72,55 +51,14 @@ public function handle(NodeInterface $node, array $data): void
7251

7352
$templateConfiguration = $node->getNodeType()->getConfiguration('options.template');
7453

75-
$exceptionHandlingStrategy = ExceptionHandlingStrategy::fromConfiguration($this->exceptionHandlingStrategyConfiguration);
76-
7754
$caughtExceptions = CaughtExceptions::create();
7855
try {
79-
$template = $this->templateFactory->processTemplateConfiguration($templateConfiguration, $evaluationContext, $caughtExceptions);
80-
if (!$caughtExceptions->hasExceptions() || $exceptionHandlingStrategy->continueWithPartiallyEvaluatedTemplate()) {
81-
$this->contentRepositoryTemplateHandler->apply($template, $node, $caughtExceptions);
82-
}
83-
} finally {
84-
$this->handleCaughtExceptionsForNode($caughtExceptions, $node, $exceptionHandlingStrategy);
85-
}
86-
}
87-
88-
private function handleCaughtExceptionsForNode(CaughtExceptions $caughtExceptions, NodeInterface $node, ExceptionHandlingStrategy $exceptionHandlingStrategy): void
89-
{
90-
if (!$caughtExceptions->hasExceptions()) {
91-
return;
92-
}
93-
94-
$initialMessageInCaseOfException = $exceptionHandlingStrategy->continueWithPartiallyEvaluatedTemplate()
95-
? sprintf('Template for "%s" only partially applied. Please check the newly created nodes beneath %s.', $node->getNodeType()->getLabel(), (string)$node)
96-
: sprintf('Template for "%s" was not applied. Only %s was created.', $node->getNodeType()->getLabel(), (string)$node);
97-
98-
$firstException = null;
99-
$messages = [];
100-
foreach ($caughtExceptions as $index => $caughtException) {
101-
$messages[sprintf('CaughtException (%s)', $index)] = $caughtException->toMessage();
102-
$firstException = $firstException ?? $caughtException->getException();
103-
}
104-
105-
// log exception
106-
$exception = new TemplatePartiallyAppliedException($initialMessageInCaseOfException, 1685880697387, $firstException);
107-
$messageWithReference = $this->throwableStorage->logThrowable($exception, $messages);
108-
$this->logger->warning($messageWithReference, LogEnvironment::fromMethodName(__METHOD__));
109-
110-
// neos ui logging
111-
$nodeTemplateError = new Error();
112-
$nodeTemplateError->setMessage($initialMessageInCaseOfException);
113-
114-
$this->feedbackCollection->add(
115-
$nodeTemplateError
116-
);
56+
$template = $this->templateConfigurationProcessor->processTemplateConfiguration($templateConfiguration, $evaluationContext, $caughtExceptions);
57+
$this->exceptionHandler->handleAfterTemplateConfigurationProcessing($caughtExceptions, $node);
11758

118-
foreach ($messages as $message) {
119-
$error = new Error();
120-
$error->setMessage($message);
121-
$this->feedbackCollection->add(
122-
$error
123-
);
59+
$this->nodeCreationService->apply($template, $node, $caughtExceptions);
60+
$this->exceptionHandler->handleAfterNodeCreation($caughtExceptions, $node);
61+
} catch (TemplateNotCreatedException|TemplatePartiallyCreatedException $templateCreationException) {
12462
}
12563
}
12664
}

Configuration/Settings.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
Flowpack:
22
NodeTemplates:
3-
exceptionHandlingStrategy:
4-
continueWithPartiallyEvaluatedTemplate: true
3+
exceptionHandling:
4+
templateConfigurationProcessing:
5+
stopOnException: false
56

67
defaultEelContext:
78
String: 'Neos\Eel\Helper\StringHelper'

README.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -182,21 +182,20 @@ way around.
182182
183183
## Exception handling, resuming with the next possible operation.
184184
185-
In the first step the configuration is evaluated, all Runtime Exceptions (for example caused in an EEL Expression) are caught, and any malformed parts of the template are ignored (with their errors being logged).
186-
This might lead to a partially evaluated template with some properties or childNodes missing.
185+
In the first step the configuration is processed, exceptions like those caused by an EEL Expression are caught, and any malformed parts of the template are ignored (with their errors being logged).
186+
This might lead to a partially processed template with some properties or childNodes missing.
187187
188-
You can decide via the exception handling strategy `continueWithPartiallyEvaluatedTemplate`, if you want to apply this partially evaluated template `true` or abort the process `false` which will only lead to creating the root node as if there was no template.
189-
190-
The setting is configurable via Settings.yaml in `Flowpack.NodeTemplates.continueWithPartiallyEvaluatedTemplate` it defaults to `true`.
188+
You can decide via the exception handling configuration `Flowpack.NodeTemplates.exceptionHandling`, if you want to start the node creation of this partially processed template (`stopOnException: false`) or abort the process (`stopOnException: true`), which will only lead to creating the root node, ignoring the whole template.
191189

192190
```yaml
193191
Flowpack:
194192
NodeTemplates:
195-
exceptionHandlingStrategy:
196-
continueWithPartiallyEvaluatedTemplate: true
193+
exceptionHandling:
194+
templateConfigurationProcessing:
195+
stopOnException: false
197196
```
198197

199-
In case exceptions are thrown while applying the template like because a node constraint was not met or the `type` field was not set the creation of the childNode is aborted, but we continue with applying the other left over parts of the template.
198+
In case exceptions are thrown in the node creation of the template, because a node constraint was not met or the `type` field was not set, the creation of the childNode is aborted, but we continue with the node creation of the other left over parts of the template.
200199
It behaves similar with properties: In case a property value doesn't match its declared type the exception is logged, but we will try to continue with the next property.
201200

202201
## Create template from node subtree

0 commit comments

Comments
 (0)