Skip to content

Commit aacc7f3

Browse files
authored
Merge pull request #25 from Flowpack/task-merge-1.x
TASK: Merge 1.x branch
2 parents f2ab47f + 37c701b commit aacc7f3

File tree

7 files changed

+121
-20
lines changed

7 files changed

+121
-20
lines changed

Classes/Core/Infrastructure/ContentReleaseLogger.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -49,22 +49,22 @@ public static function fromSymfonyOutput(OutputInterface $output, ContentRelease
4949

5050
public function debug($message, array $additionalPayload = [])
5151
{
52-
$this->output->writeln($this->logPrefix . $message . json_encode($additionalPayload));
52+
$this->output->writeln($this->logPrefix . 'DEBUG ' . $message . ($additionalPayload ? ' ' . json_encode($additionalPayload) : ''));
5353
}
5454

5555
public function info($message, array $additionalPayload = [])
5656
{
57-
$this->output->writeln($this->logPrefix . $message . json_encode($additionalPayload));
57+
$this->output->writeln($this->logPrefix . 'INFO ' . $message . ($additionalPayload ? ' ' . json_encode($additionalPayload) : ''));
5858
}
5959

6060
public function warn($message, array $additionalPayload = [])
6161
{
62-
$this->output->writeln($this->logPrefix . $message . json_encode($additionalPayload));
62+
$this->output->writeln($this->logPrefix . 'WARN ' . $message . ($additionalPayload ? ' ' . json_encode($additionalPayload) : ''));
6363
}
6464

6565
public function error($message, array $additionalPayload = [])
6666
{
67-
$this->output->writeln($this->logPrefix . $message . json_encode($additionalPayload));
67+
$this->output->writeln($this->logPrefix . 'ERROR ' . $message . ($additionalPayload ? ' ' . json_encode($additionalPayload) : ''));
6868
}
6969

7070
public function logException(\Exception $exception, string $message, array $additionalPayload)

Classes/NodeEnumeration/Domain/Dto/EnumeratedNode.php

+20-10
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,24 @@ final class EnumeratedNode implements \JsonSerializable
3434
*/
3535
protected $arguments;
3636

37-
private function __construct(string $contextPath, string $nodeIdentifier, array $arguments)
37+
/**
38+
* The node type name
39+
*
40+
* @var string
41+
*/
42+
protected $nodeTypeName;
43+
44+
private function __construct(string $contextPath, string $nodeIdentifier, string $nodeTypeName, array $arguments)
3845
{
3946
$this->contextPath = $contextPath;
4047
$this->nodeIdentifier = $nodeIdentifier;
48+
$this->nodeTypeName = $nodeTypeName;
4149
$this->arguments = $arguments;
4250
}
4351

44-
45-
static public function fromNode(NodeInterface $node): self
52+
static public function fromNode(NodeInterface $node, array $arguments = []): self
4653
{
47-
return new self($node->getContextPath(), $node->getIdentifier(), []);
54+
return new self($node->getContextPath(), $node->getIdentifier(), $node->getNodeType()->getName(), $arguments);
4855
}
4956

5057
static public function fromJsonString(string $enumeratedNodeString): self
@@ -53,14 +60,15 @@ static public function fromJsonString(string $enumeratedNodeString): self
5360
if (!is_array($tmp)) {
5461
throw new \Exception('EnumeratedNode cannot be constructed from: ' . $enumeratedNodeString);
5562
}
56-
return new self($tmp['contextPath'], $tmp['nodeIdentifier'], $tmp['arguments']);
63+
return new self($tmp['contextPath'], $tmp['nodeIdentifier'], $tmp['nodeTypeName'] ?? '', $tmp['arguments']);
5764
}
5865

5966
public function jsonSerialize()
6067
{
6168
return [
6269
'contextPath' => $this->contextPath,
6370
'nodeIdentifier' => $this->nodeIdentifier,
71+
'nodeTypeName' => $this->nodeTypeName,
6472
'arguments' => $this->arguments
6573
];
6674
}
@@ -80,21 +88,23 @@ public function getDimensionsFromContextPath(): array
8088
return $nodePathAndContext['dimensions'];
8189
}
8290

83-
/**
84-
* @return string
85-
*/
8691
public function getNodeIdentifier(): string
8792
{
8893
return $this->nodeIdentifier;
8994
}
9095

96+
public function getNodeTypeName(): string
97+
{
98+
return $this->nodeTypeName;
99+
}
100+
91101
public function getArguments(): array
92102
{
93103
return $this->arguments;
94104
}
95105

