diff --git a/UPGRADE.md b/UPGRADE.md
index c9e93846..337aa159 100644
--- a/UPGRADE.md
+++ b/UPGRADE.md
@@ -1,5 +1,8 @@
# Upgrade Notes
+## 5.2.0
+- [NEW FEATURE] Add element hash to headless stack
+
## 5.1.2
- [BUGFIX] Enriched injected JS `toolbox-wysiwyg-document-style.js` with toolbox document id param [#223](https://github.com/dachcom-digital/pimcore-toolbox/issues/223)
diff --git a/src/Document/Editable/EditableJsonSubscriber.php b/src/Document/Editable/EditableJsonSubscriber.php
index 9db2b5ad..40c6ec85 100644
--- a/src/Document/Editable/EditableJsonSubscriber.php
+++ b/src/Document/Editable/EditableJsonSubscriber.php
@@ -13,6 +13,7 @@ final class EditableJsonSubscriber implements EventSubscriberInterface
protected const ELEMENTS_IDENTIFIER = 'elements';
protected const ELEMENT_TYPE_IDENTIFIER = 'elementType';
protected const ELEMENT_SUB_TYPE_IDENTIFIER = 'elementSubType';
+ protected const ELEMENT_HASH = 'elementHash';
protected const ELEMENT_DATA_IDENTIFIER = 'elementContext';
protected array $jsonEditables = [];
@@ -26,7 +27,7 @@ public static function getSubscribedEvents(): array
public function onHeadlessElementAdd(HeadlessElementEvent $event): void
{
- $this->jsonEditables[$event->getElementNamespace()] = [$event->getElementType(), $event->getElementSubType(), $event->getData()];
+ $this->jsonEditables[$event->getElementNamespace()] = [$event->getElementType(), $event->getElementSubType(), $event->getElementHash(), $event->getData()];
}
public function getJsonEditables(): array
@@ -59,7 +60,8 @@ private function convertNestedArray($flatArray): array
$currentArray[self::ELEMENT_TYPE_IDENTIFIER] = $value[0];
$currentArray[self::ELEMENT_SUB_TYPE_IDENTIFIER] = $value[1];
- $currentArray[self::ELEMENT_DATA_IDENTIFIER] = $value[2];
+ $currentArray[self::ELEMENT_HASH] = $value[2];
+ $currentArray[self::ELEMENT_DATA_IDENTIFIER] = $value[3];
}
/** @phpstan-ignore-next-line */
diff --git a/src/Document/Editable/EditableWorker.php b/src/Document/Editable/EditableWorker.php
index e217dedd..32c0ec51 100644
--- a/src/Document/Editable/EditableWorker.php
+++ b/src/Document/Editable/EditableWorker.php
@@ -30,6 +30,7 @@ public function processBrick(HeadlessResponse $data, AreabrickInterface $areabri
$this->dispatch([
'elementType' => $data->getType(),
'elementSubType' => $areabrick->getId(),
+ 'elementHash' => $this->buildBrickHash(),
'elementNamespace' => $this->buildBrickNamespace(),
'data' => $this->processBrickData($data, $areabrick->getId())
]);
@@ -40,11 +41,38 @@ public function processEditable(HeadlessResponse $data, Editable $editable): voi
$this->dispatch([
'elementType' => $data->getType(),
'elementSubType' => $editable->getType(),
+ 'elementHash' => $this->buildEditableHash($editable),
'elementNamespace' => $this->buildEditableNamespace($editable),
'data' => $this->processEditableData($data)
]);
}
+ public function processVirtualElement(string $type, string $subType, string $hash, string $namespace): void
+ {
+ $this->dispatch([
+ 'elementType' => $type,
+ 'elementSubType' => $subType,
+ 'elementHash' => $hash,
+ 'elementNamespace' => $namespace,
+ 'data' => []
+ ]);
+ }
+
+ public function buildBrickHash(): string
+ {
+ return hash('xxh3', sprintf('element_hash_%s', str_replace([':', '.'], '_', $this->buildBrickNamespace())));
+ }
+
+ public function buildEditableHash(Editable $editable): string
+ {
+ return hash('xxh3', sprintf('element_hash_%s', str_replace([':', '.'], '_', $editable->getName())));
+ }
+
+ public function buildBlockHash(string $blockName, int $blockIndex): string
+ {
+ return hash('xxh3', sprintf('element_hash_%s_%d', $blockName, $blockIndex));
+ }
+
private function dispatch(array $arguments): void
{
$this->eventDispatcher->dispatch(
diff --git a/src/Document/Editable/HeadlessEditableRenderer.php b/src/Document/Editable/HeadlessEditableRenderer.php
index 8b45e8c6..807c0bc4 100644
--- a/src/Document/Editable/HeadlessEditableRenderer.php
+++ b/src/Document/Editable/HeadlessEditableRenderer.php
@@ -21,12 +21,24 @@ public function __construct(
public function renderBrickWithWrapper(array $contentBlocks): string
{
- return sprintf('
%s
', implode(PHP_EOL, $contentBlocks));
+ $brickHash = $this->editableWorker->buildBrickHash();
+
+ return sprintf(
+ '%s
',
+ $brickHash,
+ implode(PHP_EOL, $contentBlocks)
+ );
}
- public function renderStandaloneEditableWithWrapper(string $contentBlock): string
+ public function renderStandaloneEditableWithWrapper(string $contentBlock, Editable $editable): string
{
- return sprintf('%s
', $contentBlock);
+ $editableHash = $this->editableWorker->buildEditableHash($editable);
+
+ return sprintf(
+ '%s
',
+ $editableHash,
+ $contentBlock
+ );
}
public function renderEditableWithWrapper(string $type, array $viewParameters): string
@@ -52,7 +64,7 @@ public function buildEditable(HeadlessEditableInfo $headlessEditableInfo): Edita
private function buildStandardEditable(HeadlessEditableInfo $headlessEditableInfo): Editable|string|array
{
- return $this->processEditable($headlessEditableInfo);
+ return $this->processEditable($headlessEditableInfo, $this->getEditable($headlessEditableInfo));
}
private function buildColumnEditable(HeadlessEditableInfo $headlessEditableInfo): string|array
@@ -72,13 +84,14 @@ private function buildColumnEditable(HeadlessEditableInfo $headlessEditableInfo)
foreach ($headlessEditableInfo->getChildren() as $headlessColumnEditableInfo) {
$areaBlockDataResponse = null;
+ $editable = $this->getEditable($headlessEditableInfo);
ob_start();
- echo $this->processEditable($headlessColumnEditableInfo, true);
+ echo $this->processEditable($headlessColumnEditableInfo, $editable, true);
if ($editMode === false) {
- $areaBlockDataResponse = $this->processEditable($headlessColumnEditableInfo);
+ $areaBlockDataResponse = $this->processEditable($headlessColumnEditableInfo, $editable);
}
$areaBlockHtmlResponse = ob_get_clean();
@@ -100,13 +113,14 @@ private function buildAreaEditable(HeadlessEditableInfo $headlessEditableInfo):
{
$areaDataResponse = '';
$editMode = $headlessEditableInfo->isEditMode();
+ $editable = $this->getEditable($headlessEditableInfo);
ob_start();
- echo $this->processEditable($headlessEditableInfo, true);
+ echo $this->processEditable($headlessEditableInfo, $editable, true);
if ($editMode === false) {
- $areaDataResponse = $this->processEditable($headlessEditableInfo);
+ $areaDataResponse = $this->processEditable($headlessEditableInfo, $editable);
}
$areaHtmlResponse = ob_get_clean();
@@ -118,13 +132,14 @@ private function buildAreaBlockEditable(HeadlessEditableInfo $headlessEditableIn
{
$areaBlockDataResponse = '';
$editMode = $headlessEditableInfo->isEditMode();
+ $editable = $this->getEditable($headlessEditableInfo);
ob_start();
- echo $this->processEditable($headlessEditableInfo, true);
+ echo $this->processEditable($headlessEditableInfo, $editable, true);
if ($editMode === false) {
- $areaBlockDataResponse = $this->processEditable($headlessEditableInfo);
+ $areaBlockDataResponse = $this->processEditable($headlessEditableInfo, $editable);
}
$areaBlockHtmlResponse = ob_get_clean();
@@ -145,11 +160,23 @@ private function buildBlockEditable(HeadlessEditableInfo $headlessEditableInfo):
$blockEditable = $this->editableRenderer->getEditable($document, 'block', $headlessEditableInfo->getName(), $config, $headlessEditableInfo->isEditMode());
foreach ($blockEditable->getIterator() as $blockIndex) {
+
+ $blockHash = $this->editableWorker->buildBlockHash($headlessEditableInfo->getName(), $blockIndex);
+ $blockNamespace = sprintf('%s:%s', $headlessEditableInfo->getName(), $blockIndex);
+
+ if ($editMode === true) {
+ echo sprintf('', $blockHash);
+ }
+
+ $this->editableWorker->processVirtualElement(HeadlessResponse::TYPE_EDITABLE, 'block', $blockHash, $blockNamespace);
+
foreach ($headlessEditableInfo->getChildren() as $childHeadlessEditableInfo) {
+ $editable = $this->getEditable($childHeadlessEditableInfo);
+
ob_start();
- echo $this->processEditable($childHeadlessEditableInfo, true);
+ echo $this->processEditable($childHeadlessEditableInfo, $editable, true);
$renderedBlockEditable = ob_get_clean();
@@ -162,7 +189,7 @@ private function buildBlockEditable(HeadlessEditableInfo $headlessEditableInfo):
]);
if ($editMode === false) {
- $data[] = $this->processEditable($childHeadlessEditableInfo);
+ $data[] = $this->processEditable($childHeadlessEditableInfo, $editable);
}
}
}
@@ -172,18 +199,12 @@ private function buildBlockEditable(HeadlessEditableInfo $headlessEditableInfo):
return $editMode ? $areaBlockHtmlResponse : $data;
}
- private function processEditable(HeadlessEditableInfo $headlessEditableInfo, bool $forceRendering = false): mixed
+ private function processEditable(HeadlessEditableInfo $headlessEditableInfo, Editable $editable, bool $forceRendering = false): mixed
{
$editMode = $headlessEditableInfo->isEditMode();
$type = $headlessEditableInfo->getType();
- $name = $headlessEditableInfo->getName();
- $config = $headlessEditableInfo->getConfig();
- $document = $headlessEditableInfo->getDocument();
$isSimple = !$headlessEditableInfo->isBlockEditable();
- /** @var Editable $editable */
- $editable = $this->editableRenderer->getEditable($document, $type, $name, $config, $editMode);
-
if ($headlessEditableInfo->isStandAlone() === true) {
if ($editMode === false) {
@@ -217,4 +238,18 @@ private function processEditable(HeadlessEditableInfo $headlessEditableInfo, boo
return '';
}
+
+ public function getEditable(HeadlessEditableInfo $headlessEditableInfo): Editable
+ {
+ $editMode = $headlessEditableInfo->isEditMode();
+ $type = $headlessEditableInfo->getType();
+ $name = $headlessEditableInfo->getName();
+ $config = $headlessEditableInfo->getConfig();
+ $document = $headlessEditableInfo->getDocument();
+
+ /** @var Editable $editable */
+ $editable = $this->editableRenderer->getEditable($document, $type, $name, $config, $editMode);
+
+ return $editable;
+ }
}
diff --git a/src/Event/HeadlessElementEvent.php b/src/Event/HeadlessElementEvent.php
index 79d6f601..7b4b4297 100644
--- a/src/Event/HeadlessElementEvent.php
+++ b/src/Event/HeadlessElementEvent.php
@@ -10,6 +10,7 @@ public function __construct(
protected array $data,
protected string $elementType,
protected string $elementSubType,
+ protected ?string $elementHash,
protected string $elementNamespace
) {
}
@@ -29,6 +30,11 @@ public function getElementSubType(): string
return $this->elementSubType;
}
+ public function getElementHash(): ?string
+ {
+ return $this->elementHash;
+ }
+
public function getElementNamespace(): string
{
return $this->elementNamespace;
diff --git a/src/HeadlessDocument/HeadlessDocumentResolver.php b/src/HeadlessDocument/HeadlessDocumentResolver.php
index 9e923d1d..14f3f4ed 100644
--- a/src/HeadlessDocument/HeadlessDocumentResolver.php
+++ b/src/HeadlessDocument/HeadlessDocumentResolver.php
@@ -67,6 +67,7 @@ private function buildEditModeOutput(Document $document, string $headlessDocumen
$headlessInfo = $this->editableInfoFactory->createViaEditable($document, $itemName, true, $item);
$renderedEditable = $this->headlessEditableRenderer->buildEditable($headlessInfo);
+ $editable = $this->headlessEditableRenderer->getEditable($headlessInfo);
if (in_array($headlessInfo->getType(), ['areablock', 'area'])) {
// will be rendered within brick process workflow
@@ -76,7 +77,8 @@ private function buildEditModeOutput(Document $document, string $headlessDocumen
$this->headlessEditableRenderer->renderEditableWithWrapper($item['type'], [
'item' => $item,
'editable' => $renderedEditable
- ])
+ ]),
+ $editable
);
}