diff --git a/src/EventListener/OrganizationListingTemplateDataListener.php b/src/EventListener/OrganizationListingTemplateDataListener.php new file mode 100644 index 0000000..6b8932c --- /dev/null +++ b/src/EventListener/OrganizationListingTemplateDataListener.php @@ -0,0 +1,281 @@ +getName()) { + return; + } + + $tbody = $template->tbody; + + if (!\is_array($tbody) || [] === $tbody) { + return; + } + + $rowToOrganizationIdMap = []; + + foreach ($tbody as $rowIndex => $row) { + if (!\is_array($row)) { + continue; + } + + $organizationId = $this->extractOrganizationId($row); + + if ($organizationId > 0) { + $rowToOrganizationIdMap[(int) $rowIndex] = $organizationId; + } + } + + if ([] === $rowToOrganizationIdMap) { + return; + } + + $organizationTagMap = $this->fetchOrganizationTagMap(array_values(array_unique(array_values($rowToOrganizationIdMap)))); + $organizationLogoUuidMap = $this->fetchOrganizationLogoUuidMap(array_values(array_unique(array_values($rowToOrganizationIdMap)))); + + foreach ($rowToOrganizationIdMap as $rowIndex => $organizationId) { + $tagData = $organizationTagMap[$organizationId] ?? ['labels' => [], 'slugs' => []]; + $logoUuid = $organizationLogoUuidMap[$organizationId] ?? ''; + + if (!isset($tbody[$rowIndex]) || !\is_array($tbody[$rowIndex])) { + continue; + } + + $tbody[$rowIndex]['tag_labels']['content'] = implode(', ', $tagData['labels']); + $tbody[$rowIndex]['tag_slugs']['content'] = implode(',', $tagData['slugs']); + $tbody[$rowIndex]['tags']['content'] = implode(', ', $tagData['labels']); + + if ('' !== $logoUuid) { + $tbody[$rowIndex]['logo_uuid']['content'] = $logoUuid; + } + } + + $template->tbody = $tbody; + } + + /** @param array $row */ + private function extractOrganizationId(array $row): int + { + foreach (['id', 'organization_id', 'org_id'] as $fieldName) { + $value = $this->extractRowFieldContent($row, $fieldName); + + if ('' !== $value && ctype_digit($value)) { + return (int) $value; + } + } + + $urlCandidates = []; + + foreach ($row as $column) { + if (!\is_array($column)) { + continue; + } + + if (isset($column['url']) && \is_scalar($column['url'])) { + $urlCandidates[] = (string) $column['url']; + } + + if (isset($column['href']) && \is_scalar($column['href'])) { + $urlCandidates[] = (string) $column['href']; + } + } + + foreach ($urlCandidates as $url) { + $organizationId = $this->extractIdFromUrl($url); + + if ($organizationId > 0) { + return $organizationId; + } + } + + return 0; + } + + /** @param array $row */ + private function extractRowFieldContent(array $row, string $fieldName): string + { + if (!isset($row[$fieldName]) || !\is_array($row[$fieldName])) { + return ''; + } + + $field = $row[$fieldName]; + + if (!isset($field['content']) || !\is_scalar($field['content'])) { + return ''; + } + + return trim((string) $field['content']); + } + + private function extractIdFromUrl(string $url): int + { + $parts = parse_url($url); + + if (!\is_array($parts) || !isset($parts['query'])) { + return 0; + } + + parse_str((string) $parts['query'], $query); + + foreach (['show', 'id'] as $queryKey) { + if (!isset($query[$queryKey])) { + continue; + } + + $value = $query[$queryKey]; + + if (\is_scalar($value) && ctype_digit((string) $value)) { + return (int) $value; + } + } + + return 0; + } + + /** @param list $organizationIds + * @return array, slugs: list}> + */ + private function fetchOrganizationTagMap(array $organizationIds): array + { + if ([] === $organizationIds) { + return []; + } + + $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 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(); + + $map = []; + $seen = []; + + foreach ($rows as $row) { + $organizationId = (int) ($row['organization_id'] ?? 0); + $tagId = (int) ($row['tag_id'] ?? 0); + $label = trim((string) ($row['label'] ?? '')); + + if ($organizationId <= 0 || $tagId <= 0 || '' === $label) { + continue; + } + + if (isset($seen[$organizationId][$tagId])) { + continue; + } + + $seen[$organizationId][$tagId] = true; + $map[$organizationId]['labels'][] = $label; + + $slug = $this->slugify($label); + + if ('' !== $slug) { + $map[$organizationId]['slugs'][] = $slug; + } + } + + foreach ($map as $organizationId => $tagData) { + $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 + */ + private function fetchOrganizationLogoUuidMap(array $organizationIds): array + { + if ([] === $organizationIds) { + return []; + } + + $rows = $this->connection->executeQuery( + 'SELECT o.id AS organization_id, o.logo AS logo_uuid FROM tl_organization o WHERE o.id IN (?)', + [$organizationIds], + [ArrayParameterType::INTEGER], + )->fetchAllAssociative(); + + $map = []; + + foreach ($rows as $row) { + $organizationId = (int) ($row['organization_id'] ?? 0); + $logoUuid = $this->normalizeUuid($row['logo_uuid'] ?? null); + + if ($organizationId <= 0 || '' === $logoUuid) { + continue; + } + + $map[$organizationId] = $logoUuid; + } + + return $map; + } + + private function normalizeUuid(mixed $value): string + { + if (null === $value) { + return ''; + } + + if (\is_resource($value)) { + $value = stream_get_contents($value) ?: ''; + } + + $trimmed = trim((string) $value); + + if ('' === $trimmed) { + return ''; + } + + if (preg_match('/^[0-9a-fA-F-]{36}$/', $trimmed)) { + return strtolower($trimmed); + } + + if (16 === strlen($trimmed)) { + return StringUtil::binToUuid($trimmed); + } + + 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; + } +}