96106
public function debugString(): string
97107
{
98-
return sprintf('Node %s (%s)', $this->nodeIdentifier, $this->contextPath);
108+
return sprintf('%s %s %s(%s)', $this->nodeTypeName, $this->nodeIdentifier, $this->arguments ? http_build_query($this->arguments) . ' ' : '', $this->contextPath);
99109
}
100-
}
110+
}

Classes/NodeEnumeration/NodeEnumerator.php

+18
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ public function enumerateAndStoreInRedis(?Site $site, ContentReleaseLogger $cont
6666
// TODO: EXTENSION POINT HERE, TO ADD ADDITIONAL ENUMERATIONS (.metadata.json f.e.)
6767
// TODO: not yet fully sure how to handle Enumeration
6868
$this->redisEnumerationRepository->addDocumentNodesToEnumeration($releaseIdentifier, ...$enumeration);
69+
foreach ($enumeration as $enumeratedNode) {
70+
$this->emitNodeEnumerated($enumeratedNode, $releaseIdentifier, $contentReleaseLogger);
71+
}
6972
}
7073
}
7174

@@ -119,4 +122,19 @@ private function enumerateAll(?Site $site, ContentReleaseLogger $contentReleaseL
119122
}
120123
}
121124

125+
/**
126+
* A node was enumerated for a new content release.
127+
*
128+
* This signal can be used to add additional EnumeratedNode entries (e.g. with added arguments for pagination or filters) based on the given node.
129+
*
130+
* @param EnumeratedNode $enumeratedNode
131+
* @param ContentReleaseIdentifier $releaseIdentifier
132+
* @param ContentReleaseLogger $contentReleaseLogger
133+
* @return void
134+
* @Flow\Signal
135+
*/
136+
protected function emitNodeEnumerated(EnumeratedNode $enumeratedNode, ContentReleaseIdentifier $releaseIdentifier, ContentReleaseLogger $contentReleaseLogger)
137+
{
138+
}
139+
122140
}

Classes/NodeRendering/Render/DocumentRenderer.php

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
2+
23
namespace Flowpack\DecoupledContentStore\NodeRendering\Render;
4+
35
use Flowpack\DecoupledContentStore\Aspects\CacheUrlMappingAspect;
46
use Flowpack\DecoupledContentStore\Exception;
57
use Flowpack\DecoupledContentStore\Core\Infrastructure\ContentReleaseLogger;
@@ -154,7 +156,7 @@ protected function buildControllerContextAndSetBaseUri(string $uri, NodeInterfac
154156
return new ControllerContext(
155157
$request,
156158
new ActionResponse(),
157-
new Arguments(array()),
159+
new Arguments([]),
158160
$uriBuilder
159161
);
160162
}
@@ -227,7 +229,7 @@ protected function renderDocumentView(NodeInterface $node, $uri, array $requestA
227229
);
228230
}
229231

230-
$contentReleaseLogger->debug('Rendering document for URI ' . $uri, ['baseUri' => $baseUri]);
232+
$contentReleaseLogger->info('Rendering document for URI ' . $uri, ['baseUri' => $baseUri]);
231233

