From f3d4c857e00411578da38d1f1a9731fd164b0f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Mummert?= Date: Sun, 22 Feb 2026 17:53:17 +0100 Subject: [PATCH] Harden organization listing tag enrichment and simplify listener --- ...rganizationListingTemplateDataListener.php | 144 +++--------------- 1 file changed, 19 insertions(+), 125 deletions(-) diff --git a/src/EventListener/OrganizationListingTemplateDataListener.php b/src/EventListener/OrganizationListingTemplateDataListener.php index 370227b..282b8b8 100644 --- a/src/EventListener/OrganizationListingTemplateDataListener.php +++ b/src/EventListener/OrganizationListingTemplateDataListener.php @@ -55,16 +55,10 @@ class OrganizationListingTemplateDataListener $organizationTagMap = $this->fetchOrganizationTagMap($organizationIds); $organizationLogoUuidMap = $this->fetchOrganizationLogoUuidMap($organizationIds); - $organizationTagIdsMap = []; $organizationTagLabelMap = []; - $rowTagIdsMap = []; $rowTagIdsList = []; - foreach ($organizationTagMap as $organizationId => $tagData) { - if ([] !== ($tagData['ids'] ?? [])) { - $organizationTagIdsMap[(string) $organizationId] = implode(',', $tagData['ids']); - } - + foreach ($organizationTagMap as $tagData) { foreach (($tagData['ids'] ?? []) as $index => $tagId) { $label = trim((string) (($tagData['labels'][$index] ?? '') ?: '')); @@ -79,26 +73,15 @@ class OrganizationListingTemplateDataListener continue; } - $tagData = $organizationTagMap[$organizationId] ?? ['ids' => [], 'labels' => [], 'slugs' => []]; + $tagData = $organizationTagMap[$organizationId] ?? ['ids' => [], 'labels' => []]; $logoUuid = $organizationLogoUuidMap[$organizationId] ?? ''; $tagIdsCsv = implode(',', $tagData['ids']); $tagLabelsCsv = implode(', ', $tagData['labels']); - $tagSlugsCsv = implode(',', $tagData['slugs']); $tbody[$rowIndex]['tag_ids']['content'] = $tagIdsCsv; $tbody[$rowIndex]['tag_labels']['content'] = $tagLabelsCsv; - $tbody[$rowIndex]['tag_slugs']['content'] = $tagSlugsCsv; $tbody[$rowIndex]['tags']['content'] = $tagLabelsCsv; - $tbody[$rowIndex]['tag_ids'] = $tagIdsCsv; - $tbody[$rowIndex]['tag_labels'] = $tagLabelsCsv; - $tbody[$rowIndex]['tag_slugs'] = $tagSlugsCsv; - $tbody[$rowIndex]['tags'] = $tagLabelsCsv; - - if ('' !== $tagIdsCsv) { - $rowTagIdsMap[(string) $rowIndex] = $tagIdsCsv; - } - if ('' !== $logoUuid) { $tbody[$rowIndex]['logo_uuid']['content'] = $logoUuid; } @@ -119,7 +102,7 @@ class OrganizationListingTemplateDataListener if (null !== $this->logger) { $rowsWithoutTagIds = 0; - foreach ($rowToOrganizationIdMap as $rowIndex => $organizationId) { + foreach ($rowToOrganizationIdMap as $organizationId) { if (!isset($organizationTagMap[$organizationId]) || [] === ($organizationTagMap[$organizationId]['ids'] ?? [])) { ++$rowsWithoutTagIds; } @@ -135,9 +118,7 @@ class OrganizationListingTemplateDataListener } } - $template->organization_tag_ids_map = $organizationTagIdsMap; $template->organization_tag_label_map = $organizationTagLabelMap; - $template->organization_row_tag_ids_map = $rowTagIdsMap; $template->organization_row_tag_ids_list = $rowTagIdsList; $template->tbody = $tbody; @@ -229,7 +210,7 @@ class OrganizationListingTemplateDataListener } /** @param list $organizationIds - * @return array, labels: list, slugs: list}> + * @return array, labels: list}> */ private function fetchOrganizationTagMap(array $organizationIds): array { @@ -237,46 +218,25 @@ class OrganizationListingTemplateDataListener return []; } - $scope = $this->resolveTagRelationScope($organizationIds); - - $conditions = ['r.pid IN (?)']; - $params = [$organizationIds]; - $types = [ArrayParameterType::INTEGER]; - - if ('' === $scope['ptable']) { - $conditions[] = "(r.ptable = '' OR r.ptable IS NULL)"; - } else { - $conditions[] = 'r.ptable = ?'; - $params[] = $scope['ptable']; - $types[] = ParameterType::STRING; - } - - if ('' === $scope['field']) { - $conditions[] = "(r.field = '' OR r.field IS NULL)"; - } else { - $conditions[] = 'r.field = ?'; - $params[] = $scope['field']; - $types[] = ParameterType::STRING; - } - $rows = $this->connection->executeQuery( - 'SELECT r.pid AS organization_id, r.tag_id, t.tag AS label FROM tl_tags_rel r INNER JOIN tl_tags t ON t.id = r.tag_id WHERE '.implode(' AND ', $conditions).' ORDER BY r.pid ASC, r.tag_id ASC', - $params, - $types, + 'SELECT r.pid AS organization_id, r.tag_id, t.tag AS label + FROM tl_tags_rel r + INNER JOIN tl_tags t ON t.id = r.tag_id + WHERE r.ptable = ? AND r.field = ? AND r.pid IN (?) + ORDER BY r.pid ASC, r.tag_id ASC', + ['tl_organization', 'tags', $organizationIds], + [ParameterType::STRING, ParameterType::STRING, ArrayParameterType::INTEGER], )->fetchAllAssociative(); - if ([] === $rows && '' !== $scope['field']) { - $fieldFreeConditions = array_values(array_filter($conditions, static fn (string $condition): bool => 'r.field = ?' !== $condition)); - $fieldFreeParams = $params; - $fieldFreeTypes = $types; - - array_pop($fieldFreeParams); - array_pop($fieldFreeTypes); - + if ([] === $rows) { $rows = $this->connection->executeQuery( - 'SELECT r.pid AS organization_id, r.tag_id, t.tag AS label FROM tl_tags_rel r INNER JOIN tl_tags t ON t.id = r.tag_id WHERE '.implode(' AND ', $fieldFreeConditions).' ORDER BY r.pid ASC, r.tag_id ASC', - $fieldFreeParams, - $fieldFreeTypes, + 'SELECT r.pid AS organization_id, r.tag_id, t.tag AS label + FROM tl_tags_rel r + INNER JOIN tl_tags t ON t.id = r.tag_id + WHERE r.ptable = ? AND r.pid IN (?) + ORDER BY r.pid ASC, r.tag_id ASC', + ['tl_organization', $organizationIds], + [ParameterType::STRING, ArrayParameterType::INTEGER], )->fetchAllAssociative(); } @@ -295,62 +255,16 @@ class OrganizationListingTemplateDataListener $seen[$organizationId][$tagId] = true; $map[$organizationId]['ids'][] = (string) $tagId; $map[$organizationId]['labels'][] = $label; - - $slug = $this->slugify($label); - - if ('' !== $slug) { - $map[$organizationId]['slugs'][] = $slug; - } } foreach ($map as $organizationId => $tagData) { $map[$organizationId]['ids'] = array_values(array_unique($tagData['ids'] ?? [])); $map[$organizationId]['labels'] = array_values(array_unique($tagData['labels'] ?? [])); - $map[$organizationId]['slugs'] = array_values(array_unique($tagData['slugs'] ?? [])); } return $map; } - /** @param list $organizationIds - * @return array{ptable: string, field: string} - */ - private function resolveTagRelationScope(array $organizationIds): array - { - $rows = $this->connection->executeQuery( - "SELECT COALESCE(NULLIF(TRIM(r.ptable), ''), '') AS ptable_scope, COALESCE(NULLIF(TRIM(r.field), ''), '') AS field_scope, COUNT(DISTINCT r.pid) AS pid_count, COUNT(*) AS rel_count FROM tl_tags_rel r WHERE r.pid IN (?) GROUP BY COALESCE(NULLIF(TRIM(r.ptable), ''), ''), COALESCE(NULLIF(TRIM(r.field), ''), '') ORDER BY pid_count DESC, rel_count DESC", - [$organizationIds], - [ArrayParameterType::INTEGER], - )->fetchAllAssociative(); - - if ([] === $rows) { - return ['ptable' => 'tl_organization', 'field' => 'tags']; - } - - foreach ($rows as $row) { - if ('tl_organization' === (string) ($row['ptable_scope'] ?? '') && 'tags' === (string) ($row['field_scope'] ?? '')) { - return ['ptable' => 'tl_organization', 'field' => 'tags']; - } - } - - foreach ($rows as $row) { - if ('tl_organization' === (string) ($row['ptable_scope'] ?? '')) { - return ['ptable' => 'tl_organization', 'field' => (string) ($row['field_scope'] ?? '')]; - } - } - - foreach ($rows as $row) { - if ('tags' === (string) ($row['field_scope'] ?? '')) { - return ['ptable' => (string) ($row['ptable_scope'] ?? ''), 'field' => 'tags']; - } - } - - return [ - 'ptable' => (string) ($rows[0]['ptable_scope'] ?? 'tl_organization'), - 'field' => (string) ($rows[0]['field_scope'] ?? 'tags'), - ]; - } - /** @param list $organizationIds * @return array */ @@ -409,24 +323,4 @@ class OrganizationListingTemplateDataListener return ''; } - private function slugify(string $value): string - { - $value = trim(mb_strtolower($value)); - - if ('' === $value) { - return ''; - } - - $value = strtr($value, [ - 'ä' => 'ae', - 'ö' => 'oe', - 'ü' => 'ue', - 'ß' => 'ss', - ]); - - $value = preg_replace('/[^a-z0-9]+/u', '-', $value) ?? ''; - $value = trim($value, '-'); - - return $value; - } }