added date selection and filter popup

This commit is contained in:
Hendrik Behme committed 2026-10-09 16:26:56 +02:00
1 parent 739a1eee28
commit 36ed3880e8
16 files changed
+741 -180

No files matched your search

+35 -33
View File
@@ -56,7 +56,7 @@ class EventRepository extends ServiceEntityRepository
*/
public function distancesWithinRadius(float $lat, float $lon, float $radiusKm, int $limit = 500): array
{
// end_date comparison mirrors notEnded()/filterByWhen(): day-level
// end_date comparison mirrors notEnded()/filterByDateRange(): day-level
// lexicographic comparison against the raw ISO-ish string column,
// in Europe/Berlin — this is raw SQL (DBAL, not the QueryBuilder),
// so it can't just call that helper directly.
@@ -124,7 +124,7 @@ class EventRepository extends ServiceEntityRepository
*
* @return Event[]
*/
public function search(?string $q, ?string $category, string $when, int $limit, int $offset, ?array $locationIds = null, string $sort = 'soonest'): array
public function search(?string $q, ?string $category, ?string $dateFrom, ?string $dateTo, int $limit, int $offset, ?array $locationIds = null, string $sort = 'soonest'): array
{
// "Nearest" only means anything once a location narrowed the pool.
if ('nearest' === $sort && null === $locationIds) {
@@ -137,7 +137,7 @@ class EventRepository extends ServiceEntityRepository
}
$matchingIds = array_map('intval', array_column(
$this->baseSearchQb($q, $category, $when)
$this->baseSearchQb($q, $category, $dateFrom, $dateTo)
->select('e.id')
->andWhere('e.id IN (:locationIds)')
->setParameter('locationIds', $locationIds)
@@ -156,7 +156,7 @@ class EventRepository extends ServiceEntityRepository
return [];
}
$qb = $this->baseSearchQb($q, $category, $when);
$qb = $this->baseSearchQb($q, $category, $dateFrom, $dateTo);
if (null !== $locationIds) {
$qb->andWhere('e.id IN (:locationIds)')->setParameter('locationIds', $locationIds);
}
@@ -178,13 +178,13 @@ class EventRepository extends ServiceEntityRepository
*
* @param int[]|null $locationIds
*/
public function countSearch(?string $q, ?string $category, string $when, ?array $locationIds = null): int
public function countSearch(?string $q, ?string $category, ?string $dateFrom, ?string $dateTo, ?array $locationIds = null): int
{
if (null !== $locationIds && !$locationIds) {
return 0;
}
$qb = $this->baseSearchQb($q, $category, $when)->select('COUNT(DISTINCT e.id)');
$qb = $this->baseSearchQb($q, $category, $dateFrom, $dateTo)->select('COUNT(DISTINCT e.id)');
if (null !== $locationIds) {
$qb->andWhere('e.id IN (:locationIds)')->setParameter('locationIds', $locationIds);
@@ -193,7 +193,7 @@ class EventRepository extends ServiceEntityRepository
return (int) $qb->getQuery()->getSingleScalarResult();
}
private function baseSearchQb(?string $q, ?string $category, string $when): QueryBuilder
private function baseSearchQb(?string $q, ?string $category, ?string $dateFrom, ?string $dateTo): QueryBuilder
{
$qb = $this->notEnded($this->notDeleted());
@@ -203,45 +203,47 @@ class EventRepository extends ServiceEntityRepository
}
$this->filterByCategory($qb, $category);
$this->filterByWhen($qb, $when);
$this->filterByDateRange($qb, $dateFrom, $dateTo);
return $qb;
}
/**
* startDate is a raw ISO-8601-ish string ("2026-09-12T18:00:00+02:00"),
* consistently formatted across the imported dataset, so a plain
* lexicographic string comparison against a "Y-m-d" boundary sorts
* correctly without needing to parse it as a real date/time column.
* Keeps events that are happening at some point within the inclusive
* day range [$dateFrom, $dateTo] ("Y-m-d", either end optional) — i.e.
* the event overlaps the window, so a multi-day exhibition shows up
* for any day it's running, not just the day it opened.
*
* start_date/end_date are raw ISO-8601-ish strings
* ("2026-09-12T18:00:00+02:00"), consistently formatted across the
* imported dataset, so a plain lexicographic comparison against a
* "Y-m-d" boundary sorts correctly without parsing them as real
* date/time columns. The upper bound compares against the *next* day
* with "<", since "2026-09-12T18:00" > "2026-09-12" as strings.
* Applied in SQL (not PHP, post-fetch) so it composes correctly with
* pagination and COUNT — filtering after LIMIT/OFFSET would make the
* page size and total count lie.
* page size and total count lie. Undated events (blank start_date)
* are excluded once a range is active; a blank end_date falls back to
* the start alone.
*/
private function filterByWhen(QueryBuilder $qb, string $when): void
private function filterByDateRange(QueryBuilder $qb, ?string $dateFrom, ?string $dateTo): void
{
if ('any' === $when) {
if (!$dateFrom && !$dateTo) {
return;
}
// Explicit timezone, not the container's (UTC): the imported dates
// and the site's audience are both German-local, so "today" needs
// to mean the German calendar day, not whatever day it happens to
// be in UTC — those disagree for two hours after every UTC
// midnight.
$start = new \DateTimeImmutable('today', new \DateTimeZone('Europe/Berlin'));
$end = match ($when) {
'today' => $start->modify('+1 day'),
'week' => $start->modify('+7 days'),
default => null,
};
$qb->andWhere("e.startDate <> ''");
if (!$end) {
return;
if ($dateTo) {
$dayAfterTo = (new \DateTimeImmutable($dateTo, new \DateTimeZone('Europe/Berlin')))->modify('+1 day');
$qb->andWhere('e.startDate < :rangeToExclusive')
->setParameter('rangeToExclusive', $dayAfterTo->format('Y-m-d'));
}
$qb->andWhere('e.startDate >= :whenStart AND e.startDate < :whenEnd')
->setParameter('whenStart', $start->format('Y-m-d'))
->setParameter('whenEnd', $end->format('Y-m-d'));
if ($dateFrom) {
$qb->andWhere("e.endDate >= :rangeFrom OR (e.endDate = '' AND e.startDate >= :rangeFrom)")
->setParameter('rangeFrom', $dateFrom);
}
}
/**
@@ -289,8 +291,8 @@ class EventRepository extends ServiceEntityRepository
/**
* Hides events that have already ended — compared by calendar day
* (Europe/Berlin), the same precision filterByWhen() uses for
* "today"/"week", not exact time (end_date is a raw ISO-ish string,
* (Europe/Berlin), the same precision filterByDateRange() uses,
* not exact time (end_date is a raw ISO-ish string,
* not a real date/time column). Blank end_date is treated as "still
* current" rather than excluded, matching orderByStartDate()'s
* defensive handling of blank date strings.