Add event filter frontend module with server-side aggregates
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MummertMedia\EventManagerBundle\Controller\Frontend;
|
||||
|
||||
use Contao\CoreBundle\Controller\FrontendModule\AbstractFrontendModuleController;
|
||||
use Contao\CoreBundle\DependencyInjection\Attribute\AsFrontendModule;
|
||||
use Contao\CoreBundle\Twig\FragmentTemplate;
|
||||
use Contao\ModuleModel;
|
||||
use Contao\StringUtil;
|
||||
use Doctrine\DBAL\ArrayParameterType;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
#[AsFrontendModule(type: 'event_filter', category: 'eventmanager', template: 'frontend/event_filter')]
|
||||
class EventFilterController extends AbstractFrontendModuleController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Connection $connection,
|
||||
) {
|
||||
}
|
||||
|
||||
protected function getResponse(FragmentTemplate $template, ModuleModel $model, Request $request): Response
|
||||
{
|
||||
$calendarIds = array_map('intval', StringUtil::deserialize($model->cal_calendar, true));
|
||||
$eventIds = $this->findUpcomingEventIds($calendarIds);
|
||||
|
||||
$template->set('tagButtons', $this->findTagButtons($eventIds));
|
||||
$template->set('locations', $this->findLocations($eventIds));
|
||||
$template->set('organizations', $this->findOrganizations($eventIds));
|
||||
|
||||
return $template->getResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<int> $calendarIds
|
||||
*
|
||||
* @return list<int>
|
||||
*/
|
||||
private function findUpcomingEventIds(array $calendarIds): array
|
||||
{
|
||||
$today = strtotime('today');
|
||||
|
||||
if ([] === $calendarIds) {
|
||||
$rows = $this->connection->executeQuery(
|
||||
<<<'SQL'
|
||||
SELECT e.id
|
||||
FROM tl_calendar_events e
|
||||
INNER JOIN tl_calendar c ON c.id=e.pid
|
||||
WHERE e.published='1'
|
||||
AND c.published='1'
|
||||
AND (e.startTime>=? OR e.endTime>=?)
|
||||
ORDER BY e.startTime ASC
|
||||
SQL,
|
||||
[$today, $today],
|
||||
[\PDO::PARAM_INT, \PDO::PARAM_INT],
|
||||
)->fetchFirstColumn();
|
||||
} else {
|
||||
$rows = $this->connection->executeQuery(
|
||||
<<<'SQL'
|
||||
SELECT e.id
|
||||
FROM tl_calendar_events e
|
||||
INNER JOIN tl_calendar c ON c.id=e.pid
|
||||
WHERE e.pid IN (?)
|
||||
AND e.published='1'
|
||||
AND c.published='1'
|
||||
AND (e.startTime>=? OR e.endTime>=?)
|
||||
ORDER BY e.startTime ASC
|
||||
SQL,
|
||||
[$calendarIds, $today, $today],
|
||||
[ArrayParameterType::INTEGER, \PDO::PARAM_INT, \PDO::PARAM_INT],
|
||||
)->fetchFirstColumn();
|
||||
}
|
||||
|
||||
return array_values(array_unique(array_map('intval', $rows)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<int> $eventIds
|
||||
*
|
||||
* @return list<array{id:int,title:string,count:int}>
|
||||
*/
|
||||
private function findTagButtons(array $eventIds): array
|
||||
{
|
||||
if ([] === $eventIds) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$rows = $this->connection->executeQuery(
|
||||
<<<'SQL'
|
||||
SELECT t.id, t.tag, COUNT(DISTINCT r.item_id) AS total
|
||||
FROM tl_tags_rel r
|
||||
INNER JOIN tl_tags t ON t.id=r.tag_id
|
||||
WHERE r.ptable='tl_calendar_events'
|
||||
AND r.field='tags'
|
||||
AND r.item_id IN (?)
|
||||
GROUP BY t.id, t.tag
|
||||
ORDER BY t.tag ASC
|
||||
SQL,
|
||||
[$eventIds],
|
||||
[ArrayParameterType::INTEGER],
|
||||
)->fetchAllAssociative();
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$items[] = [
|
||||
'id' => (int) ($row['id'] ?? 0),
|
||||
'title' => (string) ($row['tag'] ?? ''),
|
||||
'count' => (int) ($row['total'] ?? 0),
|
||||
];
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<int> $eventIds
|
||||
*
|
||||
* @return list<array{id:int,title:string,count:int}>
|
||||
*/
|
||||
private function findLocations(array $eventIds): array
|
||||
{
|
||||
if ([] === $eventIds) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$rows = $this->connection->executeQuery(
|
||||
<<<'SQL'
|
||||
SELECT l.id, l.title, COUNT(e.id) AS total
|
||||
FROM tl_calendar_events e
|
||||
INNER JOIN tl_location l ON l.id=e.location
|
||||
WHERE e.id IN (?)
|
||||
AND e.location>0
|
||||
GROUP BY l.id, l.title
|
||||
ORDER BY l.title ASC
|
||||
SQL,
|
||||
[$eventIds],
|
||||
[ArrayParameterType::INTEGER],
|
||||
)->fetchAllAssociative();
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$items[] = [
|
||||
'id' => (int) ($row['id'] ?? 0),
|
||||
'title' => (string) ($row['title'] ?? ''),
|
||||
'count' => (int) ($row['total'] ?? 0),
|
||||
];
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<int> $eventIds
|
||||
*
|
||||
* @return list<array{id:int,title:string,count:int}>
|
||||
*/
|
||||
private function findOrganizations(array $eventIds): array
|
||||
{
|
||||
if ([] === $eventIds) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$rows = $this->connection->executeQuery(
|
||||
<<<'SQL'
|
||||
SELECT o.id, o.title, COUNT(DISTINCT rel.event_id) AS total
|
||||
FROM tl_calendar_events_organization rel
|
||||
INNER JOIN tl_organization o ON o.id=rel.organization_id
|
||||
WHERE rel.event_id IN (?)
|
||||
GROUP BY o.id, o.title
|
||||
ORDER BY o.title ASC
|
||||
SQL,
|
||||
[$eventIds],
|
||||
[ArrayParameterType::INTEGER],
|
||||
)->fetchAllAssociative();
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$items[] = [
|
||||
'id' => (int) ($row['id'] ?? 0),
|
||||
'title' => (string) ($row['title'] ?? ''),
|
||||
'count' => (int) ($row['total'] ?? 0),
|
||||
];
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user