179 lines
7.0 KiB
PHP
179 lines
7.0 KiB
PHP
<?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\PageModel;
|
|
use Contao\StringUtil;
|
|
use MummertMedia\EventManagerBundle\Service\MapModuleDataProvider;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
#[AsFrontendModule(type: 'eventmanager_map', category: 'eventmanager', template: 'frontend/event_map')]
|
|
class EventMapController extends AbstractFrontendModuleController
|
|
{
|
|
private const MAP_STYLE_URL = 'https://maps.mummert.media/metadaten/world-light.json';
|
|
private const DEFAULT_CENTER_MODE = 'markers';
|
|
private const DEFAULT_EVENT_COLOR = '#BC5067';
|
|
private const DEFAULT_INITIAL_DISPLAY = 'random';
|
|
|
|
/**
|
|
* @var list<string>
|
|
*/
|
|
private const ALLOWED_INITIAL_DISPLAYS = ['random', 'events', 'organization_tag'];
|
|
|
|
public function __construct(
|
|
private readonly MapModuleDataProvider $mapModuleDataProvider,
|
|
) {
|
|
}
|
|
|
|
protected function getResponse(FragmentTemplate $template, ModuleModel $model, Request $request): Response
|
|
{
|
|
$containerId = sprintf('eventmanager-map-%d', (int) ($model->id ?? 0));
|
|
$dataElementId = sprintf('%s-data', $containerId);
|
|
$filterWrapperId = sprintf('%s-filter', $containerId);
|
|
$filterGroupId = sprintf('%s-filter-group', $containerId);
|
|
$showOrganizations = '1' === (string) ($model->mapShowOrganizations ?? '');
|
|
$showExternalOrganizations = '1' === (string) ($model->mapShowExternalOrganizations ?? '');
|
|
$showEvents = '1' === (string) ($model->mapShowEvents ?? '');
|
|
$selectedOrganizationTagIds = array_values(array_unique(array_filter(
|
|
array_map('intval', StringUtil::deserialize($model->organizationTypeTags ?? null, true)),
|
|
static fn (int $tagId): bool => $tagId > 0,
|
|
)));
|
|
$availableOrganizationTags = $this->mapModuleDataProvider->getOrganizationTags();
|
|
$availableOrganizationTagIds = array_map(
|
|
static fn (array $tag): int => (int) ($tag['id'] ?? 0),
|
|
$availableOrganizationTags,
|
|
);
|
|
$selectedOrganizationTagIds = [] === $selectedOrganizationTagIds
|
|
? []
|
|
: array_values(array_intersect($selectedOrganizationTagIds, $availableOrganizationTagIds));
|
|
$organizationListPageId = (int) ($model->mapOrganizationListPage ?? 0);
|
|
$organizationListBaseUrl = $this->buildOrganizationListBaseUrl($organizationListPageId, $request);
|
|
$initialDisplay = (string) ($model->mapInitialDisplay ?? self::DEFAULT_INITIAL_DISPLAY);
|
|
$initialOrganizationTagId = (int) ($model->mapInitialOrganizationTagId ?? 0);
|
|
$centerMode = (string) ($model->mapCenterMode ?? self::DEFAULT_CENTER_MODE);
|
|
$mapPitch = $this->normalizePitch($model->mapPitch ?? 0);
|
|
$eventColor = $this->normalizeHexColor((string) ($model->mapEventColor ?? self::DEFAULT_EVENT_COLOR));
|
|
$organizationColor = $this->normalizeHexColor((string) ($model->mapOrganizationColor ?? $eventColor), $eventColor);
|
|
|
|
if (!in_array($centerMode, ['markers', 'custom'], true)) {
|
|
$centerMode = self::DEFAULT_CENTER_MODE;
|
|
}
|
|
|
|
if (!in_array($initialDisplay, self::ALLOWED_INITIAL_DISPLAYS, true)) {
|
|
$initialDisplay = self::DEFAULT_INITIAL_DISPLAY;
|
|
}
|
|
|
|
if ($initialOrganizationTagId < 0) {
|
|
$initialOrganizationTagId = 0;
|
|
}
|
|
|
|
$template->set('mapContainerId', $containerId);
|
|
$template->set('mapDataElementId', $dataElementId);
|
|
$template->set('mapFilterWrapperId', $filterWrapperId);
|
|
$template->set('mapFilterGroupId', $filterGroupId);
|
|
$template->set('mapStyleUrl', self::MAP_STYLE_URL);
|
|
$template->set('mapShowOrganizations', $showOrganizations);
|
|
$template->set('mapShowEvents', $showEvents);
|
|
$template->set('mapCenterMode', $centerMode);
|
|
$template->set('mapEventColor', $eventColor);
|
|
$template->set('mapOrganizationColor', $organizationColor);
|
|
$template->set('mapInitialDisplay', $initialDisplay);
|
|
$template->set('mapInitialTagId', $initialOrganizationTagId);
|
|
$template->set('mapCenterLat', trim((string) ($model->mapCenterLat ?? '')));
|
|
$template->set('mapCenterLng', trim((string) ($model->mapCenterLng ?? '')));
|
|
$template->set('mapCenterZoom', (int) ($model->mapCenterZoom ?? 12));
|
|
$template->set('mapPitch', $mapPitch);
|
|
$template->set('mapItemsJson', json_encode(
|
|
$this->mapModuleDataProvider->getMapItems($showOrganizations, $showEvents, $showExternalOrganizations, $selectedOrganizationTagIds, $organizationListBaseUrl),
|
|
\JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_APOS | \JSON_HEX_QUOT | \JSON_UNESCAPED_UNICODE | \JSON_THROW_ON_ERROR,
|
|
));
|
|
$template->set('mapOrganizationTags', $this->mapModuleDataProvider->getOrganizationTags($selectedOrganizationTagIds));
|
|
|
|
return $template->getResponse();
|
|
}
|
|
|
|
private function normalizeHexColor(string $value, string $fallback = self::DEFAULT_EVENT_COLOR): string
|
|
{
|
|
$normalized = strtoupper(trim($value));
|
|
|
|
if (preg_match('/^#[0-9A-F]{6}$/', $normalized)) {
|
|
return $normalized;
|
|
}
|
|
|
|
if (preg_match('/^[0-9A-F]{6}$/', $normalized)) {
|
|
return '#'.$normalized;
|
|
}
|
|
|
|
if (preg_match('/^#[0-9A-F]{3}$/', $normalized)) {
|
|
return sprintf(
|
|
'#%1$s%1$s%2$s%2$s%3$s%3$s',
|
|
$normalized[1],
|
|
$normalized[2],
|
|
$normalized[3],
|
|
);
|
|
}
|
|
|
|
if (preg_match('/^[0-9A-F]{3}$/', $normalized)) {
|
|
return sprintf(
|
|
'#%1$s%1$s%2$s%2$s%3$s%3$s',
|
|
$normalized[0],
|
|
$normalized[1],
|
|
$normalized[2],
|
|
);
|
|
}
|
|
|
|
return $fallback;
|
|
}
|
|
|
|
private function normalizePitch(mixed $value): int
|
|
{
|
|
if (!is_scalar($value)) {
|
|
return 0;
|
|
}
|
|
|
|
$parsedPitch = (int) round((float) str_replace(',', '.', (string) $value));
|
|
|
|
if ($parsedPitch < 0) {
|
|
return 0;
|
|
}
|
|
|
|
if ($parsedPitch > 85) {
|
|
return 85;
|
|
}
|
|
|
|
return $parsedPitch;
|
|
}
|
|
|
|
private function buildOrganizationListBaseUrl(int $pageId, Request $request): string
|
|
{
|
|
if ($pageId <= 0) {
|
|
return '';
|
|
}
|
|
|
|
$pageModel = PageModel::findById($pageId);
|
|
|
|
if (null === $pageModel) {
|
|
return '';
|
|
}
|
|
|
|
$frontendUrl = trim((string) $pageModel->getFrontendUrl());
|
|
|
|
if ('' === $frontendUrl) {
|
|
return '';
|
|
}
|
|
|
|
if (preg_match('#^https?://#i', $frontendUrl)) {
|
|
return $frontendUrl;
|
|
}
|
|
|
|
return rtrim($request->getSchemeAndHttpHost(), '/').'/'.ltrim($frontendUrl, '/');
|
|
}
|
|
}
|