diff --git a/Classes/Domain/Repository/DateRepository.php b/Classes/Domain/Repository/DateRepository.php index bcbc20f..5f842a4 100644 --- a/Classes/Domain/Repository/DateRepository.php +++ b/Classes/Domain/Repository/DateRepository.php @@ -77,22 +77,9 @@ class DateRepository extends Repository $constraints['userCategories'] = $query->in('event.categories.uid', $demand->getUserCategories()); } - if ($demand->getStartObject() !== null) { - $constraints['starts'] = $query->greaterThanOrEqual('start', $demand->getStartObject()); - } - 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->getEndObject()), - $query->greaterThan('end', 0) - ]), - $query->logicalAnd([ - $query->equals('end', 0), - $query->lessThanOrEqual('start', $demand->getEndObject()) - ]), - ]); + $timingConstraint = $this->createTimingConstraint($query, $demand); + if ($timingConstraint instanceof ConstraintInterface) { + $constraints['timing'] = $timingConstraint; } if ($demand->shouldShowFromNow() || $demand->shouldShowFromMidnight()) { @@ -198,6 +185,54 @@ class DateRepository extends Repository return $query->logicalAnd($constraints); } + private function createTimingConstraint( + QueryInterface $query, + DateDemand $demand + ): ?ConstraintInterface { + // Dates might have end of 0 if only start exists. + + if ($demand->getStartObject() !== null && $demand->getEndObject() === null) { + return $query->logicalOr([ + $query->greaterThanOrEqual('start', $demand->getStartObject()), + $query->greaterThanOrEqual('end', $demand->getStartObject()), + ]); + } + + if ($demand->getStartObject() === null && $demand->getEndObject() !== null) { + return $query->logicalOr([ + $query->logicalAnd([ + $query->lessThanOrEqual('end', $demand->getEndObject()), + $query->greaterThan('end', 0), + ]), + $query->lessThanOrEqual('start', $demand->getEndObject()), + ]); + } + + if ($demand->getStartObject() !== null && $demand->getEndObject() !== null) { + return $query->logicalOr([ + $query->logicalAnd([ + $query->logicalOr([ + $query->greaterThanOrEqual('start', $demand->getStartObject()), + $query->greaterThanOrEqual('end', $demand->getStartObject()), + ]), + $query->logicalOr([ + $query->lessThanOrEqual('start', $demand->getEndObject()), + $query->logicalAnd([ + $query->lessThanOrEqual('end', $demand->getEndObject()), + $query->greaterThan('end', 0), + ]), + ]), + ]), + $query->logicalAnd([ + $query->lessThanOrEqual('start', $demand->getStartObject()), + $query->greaterThanOrEqual('end', $demand->getEndObject()), + ]), + ]); + } + + return null; + } + private function createFeaturesConstraint( QueryInterface $query, DateDemand $demand diff --git a/Configuration/TypoScript/constants.typoscript b/Configuration/TypoScript/constants.typoscript index 5ab60de..1f0ccc4 100644 --- a/Configuration/TypoScript/constants.typoscript +++ b/Configuration/TypoScript/constants.typoscript @@ -19,7 +19,7 @@ plugin.tx_events { # cat=plugin.tx_events//a; type=string; label=Rest Url restUrl = http://meta.et4.de/rest.ashx/search/ # cat=plugin.tx_events//a; type=string; label=License - license = ***REMOVED*** + license = # cat=plugin.tx_events//a; type=string; label=Data Type restType = Event # cat=plugin.tx_events//a; type=string; label=Data Limit diff --git a/Documentation/Changelog/3.2.1.rst b/Documentation/Changelog/3.2.1.rst new file mode 100644 index 0000000..b996cd4 --- /dev/null +++ b/Documentation/Changelog/3.2.1.rst @@ -0,0 +1,27 @@ +3.2.1 +===== + +Breaking +-------- + +Nothing + +Features +-------- + +Nothing + +Fixes +----- + +* Properly handle time searches, now covered with tests. + +Tasks +----- + +Nothing + +Deprecation +----------- + +Nothing diff --git a/Tests/Functional/Frontend/DatesTest.php b/Tests/Functional/Frontend/DatesTest.php index 789ba04..5010a36 100644 --- a/Tests/Functional/Frontend/DatesTest.php +++ b/Tests/Functional/Frontend/DatesTest.php @@ -84,4 +84,93 @@ class DatesTest extends FunctionalTestCase self::assertStringNotContainsString('Event 1 hidden', $html); self::assertStringContainsString('Event 2 visible', $html); } + + /** + * @test + */ + public function returnsDateAfterStart(): void + { + $this->importCSVDataSet(__DIR__ . '/DatesTestFixtures/ReturnsDateWithinTimeSpan.csv'); + + $request = new InternalRequest(); + $request = $request->withPageId(1); + $request = $request->withQueryParameters([ + 'events_search[search][start]' => '2023-02-16', + ]); + $response = $this->executeFrontendRequest($request); + + self::assertSame(200, $response->getStatusCode()); + $html = (string) $response->getBody(); + + self::assertStringNotContainsString('Event 1', $html); + self::assertStringNotContainsString('Event 2', $html); + self::assertStringContainsString('Event 3', $html); + self::assertStringContainsString('Event 4', $html); + self::assertStringContainsString('Event 5', $html); + self::assertStringContainsString('Event 6', $html); + self::assertStringContainsString('Event 7', $html); + self::assertStringContainsString('Event 8', $html); + self::assertStringContainsString('Event 9', $html); + } + + /** + * @test + */ + public function returnsDateBeforeEnd(): void + { + $this->importCSVDataSet(__DIR__ . '/DatesTestFixtures/ReturnsDateWithinTimeSpan.csv'); + + $request = new InternalRequest(); + $request = $request->withPageId(1); + $request = $request->withQueryParameters([ + 'events_search[search][end]' => '2023-02-17', + ]); + $response = $this->executeFrontendRequest($request); + + self::assertSame(200, $response->getStatusCode()); + $html = (string) $response->getBody(); + + self::assertStringContainsString('Event 1', $html); + self::assertStringContainsString('Event 2', $html); + self::assertStringNotContainsString('Event 3', $html); + self::assertStringNotContainsString('Event 4', $html); + self::assertStringContainsString('Event 5', $html); + self::assertStringContainsString('Event 6', $html); + self::assertStringContainsString('Event 7', $html); + self::assertStringContainsString('Event 8', $html); + self::assertStringContainsString('Event 9', $html); + } + + /** + * Covers issue https://redmine.werkraum-media.de/issues/10350. + * A date can span multiple dates. + * The visitor might search a time frame within the spaned dates and expects the date to be shown. + * + * @test + */ + public function returnsDateWithinTimeSpan(): void + { + $this->importCSVDataSet(__DIR__ . '/DatesTestFixtures/ReturnsDateWithinTimeSpan.csv'); + + $request = new InternalRequest(); + $request = $request->withPageId(1); + $request = $request->withQueryParameters([ + 'events_search[search][start]' => '2023-02-16', + 'events_search[search][end]' => '2023-02-17', + ]); + $response = $this->executeFrontendRequest($request); + + self::assertSame(200, $response->getStatusCode()); + $html = (string) $response->getBody(); + + self::assertStringNotContainsString('Event 1', $html); + self::assertStringNotContainsString('Event 2', $html); + self::assertStringNotContainsString('Event 3', $html); + self::assertStringNotContainsString('Event 4', $html); + self::assertStringContainsString('Event 5', $html); + self::assertStringContainsString('Event 6', $html); + self::assertStringContainsString('Event 7', $html); + self::assertStringContainsString('Event 8', $html); + self::assertStringContainsString('Event 9', $html); + } } diff --git a/Tests/Functional/Frontend/DatesTestFixtures/ReturnsDateWithinTimeSpan.csv b/Tests/Functional/Frontend/DatesTestFixtures/ReturnsDateWithinTimeSpan.csv new file mode 100644 index 0000000..d490d7e --- /dev/null +++ b/Tests/Functional/Frontend/DatesTestFixtures/ReturnsDateWithinTimeSpan.csv @@ -0,0 +1,25 @@ +tt_content +,uid,pid,CType,list_type,header +,1,1,list,events_datelist,All Dates +tx_events_domain_model_event +,uid,pid,title +,1,2,Event 1 starts before search, ends before search +,2,2,Event 2 starts before search, no end +,3,2,Event 3 starts after search, ends after search +,4,2,Event 4 starts after search, no end +,5,2,Event 5 starts before search, ends after search +,6,2,Event 6 starts inside search, ends inside search +,7,2,Event 7 starts inside search, ends after search +,8,2,Event 8 starts inside search, no end +,9,2,Event 9 starts before search, ends inside search +tx_events_domain_model_date +,uid,pid,event,start,end +,1,2,1,1676419200,1676484000 +,2,2,2,1676419200,0 +,3,2,3,1676678400,1676743200 +,4,2,4,1676678400,0 +,5,2,5,1676419200,1676678400 +,6,2,6,1676559600,1676570400 +,7,2,7,1676559600,1676678400 +,8,2,8,1676559600,0 +,9,2,9,1676419200,1676570400 diff --git a/ext_emconf.php b/ext_emconf.php index 6c446fb..274c764 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -9,7 +9,7 @@ $EM_CONF['events'] = [ 'state' => 'alpha', 'createDirs' => '', 'clearCacheOnLoad' => 0, - 'version' => '3.2.0', + 'version' => '3.2.1', 'constraints' => [ 'depends' => [ 'typo3' => '10.4.00-11.5.99',