diff --git a/Classes/Controller/DateController.php b/Classes/Controller/DateController.php index d92ad06..5b8e137 100644 --- a/Classes/Controller/DateController.php +++ b/Classes/Controller/DateController.php @@ -6,6 +6,7 @@ use TYPO3\CMS\Core\EventDispatcher\EventDispatcher; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Annotation as Extbase; use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface; +use TYPO3\CMS\Extbase\Service\ExtensionService; use Wrm\Events\Domain\Model\Date; use Wrm\Events\Domain\Model\Dto\DateDemand; use Wrm\Events\Domain\Model\Dto\DateDemandFactory; @@ -42,11 +43,6 @@ class DateController extends AbstractController */ protected $categoryRepository; - /** - * @var EventDispatcher - */ - protected $eventDispatcher; - /** * @var Factory */ @@ -57,22 +53,34 @@ class DateController extends AbstractController */ protected $dataProcessing; + /** + * @var EventDispatcher + */ + protected $eventDispatcher; + + /** + * @var ExtensionService + */ + protected $extensionService; + public function __construct( DateDemandFactory $demandFactory, - RegionRepository $regionRepository, DateRepository $dateRepository, + RegionRepository $regionRepository, CategoryRepository $categoryRepository, + Factory $paginationFactory, DataProcessingForModels $dataProcessing, EventDispatcher $eventDispatcher, - Factory $paginationFactory + ExtensionService $extensionService ) { $this->demandFactory = $demandFactory; - $this->regionRepository = $regionRepository; $this->dateRepository = $dateRepository; + $this->regionRepository = $regionRepository; $this->categoryRepository = $categoryRepository; + $this->paginationFactory = $paginationFactory; $this->dataProcessing = $dataProcessing; $this->eventDispatcher = $eventDispatcher; - $this->paginationFactory = $paginationFactory; + $this->extensionService = $extensionService; } protected function initializeAction(): void @@ -82,6 +90,8 @@ class DateController extends AbstractController $this->demandFactory->setContentObjectRenderer($contentObject); } $this->dataProcessing->setConfigurationManager($this->configurationManager); + + $this->handlePostRequest(); } /** @@ -95,14 +105,6 @@ class DateController extends AbstractController $demand = $this->demandFactory->fromSettings($this->settings); if ($search !== []) { $demand = DateDemand::createFromRequestValues($search, $this->settings); - } elseif ( - ($this->request->hasArgument('searchword') && $this->request->getArgument('searchword') != '') - || ($this->request->hasArgument('region') && $this->request->getArgument('region') != '') - || ($this->request->hasArgument('start') && $this->request->getArgument('start') != '') - || ($this->request->hasArgument('end') && $this->request->getArgument('end') != '') - || ($this->request->hasArgument('events_search') && $this->request->getArgument('events_search') != []) - ) { - $demand = $this->createDemandFromSearch(); } $dates = $this->dateRepository->findByDemand($demand); @@ -128,24 +130,6 @@ class DateController extends AbstractController */ public function searchAction(array $search = []): void { - $arguments = GeneralUtility::_GET('tx_events_datelist') ?? $search; - if (is_array($arguments) === false) { - $arguments = []; - } - if (isset($arguments['events_search']) && is_array($arguments['events_search'])) { - $arguments += $arguments['events_search']; - unset($arguments['events_search']); - } - - // For legacy systems. - $this->view->assignMultiple([ - 'searchword' => $arguments['searchword'] ?? '', - 'selRegion' => $arguments['region'] ?? '', - 'start' => $arguments['start'] ?? '', - 'end' => $arguments['end'] ?? '', - 'considerDate' => $arguments['considerDate'] ?? '', - ]); - $demand = $this->demandFactory->fromSettings($this->settings); if ($search !== []) { $demand = DateDemand::createFromRequestValues($search, $this->settings); @@ -178,17 +162,27 @@ class DateController extends AbstractController $this->view->assign('date', $date); } - protected function createDemandFromSearch(): DateDemand + /** + * Convert POST to proper GET. + * + * @see: https://en.wikipedia.org/wiki/Post/Redirect/Get + */ + private function handlePostRequest(): void { - $arguments = $this->request->getArguments(); - if (isset($arguments['events_search'])) { - $arguments += $arguments['events_search']; - unset($arguments['events_search']); + if ( + $this->request->getMethod() === 'POST' + && $this->request->hasArgument('search') + && is_array($this->request->getArgument('search')) + ) { + $namespace = $this->extensionService->getPluginNamespace(null, null); + $this->redirectToUri($this->configurationManager->getContentObject()->typoLink_URL([ + 'parameter' => 't3://page?uid=current', + 'additionalParams' => '&' . http_build_query([ + $namespace => [ + 'search' => array_filter($this->request->getArgument('search')) + ], + ]), + ])); } - - return DateDemand::createFromRequestValues( - $arguments, - $this->settings - ); } } diff --git a/Classes/Domain/Model/Dto/DateDemand.php b/Classes/Domain/Model/Dto/DateDemand.php index fee8d34..bc81290 100644 --- a/Classes/Domain/Model/Dto/DateDemand.php +++ b/Classes/Domain/Model/Dto/DateDemand.php @@ -331,13 +331,18 @@ class DateDemand return $this->startObject; } - public function getStart(): ?int + /** + * Returns necessary format for forms. + * + * @internal Only for Extbase/Fluid. + */ + public function getStart(): string { if ($this->getStartObject() === null) { - return null; + return ''; } - return (int) $this->getStartObject()->format('U'); + return $this->getStartObject()->format('Y-m-d'); } public function setStart(?int $start): void @@ -362,13 +367,18 @@ class DateDemand return $this->getStartObject()->format('Y-m-d') === $this->getEndObject()->format('Y-m-d'); } - public function getEnd(): ?int + /** + * Returns necessary format for forms. + * + * @internal Only for Extbase/Fluid. + */ + public function getEnd(): string { if ($this->getEndObject() === null) { - return null; + return ''; } - return (int) $this->getEndObject()->format('U'); + return $this->getEndObject()->format('Y-m-d'); } public function setEnd(?int $end): void @@ -387,15 +397,15 @@ class DateDemand public function shouldShowFromNow(): bool { - return $this->getStart() === null - && $this->getEnd() === null + return $this->getStartObject() === null + && $this->getEndObject() === null && $this->useMidnight === false; } public function shouldShowFromMidnight(): bool { - return $this->getStart() === null - && $this->getEnd() === null + return $this->getStartObject() === null + && $this->getEndObject() === null && $this->useMidnight === true; } diff --git a/Classes/Domain/Repository/DateRepository.php b/Classes/Domain/Repository/DateRepository.php index 99b30da..e8a3ee4 100644 --- a/Classes/Domain/Repository/DateRepository.php +++ b/Classes/Domain/Repository/DateRepository.php @@ -77,20 +77,20 @@ class DateRepository extends Repository $constraints['userCategories'] = $query->in('event.categories.uid', $demand->getUserCategories()); } - if ($demand->getStart() !== null) { - $constraints['starts'] = $query->greaterThanOrEqual('start', $demand->getStart()); + if ($demand->getStartObject() !== null) { + $constraints['starts'] = $query->greaterThanOrEqual('start', $demand->getStartObject()); } - if ($demand->getEnd() != null) { + if ($demand->getEndObject() != null) { // Dates might have end of 0 if only start exists. // This is respected to take start as end date. $constraints['ends'] = $query->logicalOr([ $query->logicalAnd([ - $query->lessThanOrEqual('end', $demand->getEnd()), + $query->lessThanOrEqual('end', $demand->getEndObject()), $query->greaterThan('end', 0) ]), $query->logicalAnd([ $query->equals('end', 0), - $query->lessThanOrEqual('start', $demand->getEnd()) + $query->lessThanOrEqual('start', $demand->getEndObject()) ]), ]); } diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript index 71c4f8c..f679496 100644 --- a/Configuration/TypoScript/setup.typoscript +++ b/Configuration/TypoScript/setup.typoscript @@ -23,14 +23,10 @@ plugin.tx_events { recursive = 1 } features { - #skipDefaultArguments = 1 - # if set to 1, the enable fields are ignored in BE context - ignoreAllEnableFieldsInBe = 0 - # Should be on by default, but can be disabled if all action in the plugin are uncached - requireCHashArgumentForActionArguments = 0 + skipDefaultArguments = 1 } mvc { - #callDefaultActionIfActionCantBeResolved = 1 + callDefaultActionIfActionCantBeResolved = 1 } settings { @@ -74,4 +70,7 @@ plugin.tx_events { } } +plugin.tx_events_datelist.view.pluginNamespace = events_search +plugin.tx_events_datesearch.view.pluginNamespace = events_search + module.tx_events < plugin.tx_events diff --git a/Documentation/Changelog/3.0.0.rst b/Documentation/Changelog/3.0.0.rst new file mode 100644 index 0000000..3f6fdde --- /dev/null +++ b/Documentation/Changelog/3.0.0.rst @@ -0,0 +1,64 @@ +3.0.0 +===== + +Breaking +-------- + +Namespace changes +^^^^^^^^^^^^^^^^^ + +A new namespace was defined for plugins which is "events_search". +The search parameters are now collected below namespace "search" instead of +"events_search" leading to ``events_search[search][parametername]=value`` instead of +``tx_events_signature[events_search][parametername]=value``. + +The form now is submitted as post and redirects to a proper URL with GET. + +The code was bloated and made it hard to fix bugs. + +Necessary steps: + +- Check usage of old namespace within templates and other sources. + +- Check usage of old nesting of parameters. + +API Changes +^^^^^^^^^^^ + +The methods of ``DateDemand`` have changed, ``getStart()`` and ``getEnd()`` return a +string value necessary or Fluid forms. +Those are not considered public API. Use ``getStartObject()`` and ``getEndObject()`` +instead. + +Features +-------- + +Nothing + +Fixes +----- + +* Keep filter during pagination + + Search requests are POST by default. + We apply PRG (=Post Redirect Get) on them to create proper GET requests. + Those can be used to generate the URLs for pagination. + + We follow Extbase, and do not explicitly ask for arguments from foreign namespaces. + Instead we configure a pluginNamespace that's shared between plugins. + This is all necessary as we still ship pre defined plugins. + This should belong into integration of each project. + + See: https://en.wikipedia.org/wiki/Post/Redirect/Get + + Relates: #10175 + +Tasks +----- + +Nothing + +Deprecation +----------- + +Nothing diff --git a/Resources/Private/Language/de.locallang.xlf b/Resources/Private/Language/de.locallang.xlf index dd71334..d0f4150 100644 --- a/Resources/Private/Language/de.locallang.xlf +++ b/Resources/Private/Language/de.locallang.xlf @@ -17,7 +17,7 @@ Date to - Date bis + Datum bis All regions diff --git a/Resources/Private/Partials/Pagination.html b/Resources/Private/Partials/Pagination.html index 657450b..e0060f9 100644 --- a/Resources/Private/Partials/Pagination.html +++ b/Resources/Private/Partials/Pagination.html @@ -8,13 +8,13 @@ - + @@ -25,7 +25,7 @@
  • 1 @@ -54,7 +54,7 @@ {page} @@ -62,7 +62,7 @@ 1 @@ -83,7 +83,7 @@
  • {pagination.lastPageNumber} @@ -94,7 +94,7 @@
  • diff --git a/Resources/Private/Templates/Date/Search.html b/Resources/Private/Templates/Date/Search.html index 96f482d..c3945fd 100644 --- a/Resources/Private/Templates/Date/Search.html +++ b/Resources/Private/Templates/Date/Search.html @@ -3,14 +3,14 @@
    - +
    - +
    @@ -18,23 +18,13 @@
    -
    - -
    -
    -
    -
    +
    -
    - -
    -
    -
    -
    +
    @@ -44,7 +34,7 @@
    - +
    @@ -52,7 +42,7 @@
    - +
    diff --git a/Tests/Unit/Domain/Model/Dto/DateDemandTest.php b/Tests/Unit/Domain/Model/Dto/DateDemandTest.php index a4aefd5..8682488 100644 --- a/Tests/Unit/Domain/Model/Dto/DateDemandTest.php +++ b/Tests/Unit/Domain/Model/Dto/DateDemandTest.php @@ -201,7 +201,7 @@ class DateDemandTest extends TestCase $result->getStartObject()->format('Y-m-d') ); self::assertSame( - 1657576800, + '2022-07-12', $result->getStart() ); } @@ -228,7 +228,7 @@ class DateDemandTest extends TestCase $result->getEndObject()->format('Y-m-d') ); self::assertSame( - 1657663140, + '2022-07-12', $result->getEnd() ); } diff --git a/ext_emconf.php b/ext_emconf.php index f32f6a4..c18a1dd 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -9,7 +9,7 @@ $EM_CONF['events'] = [ 'state' => 'alpha', 'createDirs' => '', 'clearCacheOnLoad' => 0, - 'version' => '2.6.3', + 'version' => '3.0.0', 'constraints' => [ 'depends' => [ 'typo3' => '10.4.00-11.5.99', diff --git a/ext_localconf.php b/ext_localconf.php index bd81f08..3c53350 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -37,6 +37,8 @@ call_user_func(function () { $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['events_category'] = []; } + $GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = '^events_search'; + $iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\IconRegistry::class); $iconRegistry->registerIcon( 'events-plugin', diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 30bf9ac..1df3fc1 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,5 +1,9 @@ parameters: ignoreErrors: + - + message: "#^Cannot call method typoLink_URL\\(\\) on TYPO3\\\\CMS\\\\Frontend\\\\ContentObject\\\\ContentObjectRenderer\\|null\\.$#" + count: 1 + path: Classes/Controller/DateController.php - message: "#^Parameter \\#1 \\$categories of method Wrm\\\\Events\\\\Domain\\\\Model\\\\Event\\:\\:setCategories\\(\\) expects TYPO3\\\\CMS\\\\Extbase\\\\Persistence\\\\ObjectStorage\\, TYPO3\\\\CMS\\\\Extbase\\\\Persistence\\\\ObjectStorage\\ given\\.$#" count: 1