Compare commits

...

2 Commits

Author SHA1 Message Date
Jürgen Mummert 51a92ea45e Map tags: load live organization tags and sanitize selections 2026-02-26 22:00:12 +01:00
Jürgen Mummert 1a4811cb02 Fix backend pitch visibility and tag marker mapping 2026-02-26 21:46:27 +01:00
3 changed files with 79 additions and 14 deletions
+43 -7
View File
@@ -9,7 +9,7 @@ use Contao\StringUtil;
$GLOBALS['TL_DCA']['tl_module']['palettes']['member_organizations'] = '{title_legend},name,headline,type;{eventmanager_legend},editPage;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID'; $GLOBALS['TL_DCA']['tl_module']['palettes']['member_organizations'] = '{title_legend},name,headline,type;{eventmanager_legend},editPage;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
$GLOBALS['TL_DCA']['tl_module']['palettes']['member_events'] = '{title_legend},name,headline,type;{eventmanager_legend},editPage;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID'; $GLOBALS['TL_DCA']['tl_module']['palettes']['member_events'] = '{title_legend},name,headline,type;{eventmanager_legend},editPage;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
$GLOBALS['TL_DCA']['tl_module']['palettes']['event_filter'] = '{title_legend},name,headline,type;{eventmanager_legend},cal_calendar,eventListDomId;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID'; $GLOBALS['TL_DCA']['tl_module']['palettes']['event_filter'] = '{title_legend},name,headline,type;{eventmanager_legend},cal_calendar,eventListDomId;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
$GLOBALS['TL_DCA']['tl_module']['palettes']['eventmanager_map'] = '{title_legend},name,headline,type;{eventmanager_legend},mapShowOrganizations,organizationTypeTags,mapShowExternalOrganizations,mapShowEvents,mapInitialDisplay,mapEventColor,mapOrganizationColor,mapCenterMode;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID'; $GLOBALS['TL_DCA']['tl_module']['palettes']['eventmanager_map'] = '{title_legend},name,headline,type;{eventmanager_legend},mapShowOrganizations,organizationTypeTags,mapShowExternalOrganizations,mapShowEvents,mapInitialDisplay,mapEventColor,mapOrganizationColor,mapPitch,mapCenterMode;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
$GLOBALS['TL_DCA']['tl_module']['palettes']['organization_edit'] = '{title_legend},name,headline,type;{eventmanager_legend},listPage,logoFolder,organizationTypeTags;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID'; $GLOBALS['TL_DCA']['tl_module']['palettes']['organization_edit'] = '{title_legend},name,headline,type;{eventmanager_legend},listPage,logoFolder,organizationTypeTags;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
$GLOBALS['TL_DCA']['tl_module']['palettes']['event_edit'] = '{title_legend},name,headline,type;{eventmanager_legend},listPage,eventFolder,termsPage,frontendAuthorId,frontendArchiveId,eventTypeTags;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID'; $GLOBALS['TL_DCA']['tl_module']['palettes']['event_edit'] = '{title_legend},name,headline,type;{eventmanager_legend},listPage,eventFolder,termsPage,frontendAuthorId,frontendArchiveId,eventTypeTags;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
@@ -74,15 +74,33 @@ $GLOBALS['TL_DCA']['tl_module']['fields']['organizationTypeTags'] = [
'exclude' => true, 'exclude' => true,
'inputType' => 'checkbox', 'inputType' => 'checkbox',
'options_callback' => static function () { 'options_callback' => static function () {
$database = Database::getInstance();
$labelExpression = $database->fieldExists('title', 'tl_tags')
? "COALESCE(NULLIF(t.title, ''), t.tag)"
: 't.tag';
$rows = Database::getInstance() $rows = Database::getInstance()
->prepare('SELECT DISTINCT t.id, t.tag FROM tl_tags t LEFT JOIN tl_tags_rel r ON r.tag_id=t.id AND r.ptable=? AND r.field=? ORDER BY t.tag ASC') ->prepare(sprintf(
'SELECT DISTINCT t.id, %1$s AS label
FROM tl_tags_rel r
INNER JOIN tl_tags t ON t.id=r.tag_id
WHERE r.ptable=? AND r.field=?
ORDER BY label ASC',
$labelExpression,
))
->execute('tl_organization', 'tags') ->execute('tl_organization', 'tags')
->fetchAllAssoc(); ->fetchAllAssoc();
$options = []; $options = [];
foreach ($rows as $row) { foreach ($rows as $row) {
$options[(int) $row['id']] = (string) $row['tag']; $label = trim((string) ($row['label'] ?? ''));
if ('' === $label) {
continue;
}
$options[(int) $row['id']] = $label;
} }
return $options; return $options;
@@ -162,7 +180,7 @@ $GLOBALS['TL_DCA']['tl_module']['fields']['eventListDomId'] = [
$GLOBALS['TL_DCA']['tl_module']['palettes']['__selector__'][] = 'mapCenterMode'; $GLOBALS['TL_DCA']['tl_module']['palettes']['__selector__'][] = 'mapCenterMode';
$GLOBALS['TL_DCA']['tl_module']['palettes']['__selector__'][] = 'mapInitialDisplay'; $GLOBALS['TL_DCA']['tl_module']['palettes']['__selector__'][] = 'mapInitialDisplay';
$GLOBALS['TL_DCA']['tl_module']['subpalettes']['mapCenterMode_custom'] = 'mapCenterLat,mapCenterLng,mapCenterZoom,mapPitch'; $GLOBALS['TL_DCA']['tl_module']['subpalettes']['mapCenterMode_custom'] = 'mapCenterLat,mapCenterLng,mapCenterZoom';
$GLOBALS['TL_DCA']['tl_module']['subpalettes']['mapInitialDisplay_organization_tag'] = 'mapInitialOrganizationTagId'; $GLOBALS['TL_DCA']['tl_module']['subpalettes']['mapInitialDisplay_organization_tag'] = 'mapInitialOrganizationTagId';
$GLOBALS['TL_DCA']['tl_module']['fields']['mapShowOrganizations'] = [ $GLOBALS['TL_DCA']['tl_module']['fields']['mapShowOrganizations'] = [
@@ -204,15 +222,33 @@ $GLOBALS['TL_DCA']['tl_module']['fields']['mapInitialOrganizationTagId'] = [
'exclude' => true, 'exclude' => true,
'inputType' => 'select', 'inputType' => 'select',
'options_callback' => static function (): array { 'options_callback' => static function (): array {
$rows = Database::getInstance() $database = Database::getInstance();
->prepare('SELECT DISTINCT t.id, t.tag FROM tl_tags t LEFT JOIN tl_tags_rel r ON r.tag_id=t.id AND r.ptable=? AND r.field=? ORDER BY t.tag ASC') $labelExpression = $database->fieldExists('title', 'tl_tags')
? "COALESCE(NULLIF(t.title, ''), t.tag)"
: 't.tag';
$rows = $database
->prepare(sprintf(
'SELECT DISTINCT t.id, %1$s AS label
FROM tl_tags_rel r
INNER JOIN tl_tags t ON t.id=r.tag_id
WHERE r.ptable=? AND r.field=?
ORDER BY label ASC',
$labelExpression,
))
->execute('tl_organization', 'tags') ->execute('tl_organization', 'tags')
->fetchAllAssoc(); ->fetchAllAssoc();
$options = []; $options = [];
foreach ($rows as $row) { foreach ($rows as $row) {
$options[(int) $row['id']] = (string) $row['tag']; $label = trim((string) ($row['label'] ?? ''));
if ('' === $label) {
continue;
}
$options[(int) $row['id']] = $label;
} }
return $options; return $options;
@@ -44,6 +44,14 @@ class EventMapController extends AbstractFrontendModuleController
array_map('intval', StringUtil::deserialize($model->organizationTypeTags ?? null, true)), array_map('intval', StringUtil::deserialize($model->organizationTypeTags ?? null, true)),
static fn (int $tagId): bool => $tagId > 0, 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));
$initialDisplay = (string) ($model->mapInitialDisplay ?? self::DEFAULT_INITIAL_DISPLAY); $initialDisplay = (string) ($model->mapInitialDisplay ?? self::DEFAULT_INITIAL_DISPLAY);
$initialOrganizationTagId = (int) ($model->mapInitialOrganizationTagId ?? 0); $initialOrganizationTagId = (int) ($model->mapInitialOrganizationTagId ?? 0);
$centerMode = (string) ($model->mapCenterMode ?? self::DEFAULT_CENTER_MODE); $centerMode = (string) ($model->mapCenterMode ?? self::DEFAULT_CENTER_MODE);
+28 -7
View File
@@ -150,7 +150,7 @@ class MapModuleDataProvider
*/ */
public function getOrganizationTags(array $selectedTagIds = []): array public function getOrganizationTags(array $selectedTagIds = []): array
{ {
if (!$this->tableExists('tl_tags')) { if (!$this->tableExists('tl_tags') || !$this->tableExists('tl_tags_rel')) {
return []; return [];
} }
@@ -168,8 +168,13 @@ class MapModuleDataProvider
$qb = $this->connection->createQueryBuilder(); $qb = $this->connection->createQueryBuilder();
$qb $qb
->select('t.id', sprintf('t.%s AS label', $labelColumn)) ->select('DISTINCT t.id', sprintf('t.%s AS label', $labelColumn))
->from('tl_tags', 't') ->from('tl_tags_rel', 'r')
->innerJoin('r', 'tl_tags', 't', 't.id = r.tag_id')
->andWhere('r.ptable = :organization_ptable')
->andWhere('(r.field = :organization_field OR r.field IS NULL OR r.field = \'\')')
->setParameter('organization_ptable', 'tl_organization')
->setParameter('organization_field', 'tags')
->orderBy(sprintf('t.%s', $labelColumn), 'ASC'); ->orderBy(sprintf('t.%s', $labelColumn), 'ASC');
if ([] !== $selectedTagIds) { if ([] !== $selectedTagIds) {
@@ -216,23 +221,36 @@ class MapModuleDataProvider
return []; return [];
} }
$tagColumns = $this->getColumnMap('tl_tags');
$tagLabelColumn = isset($tagColumns['title']) ? 'title' : (isset($tagColumns['tag']) ? 'tag' : null);
if (null === $tagLabelColumn) {
return [];
}
$rows = $this->connection->executeQuery( $rows = $this->connection->executeQuery(
'SELECT r.pid AS organization_id, r.tag_id, t.tag AS label sprintf(
'SELECT r.pid AS organization_id, r.tag_id, t.%s AS label
FROM tl_tags_rel r FROM tl_tags_rel r
INNER JOIN tl_tags t ON t.id = r.tag_id INNER JOIN tl_tags t ON t.id = r.tag_id
WHERE r.ptable = ? AND r.field = ? AND r.pid IN (?) WHERE r.ptable = ? AND r.field = ? AND r.pid IN (?)
ORDER BY r.pid ASC, r.tag_id ASC', ORDER BY r.pid ASC, r.tag_id ASC',
$tagLabelColumn,
),
['tl_organization', 'tags', $organizationIds], ['tl_organization', 'tags', $organizationIds],
[ParameterType::STRING, ParameterType::STRING, ArrayParameterType::INTEGER], [ParameterType::STRING, ParameterType::STRING, ArrayParameterType::INTEGER],
)->fetchAllAssociative(); )->fetchAllAssociative();
if ([] === $rows) { if ([] === $rows) {
$rows = $this->connection->executeQuery( $rows = $this->connection->executeQuery(
'SELECT r.pid AS organization_id, r.tag_id, t.tag AS label sprintf(
'SELECT r.pid AS organization_id, r.tag_id, t.%s AS label
FROM tl_tags_rel r FROM tl_tags_rel r
INNER JOIN tl_tags t ON t.id = r.tag_id INNER JOIN tl_tags t ON t.id = r.tag_id
WHERE r.ptable = ? AND r.pid IN (?) WHERE r.ptable = ? AND r.pid IN (?)
ORDER BY r.pid ASC, r.tag_id ASC', ORDER BY r.pid ASC, r.tag_id ASC',
$tagLabelColumn,
),
['tl_organization', $organizationIds], ['tl_organization', $organizationIds],
[ParameterType::STRING, ArrayParameterType::INTEGER], [ParameterType::STRING, ArrayParameterType::INTEGER],
)->fetchAllAssociative(); )->fetchAllAssociative();
@@ -246,13 +264,16 @@ class MapModuleDataProvider
$tagId = (int) ($row['tag_id'] ?? 0); $tagId = (int) ($row['tag_id'] ?? 0);
$label = trim((string) ($row['label'] ?? '')); $label = trim((string) ($row['label'] ?? ''));
if ($organizationId <= 0 || $tagId <= 0 || '' === $label || isset($seen[$organizationId][$tagId])) { if ($organizationId <= 0 || $tagId <= 0 || isset($seen[$organizationId][$tagId])) {
continue; continue;
} }
$seen[$organizationId][$tagId] = true; $seen[$organizationId][$tagId] = true;
$map[$organizationId]['ids'][] = (string) $tagId; $map[$organizationId]['ids'][] = (string) $tagId;
$map[$organizationId]['labels'][] = $label;
if ('' !== $label) {
$map[$organizationId]['labels'][] = $label;
}
} }
foreach ($map as $organizationId => $tagData) { foreach ($map as $organizationId => $tagData) {