*/ 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, '/'); } }