From 0b17a24edd2b9e69c5910f571ef2197d59afa1e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Sat, 24 Oct 2026 12:56:22 +0200 Subject: [PATCH] feat: page module previews for teasers, disrupter, disturber, map and lineup The TYPO3 10 drawItem hooks become one preview renderer registered per CType in TCA; it renders the old templates from a46918d with the same variables (f:format.html is not allowed in the backend: f:sanitize.html). Co-Authored-By: Claude Opus 5.5 --- .../Preview/ContentPreviewRenderer.php | 120 ++++++++++++++++++ .../TCA/Overrides/tt_content_preview.php | 13 ++ .../Templates/PreviewRenderer/Disrupter.html | 11 ++ .../Templates/PreviewRenderer/Disturber.html | 24 ++++ .../Templates/PreviewRenderer/Gmap.html | 11 ++ .../Templates/PreviewRenderer/Lineup.html | 15 +++ .../PreviewRenderer/TeaserBookingLink.html | 23 ++++ .../Templates/PreviewRenderer/TeaserCity.html | 23 ++++ .../PreviewRenderer/TeaserConcept.html | 23 ++++ .../PreviewRenderer/TeaserCountry.html | 23 ++++ .../PreviewRenderer/TeaserHotel.html | 23 ++++ .../PreviewRenderer/TeaserProduct.html | 23 ++++ .../PreviewRenderer/TeaserRegion.html | 23 ++++ 13 files changed, 355 insertions(+) create mode 100644 packages/ep_theme/Classes/Preview/ContentPreviewRenderer.php create mode 100644 packages/ep_theme/Configuration/TCA/Overrides/tt_content_preview.php create mode 100644 packages/ep_theme/Resources/Private/Templates/PreviewRenderer/Disrupter.html create mode 100644 packages/ep_theme/Resources/Private/Templates/PreviewRenderer/Disturber.html create mode 100644 packages/ep_theme/Resources/Private/Templates/PreviewRenderer/Gmap.html create mode 100644 packages/ep_theme/Resources/Private/Templates/PreviewRenderer/Lineup.html create mode 100644 packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserBookingLink.html create mode 100644 packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserCity.html create mode 100644 packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserConcept.html create mode 100644 packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserCountry.html create mode 100644 packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserHotel.html create mode 100644 packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserProduct.html create mode 100644 packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserRegion.html diff --git a/packages/ep_theme/Classes/Preview/ContentPreviewRenderer.php b/packages/ep_theme/Classes/Preview/ContentPreviewRenderer.php new file mode 100644 index 0000000..90d55c1 --- /dev/null +++ b/packages/ep_theme/Classes/Preview/ContentPreviewRenderer.php @@ -0,0 +1,120 @@ +.html as the TYPO3 10 drawItem hooks did + * (Classes/Hooks/PageLayoutView in a46918d), with the same template variables. + * Registered per CType in TCA (['types'][]['previewRenderer']). + */ +class ContentPreviewRenderer extends StandardContentPreviewRenderer +{ + /** + * CType => [field holding the related uid, related table, template variable] + */ + protected const RELATED_RECORDS = [ + 'teaser_country' => ['tx_eptheme_context_country', 'tx_epproducts_domain_model_country', 'country'], + 'teaser_region' => ['tx_eptheme_context_region', 'tx_epproducts_domain_model_region', 'region'], + 'teaser_city' => ['tx_eptheme_context_city', 'tx_epproducts_domain_model_city', 'city'], + 'teaser_hotel' => ['tx_eptheme_context_hotel', 'tx_epproducts_domain_model_hotel', 'hotel'], + 'teaser_concept' => ['tx_eptheme_context_concept', 'tx_epproducts_domain_model_concept', 'concept'], + 'teaser_product' => ['tx_eptheme_context_product', 'tx_epproducts_domain_model_product', 'product'], + 'teaser_booking_link' => ['tx_eptheme_context_product', 'tx_epproducts_domain_model_product', 'product'], + ]; + + public function renderPageModulePreviewContent(GridColumnItem $item): string + { + $row = $item->getRecord(); + $cType = (string)$row['CType']; + $template = GeneralUtility::getFileAbsFileName( + 'EXT:ep_theme/Resources/Private/Templates/PreviewRenderer/' . GeneralUtility::underscoredToUpperCamelCase($cType) . '.html' + ); + if (!is_file($template)) { + return parent::renderPageModulePreviewContent($item); + } + + $images = $this->getImages((int)$row['uid'], 'tt_content', 'image'); + $variables = [ + 'data' => $row, + 'flexForm' => GeneralUtility::makeInstance(FlexFormService::class)->convertFlexFormContentToArray((string)($row['pi_flexform'] ?? '')), + 'firstImage' => $images[0] ?? null, + 'images' => $images, + ]; + $variables = array_replace($variables, $this->getAssignmentsForTemplate($cType, $row)); + + $view = GeneralUtility::makeInstance(ViewFactoryInterface::class)->create(new ViewFactoryData( + templatePathAndFilename: $template, + request: $item->getContext()->getCurrentRequest(), + )); + $view->assignMultiple($variables); + return $view->render(); + } + + protected function getAssignmentsForTemplate(string $cType, array $row): array + { + if (isset(self::RELATED_RECORDS[$cType])) { + [$field, $table, $name] = self::RELATED_RECORDS[$cType]; + $uid = (int)($row[$field] ?? 0); + $assignments = [ + 'images' => $this->getImages($uid, $table, 'teaser_images'), + $name => $uid > 0 ? BackendUtility::getRecord($table, $uid) : null, + ]; + if ($cType === 'teaser_product') { + $hotelUid = (int)($row['tx_eptheme_context_hotel'] ?? 0); + $assignments['hotel'] = $hotelUid > 0 ? BackendUtility::getRecord('tx_epproducts_domain_model_hotel', $hotelUid) : null; + } + return $assignments; + } + + switch ($cType) { + case 'gmap': + $regionUid = (int)($row['tx_eptheme_context_region'] ?? 0); + $content = $regionUid > 0 + ? BackendUtility::getRecord('tx_epproducts_domain_model_region', $regionUid) + : BackendUtility::getRecord('tx_epproducts_domain_model_hotel', (int)($row['tx_eptheme_context_hotel'] ?? 0)); + return ['content' => $content]; + case 'disrupter': + // tx_eptheme_disrupter is an MM relation; the field itself only holds the count + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_eptheme_ttcontent_tx_eptheme_disrupter_mm'); + $disrupterUid = (int)$queryBuilder->select('uid_foreign') + ->from('tx_eptheme_ttcontent_tx_eptheme_disrupter_mm') + ->where($queryBuilder->expr()->eq('uid_local', $queryBuilder->createNamedParameter((int)$row['uid']))) + ->orderBy('sorting') + ->setMaxResults(1) + ->executeQuery() + ->fetchOne(); + return ['content' => $disrupterUid > 0 ? BackendUtility::getRecord('tx_eptheme_domain_model_disrupter', $disrupterUid) : null]; + case 'lineup': + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_eptheme_domain_model_lineup'); + $rows = $queryBuilder->select('*') + ->from('tx_eptheme_domain_model_lineup') + ->where($queryBuilder->expr()->eq('tt_content', $queryBuilder->createNamedParameter((int)$row['uid']))) + ->orderBy('sorting') + ->executeQuery() + ->fetchAllAssociative(); + return ['rows' => $rows]; + } + return []; + } + + protected function getImages(int $uid, string $table, string $field): array + { + if ($uid <= 0) { + return []; + } + return GeneralUtility::makeInstance(FileRepository::class)->findByRelation($table, $field, $uid); + } +} diff --git a/packages/ep_theme/Configuration/TCA/Overrides/tt_content_preview.php b/packages/ep_theme/Configuration/TCA/Overrides/tt_content_preview.php new file mode 100644 index 0000000..7a9457f --- /dev/null +++ b/packages/ep_theme/Configuration/TCA/Overrides/tt_content_preview.php @@ -0,0 +1,13 @@ +.html); loads after tt_content_element_*.php +foreach (['teaser_country', 'teaser_region', 'teaser_city', 'teaser_hotel', 'teaser_concept', 'teaser_product', + 'teaser_booking_link', 'gmap', 'disturber', 'disrupter', 'lineup'] as $cType) { + if (isset($GLOBALS['TCA']['tt_content']['types'][$cType])) { + $GLOBALS['TCA']['tt_content']['types'][$cType]['previewRenderer'] = ContentPreviewRenderer::class; + } +} diff --git a/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/Disrupter.html b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/Disrupter.html new file mode 100644 index 0000000..e97e2f9 --- /dev/null +++ b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/Disrupter.html @@ -0,0 +1,11 @@ +{namespace be=TYPO3\CMS\Backend\ViewHelpers} +
+
+

+ Störer +

+ + {content.headline} + +
+
diff --git a/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/Disturber.html b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/Disturber.html new file mode 100644 index 0000000..960ae76 --- /dev/null +++ b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/Disturber.html @@ -0,0 +1,24 @@ +{namespace be=TYPO3\CMS\Backend\ViewHelpers} +
+
+

+ Störer +

+ + + + groß + > + + Event klein + + + Event groß + + + klein + + + +
+
diff --git a/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/Gmap.html b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/Gmap.html new file mode 100644 index 0000000..dcb9ca0 --- /dev/null +++ b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/Gmap.html @@ -0,0 +1,11 @@ +{namespace be=TYPO3\CMS\Backend\ViewHelpers} +
+
+

+ OSM Karte +

+ + {content.name} ({content.latitude}, {content.longitude}) + +
+
diff --git a/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/Lineup.html b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/Lineup.html new file mode 100644 index 0000000..d91851c --- /dev/null +++ b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/Lineup.html @@ -0,0 +1,15 @@ +{namespace be=TYPO3\CMS\Backend\ViewHelpers} +
+
+

+ Lineup +

+
    + +
  • + {row.name} +
  • +
    +
+
+
diff --git a/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserBookingLink.html b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserBookingLink.html new file mode 100644 index 0000000..e6bb213 --- /dev/null +++ b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserBookingLink.html @@ -0,0 +1,23 @@ +{namespace be=TYPO3\CMS\Backend\ViewHelpers} +
+
+

+ Teaser Buchungslink +

+

+ + + + + + + + +

+ + {product.name} + +
+ {product.teaser -> f:sanitize.html()} +
+
diff --git a/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserCity.html b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserCity.html new file mode 100644 index 0000000..9e00332 --- /dev/null +++ b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserCity.html @@ -0,0 +1,23 @@ +{namespace be=TYPO3\CMS\Backend\ViewHelpers} +
+
+

+ Teaser Ort +

+

+ + + + + + + + +

+ + {city.name} + +
+ {city.teaser -> f:sanitize.html()} +
+
diff --git a/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserConcept.html b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserConcept.html new file mode 100644 index 0000000..36286a5 --- /dev/null +++ b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserConcept.html @@ -0,0 +1,23 @@ +{namespace be=TYPO3\CMS\Backend\ViewHelpers} +
+
+

+ Teaser Konzept +

+

+ + + + + + + + +

+ + {concept.name} + +
+ {concept.teaser -> f:sanitize.html()} +
+
diff --git a/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserCountry.html b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserCountry.html new file mode 100644 index 0000000..71bafaa --- /dev/null +++ b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserCountry.html @@ -0,0 +1,23 @@ +{namespace be=TYPO3\CMS\Backend\ViewHelpers} +
+
+

+ Teaser Land +

+

+ + + + + + + + +

+ + {country.name} + +
+ {country.teaser -> f:sanitize.html()} +
+
diff --git a/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserHotel.html b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserHotel.html new file mode 100644 index 0000000..4acbc83 --- /dev/null +++ b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserHotel.html @@ -0,0 +1,23 @@ +{namespace be=TYPO3\CMS\Backend\ViewHelpers} +
+
+

+ Teaser Hotel +

+

+ + + + + + + + +

+ + {hotel.name} + +
+ {hotel.teaser -> f:sanitize.html()} +
+
diff --git a/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserProduct.html b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserProduct.html new file mode 100644 index 0000000..e973b72 --- /dev/null +++ b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserProduct.html @@ -0,0 +1,23 @@ +{namespace be=TYPO3\CMS\Backend\ViewHelpers} +
+
+

+ Teaser Produkt +

+

+ + + + + + + + +

+ + {product.name} + +
+ {product.teaser -> f:sanitize.html()} +
+
diff --git a/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserRegion.html b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserRegion.html new file mode 100644 index 0000000..7e7f06a --- /dev/null +++ b/packages/ep_theme/Resources/Private/Templates/PreviewRenderer/TeaserRegion.html @@ -0,0 +1,23 @@ +{namespace be=TYPO3\CMS\Backend\ViewHelpers} +
+
+

+ Teaser Gebiet +

+

+ + + + + + + + +

+ + {region.name} + +
+ {region.teaser -> f:sanitize.html()} +
+