Zwischenstand vom 29.05.2026
This commit is contained in:
@@ -3,6 +3,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace Evomedien\Vitec\DataProcessing;
|
||||
|
||||
use Evomedien\Vitec\UserFunc\ProductListJsonRenderer;
|
||||
use Evomedien\Vitec\UserFunc\ProductShowJsonRenderer;
|
||||
use Evomedien\Vitec\UserFunc\UsecaseListJsonRenderer;
|
||||
use Evomedien\Vitec\UserFunc\UsecaseShowJsonRenderer;
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
@@ -15,6 +19,11 @@ use TYPO3\CMS\Frontend\ContentObject\DataProcessorInterface;
|
||||
* { id, type, colPos, sorting, appearance, data }
|
||||
* `data` only contains non-empty content-relevant fields.
|
||||
*
|
||||
* VITEC list-plugins nested as container children (productlist, productshow,
|
||||
* usecaselist, usecaseshow) are resolved to the SAME JSON the top-level
|
||||
* headless rendering produces, injected into `data` under their respective
|
||||
* key. The raw pi_flexform XML is then dropped from `data`.
|
||||
*
|
||||
* Exception-safe.
|
||||
*/
|
||||
final class ContainerChildrenProcessor implements DataProcessorInterface
|
||||
@@ -27,7 +36,6 @@ final class ContainerChildrenProcessor implements DataProcessorInterface
|
||||
|
||||
/** Technical / system / TCA-default fields — never sent to frontend. */
|
||||
private const SYSTEM_FIELDS = [
|
||||
// versioning / language / workspace / housekeeping
|
||||
'pid', 'sys_language_uid', 'l18n_parent', 'l18n_diffsource',
|
||||
'l10n_source', 'l10n_state', 'l10n_parent',
|
||||
't3_origuid', 'tx_impexp_origuid',
|
||||
@@ -38,8 +46,6 @@ final class ContainerChildrenProcessor implements DataProcessorInterface
|
||||
't3ver_id', 't3ver_label', 't3ver_count', 't3ver_tstamp',
|
||||
'editlock', 'sorting_foreign', 'rowDescription',
|
||||
'spaceBefore', 'spaceAfter', // legacy
|
||||
// TCA defaults that TYPO3 always sets on every tt_content row,
|
||||
// regardless of CType — rarely relevant to the frontend:
|
||||
'imagecols', 'sectionIndex', 'linkToTop', 'recursive', 'date',
|
||||
'bullets_type', 'cols',
|
||||
'table_delimiter', 'table_enclosure', 'table_header_position',
|
||||
@@ -53,6 +59,19 @@ final class ContainerChildrenProcessor implements DataProcessorInterface
|
||||
'header_layout',
|
||||
];
|
||||
|
||||
/**
|
||||
* Nested VITEC list-plugins: list_type => [ rendererClass, jsonKey ].
|
||||
* The renderer's renderForRecord() is invoked with the child's own
|
||||
* tt_content row so the result is record-accurate (works with multiple
|
||||
* containers / plugins on the same page).
|
||||
*/
|
||||
private const PLUGIN_RENDERERS = [
|
||||
'vitec_productlist' => [ProductListJsonRenderer::class, 'products'],
|
||||
'vitec_productshow' => [ProductShowJsonRenderer::class, 'product'],
|
||||
'vitec_usecaselist' => [UsecaseListJsonRenderer::class, 'usecases'],
|
||||
'vitec_usecaseshow' => [UsecaseShowJsonRenderer::class, 'usecase'],
|
||||
];
|
||||
|
||||
public function process(
|
||||
ContentObjectRenderer $cObj,
|
||||
array $contentObjectConfiguration,
|
||||
@@ -124,6 +143,9 @@ final class ContainerChildrenProcessor implements DataProcessorInterface
|
||||
$data[$field] = $this->castValue($field, $value);
|
||||
}
|
||||
|
||||
// Resolve nested VITEC list-plugins to their headless JSON.
|
||||
$this->resolvePluginData($record, $data);
|
||||
|
||||
return [
|
||||
'id' => (int)$record['uid'],
|
||||
'type' => (string)$record['CType'],
|
||||
@@ -139,6 +161,48 @@ final class ContainerChildrenProcessor implements DataProcessorInterface
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* If the child is a VITEC list-plugin, run its JSON renderer for THIS
|
||||
* record and inject the decoded result under its key. Drops the raw
|
||||
* pi_flexform XML afterwards. Never throws.
|
||||
*
|
||||
* @param array<string,mixed> $record
|
||||
* @param array<string,mixed> $data
|
||||
*/
|
||||
private function resolvePluginData(array $record, array &$data): void
|
||||
{
|
||||
$listType = (string)($record['list_type'] ?? '');
|
||||
if ($listType === '' || !isset(self::PLUGIN_RENDERERS[$listType])) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
[$rendererClass, $jsonKey] = self::PLUGIN_RENDERERS[$listType];
|
||||
$renderer = GeneralUtility::makeInstance($rendererClass);
|
||||
|
||||
if (!method_exists($renderer, 'renderForRecord')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$json = $renderer->renderForRecord($record);
|
||||
if ($json === '' || $json === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$decoded = json_decode($json, true);
|
||||
if ($decoded === null && json_last_error() !== JSON_ERROR_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data[$jsonKey] = $decoded;
|
||||
|
||||
// The raw FlexForm XML is noise once the plugin is resolved.
|
||||
unset($data['pi_flexform']);
|
||||
} catch (\Throwable $e) {
|
||||
// Leave the raw data untouched on any failure.
|
||||
}
|
||||
}
|
||||
|
||||
private function isEmpty(mixed $value): bool
|
||||
{
|
||||
return $value === null
|
||||
|
||||
Reference in New Issue
Block a user