232234
$controllerContext = $this->buildControllerContextAndSetBaseUri($uri, $node, $requestArguments);
233235
/** @var ActionRequest $request */
@@ -285,18 +287,24 @@ private static function wrapInHttpMessage(string $output, ActionResponse $respon
285287
* @param NodeInterface $node
286288
* @param array $arguments
287289
* @return string The resolved URI for the given node
290+
* @throws \Exception
288291
*/
289292
protected function buildNodeUri(NodeInterface $node, array $arguments)
290293
{
291294
/** @var Site $currentSite */
292295
$currentSite = $node->getContext()->getCurrentSite();
293296
if (!$currentSite->hasActiveDomains()) {
294-
throw new \Exception("No configured domain!");
297+
throw new Exception(sprintf("Site %s has no active domain", $currentSite->getNodeName()), 1666684522);
295298
}
299+
$primaryDomain = $currentSite->getPrimaryDomain();
300+
if ((string)$primaryDomain->getScheme() === '') {
301+
throw new Exception(sprintf("Domain %s for site %s has no scheme defined", $primaryDomain->getHostname(), $currentSite->getNodeName()), 1666684523);
302+
}
303+
296304
// HINT: We cannot use a static URL here, but instead need to use an URL of the current site.
297305
// This is changed from the the old behavior, where we have changed the LinkingService in LinkingServiceAspect,
298306
// to properly generate the domain part of the routes - and this relies on the proper ControllerContext URI path.
299-
$baseControllerContext = $this->buildControllerContextAndSetBaseUri($currentSite->getPrimaryDomain()->__toString(), $node, $arguments);
307+
$baseControllerContext = $this->buildControllerContextAndSetBaseUri($primaryDomain->__toString(), $node, $arguments);
300308
$format = $arguments['@format'] ?? 'html';
301309
$uri = $this->linkingService->createNodeUri($baseControllerContext, $node, null, $format, true, $arguments, '', false, [], false);
302310
return $this->removeQueryPartFromUri($uri);

Classes/Utility/GeneratorUtility.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
class GeneratorUtility
66
{
77

8+
/**
9+
* @template T
10+
* @param iterable<T> $iterable
11+
* @param int $chunkSize
12+
* @return iterable<array<T>>
13+
*/
814
static public function createArrayBatch(iterable $iterable, int $chunkSize): iterable
915
{
1016
$accumulator = [];
@@ -24,4 +30,4 @@ static public function createArrayBatch(iterable $iterable, int $chunkSize): ite
2430
yield $accumulator;
2531
}
2632
}
27-
}
33+
}

README.md

+58
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,64 @@ Flowpack:
338338
This is needed so that the system knows which keys should be synchronized between the different content stores,
339339
and what data to delete if a release is removed.
340340

341+
### Rendering additional nodes with arguments (e.g. pagination or filters)
342+
343+
If you render a paginated list or have filters (with a predictable list of values) that can be
344+
added to a document via arguments, you can implement a slot for the `nodeEnumerated` signal to enumerate additional
345+
nodes with arguments.
346+
347+
> **Note:** Request arguments must be mapped to URIs via custom routes, since we do not support HTTP query parameters for rendered documents.
348+
349+
#### Example
350+
351+
Add a slot for the `nodeEnumerated` signal via `Package.php`:
352+
353+
```php
354+
<?php
355+
class Package extends BasePackage
356+
{
357+
public function boot(Bootstrap $bootstrap)
358+
{
359+
$dispatcher = $bootstrap->getSignalSlotDispatcher();
360+
361+
$dispatcher->connect(NodeEnumerator::class, 'nodeEnumerated', MyNodeListsEnumerator::class, 'enumerateNodeLists');
362+
}
363+
}
364+
```
365+
366+
Implement the slot and enumerate additional nodes depending on the node type:
367+
368+
```php
369+
<?php
370+
class NodeListsEnumerator
371+
{
372+
public function enumerateNodeLists(EnumeratedNode $enumeratedNode, ContentReleaseIdentifier $releaseIdentifier, ContentReleaseLogger $logger)
373+
{
374+
$nodeTypeName = $enumeratedNode->getNodeTypeName();
375+
$nodeType = $this->nodeTypeManager->getNodeType($nodeTypeName);
376+
if ($nodeType->isOfType('Vendor.Site:Document.Blog.Folder')) {
377+
// Get the node and count the number of pages to render
378+
// $pageCount = ...
379+
380+
$pageCount = ceil($postCount / (float)$this->perPage);
381+
if ($pageCount <= 1) {
382+
return;
383+
}
384+
385+
// Start after the first page, because the first page will be the document without arguments
386+
for ($page = 2; $page <= $pageCount; $page++) {
387+
$enumeratedNodes[] = EnumeratedNode::fromNode($documentNode, ['page' => $page]);
388+
}
389+
390+
$this->redisEnumerationRepository->addDocumentNodesToEnumeration($releaseIdentifier, ...$enumeratedNodes);
391+
}
392+
}
393+
}
394+
```
395+
396+
The actual logic will depend on your use of the node. Having the actual filtering logic implemented in PHP is
397+
beneficial, because it allows you to use it in the rendering process as well as in the additional enumeration.
398+
341399
### Extending the backend module
342400

343401
- You need a Views.yaml in your package, looking like this:

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
2-
"description": "",
2+
"description": "This is the 2nd generation of a Two-Stack CMS package for Neos.",
33
"type": "neos-package",
4+
"license": "GPL-3.0-or-later",
45
"name": "flowpack/decoupledcontentstore",
56
"require": {
67
"php": "^7.4 || ^8.0",

0 commit comments

Comments
 (0)