From 00034c99ae96efdf60bde05aa16a67755e2c663b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Wed, 21 Oct 2026 17:28:10 +0200 Subject: [PATCH] feat: watchlist on TYPO3 13 Watchlist page (/merkliste/) and its list action, which renders the hotel/product pairs a visitor stored in sessionStorage. The "remember" buttons on teasers and detail pages had nowhere to show their list since the static switch. Compared with TYPO3 10 (page, empty and invalid input, unknown and 1 to 25 real pairs): identical. Co-Authored-By: Claude Opus 5.5 --- .../Controller/AjaxWatchlistController.php | 105 ++++++++++++++++++ .../Controller/WatchlistController.php | 43 +++++++ .../TCA/Overrides/tt_content.php | 6 + packages/ep_products/ext_localconf.php | 12 ++ .../Private/Templates/AjaxWatchlist/List.html | 44 ++++++++ .../Private/Templates/Watchlist/List.html | 23 ++++ 6 files changed, 233 insertions(+) create mode 100644 packages/ep_products/Classes/Controller/AjaxWatchlistController.php create mode 100644 packages/ep_products/Classes/Controller/WatchlistController.php create mode 100644 packages/ep_theme/Resources/Private/Templates/AjaxWatchlist/List.html create mode 100644 packages/ep_theme/Resources/Private/Templates/Watchlist/List.html diff --git a/packages/ep_products/Classes/Controller/AjaxWatchlistController.php b/packages/ep_products/Classes/Controller/AjaxWatchlistController.php new file mode 100644 index 0000000..7480ab9 --- /dev/null +++ b/packages/ep_products/Classes/Controller/AjaxWatchlistController.php @@ -0,0 +1,105 @@ +, dreipunktnull + * + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ +use Psr\Http\Message\ResponseInterface; +use EP\EpProducts\Domain\Repository\ProductRepository; +use EP\EpProducts\Service\FilterService; +use EP\EpProducts\Service\SearchResultService; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; + +class AjaxWatchlistController extends ActionController +{ + + /** + * @var ProductRepository + */ + protected $productRepository; + + /** + * @var SearchResultService + */ + protected $searchResultService; + + /** + * @var FilterService + */ + protected $filterService; + + /** + * @param ProductRepository $productRepository + * @param SearchResultService $searchResultService + * @param FilterService $filterService + */ + public function __construct + ( + ProductRepository $productRepository, + SearchResultService $searchResultService, + FilterService $filterService + ) + { + $this->productRepository = $productRepository; + $this->searchResultService = $searchResultService; + $this->filterService = $filterService; + } + + public function initializeAction(): void + { + if ($this->request->hasArgument('watchlistUids')) { + $watchlistUids = json_decode($this->request->getArgument('watchlistUids'), true, 512, JSON_THROW_ON_ERROR); + $this->request = $this->request->withArgument('watchlistUids', $watchlistUids); + } + } + + /** + * @param array $watchlistUids + * @return string + * @throws \Doctrine\DBAL\DBALException + */ + public function listAction(array $watchlistUids = []): ResponseInterface + { + $productUids = array_map(function ($uid) { + [ , $productUid ] = GeneralUtility::trimExplode(':', $uid); + return $productUid; + }, $watchlistUids); + + $hotelUids = array_map(function ($uid) { + [ $hotelUid, ] = GeneralUtility::trimExplode(':', $uid); + return $hotelUid; + }, $watchlistUids); + + $watchlistData = $this->productRepository->getWatchlist($productUids, $hotelUids); + $watchlist = $this->searchResultService->preprocess($watchlistData); + + $this->view->assignMultiple([ + 'watchlist' => $watchlist->getData(), + 'total' => $watchlist->getTotal() + ]); + return $this->htmlResponse(); + } +} diff --git a/packages/ep_products/Classes/Controller/WatchlistController.php b/packages/ep_products/Classes/Controller/WatchlistController.php new file mode 100644 index 0000000..850390d --- /dev/null +++ b/packages/ep_products/Classes/Controller/WatchlistController.php @@ -0,0 +1,43 @@ +, dreipunktnull + * + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ +use Psr\Http\Message\ResponseInterface; +use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; + +class WatchlistController extends ActionController +{ + + public function listAction(): ResponseInterface + { + $data = $this->request->getAttribute('currentContentObject')->data; + $this->view->assign('data', $data); + $this->view->assign('referringPageUid', $this->request->getAttribute('frontend.page.information')->getId()); + return $this->htmlResponse(); + } + +} diff --git a/packages/ep_products/Configuration/TCA/Overrides/tt_content.php b/packages/ep_products/Configuration/TCA/Overrides/tt_content.php index e93d057..ad99a6a 100644 --- a/packages/ep_products/Configuration/TCA/Overrides/tt_content.php +++ b/packages/ep_products/Configuration/TCA/Overrides/tt_content.php @@ -13,6 +13,12 @@ call_user_func(function () { 'Suchergebnis' ); + ExtensionUtility::registerPlugin( + 'EpProducts', + 'watchlist', + 'Merkliste' + ); + ExtensionUtility::registerPlugin( 'EpProducts', 'product_detail', diff --git a/packages/ep_products/ext_localconf.php b/packages/ep_products/ext_localconf.php index 72d509a..81158de 100644 --- a/packages/ep_products/ext_localconf.php +++ b/packages/ep_products/ext_localconf.php @@ -2,9 +2,11 @@ use TYPO3\CMS\Extbase\Utility\ExtensionUtility; use EP\EpProducts\Controller\ProductController; use EP\EpProducts\Controller\SearchController; +use EP\EpProducts\Controller\WatchlistController; use EP\EpProducts\Controller\AjaxFilterPanelController; use EP\EpProducts\Controller\AjaxSearchController; use EP\EpProducts\Controller\AjaxTableController; +use EP\EpProducts\Controller\AjaxWatchlistController; use EP\EpProducts\Controller\AjaxCalendarController; use EP\EpProducts\Controller\AjaxTeaserPopupController; use EP\EpProducts\Routing\Aspect\PassthroughMapper; @@ -62,12 +64,21 @@ $boot = function () { ] ); + ExtensionUtility::configurePlugin( + 'EpProducts', + 'watchlist', + [ + WatchlistController::class => 'list', + ] + ); + ExtensionUtility::configurePlugin( 'EpProducts', 'ajax', [ AjaxSearchController::class => 'searchresult', AjaxFilterPanelController::class => 'index', + AjaxWatchlistController::class => 'list', AjaxTableController::class => 'datestable,pricetable,pricetableHtml,eventPricetable', AjaxCalendarController::class => 'priceCalendar,priceTable', AjaxTeaserPopupController::class => 'concept', @@ -75,6 +86,7 @@ $boot = function () { [ AjaxSearchController::class => 'searchresult', AjaxFilterPanelController::class => 'index', + AjaxWatchlistController::class => 'list', AjaxTableController::class => 'datestable,pricetable,pricetableHtml,eventPricetable', AjaxTeaserPopupController::class => 'concept', ] diff --git a/packages/ep_theme/Resources/Private/Templates/AjaxWatchlist/List.html b/packages/ep_theme/Resources/Private/Templates/AjaxWatchlist/List.html new file mode 100644 index 0000000..459287a --- /dev/null +++ b/packages/ep_theme/Resources/Private/Templates/AjaxWatchlist/List.html @@ -0,0 +1,44 @@ + + + + +
+ Deine Merkliste ist aktuell leer... +
+
+ + +
+

+ {section.concept.name} +

+
+ + + +
+
+
+
+
+ + diff --git a/packages/ep_theme/Resources/Private/Templates/Watchlist/List.html b/packages/ep_theme/Resources/Private/Templates/Watchlist/List.html new file mode 100644 index 0000000..ccb69c5 --- /dev/null +++ b/packages/ep_theme/Resources/Private/Templates/Watchlist/List.html @@ -0,0 +1,23 @@ + + + + + + +
+
+ +
+
+
+ +