This commit is contained in:
@@ -55,6 +55,7 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter. Kernbereiche sind l
|
|||||||
- Neue Kategorien bleiben dort sichtbar, bis sie von einem Berechtigten bestätigt oder mit einer bestehenden Kategorie zusammengeführt werden.
|
- Neue Kategorien bleiben dort sichtbar, bis sie von einem Berechtigten bestätigt oder mit einer bestehenden Kategorie zusammengeführt werden.
|
||||||
- Im Bereich `Kategorien` gibt es zusätzlich eine Suche über bestehende Kategorien, damit sie gezielt gefunden und zusammengeführt werden können.
|
- Im Bereich `Kategorien` gibt es zusätzlich eine Suche über bestehende Kategorien, damit sie gezielt gefunden und zusammengeführt werden können.
|
||||||
- Beim Zusammenführen wird die nicht zu behaltende Kategorie anschließend vollständig entfernt und die Ansicht danach frisch neu geladen.
|
- Beim Zusammenführen wird die nicht zu behaltende Kategorie anschließend vollständig entfernt und die Ansicht danach frisch neu geladen.
|
||||||
|
- Zusammengeführte Kategorien werden zusätzlich intern als Redirect gesperrt, damit Standard-Seed oder spätere Eingaben sie nicht erneut auswählbar machen.
|
||||||
- Beim Zusammenführen kann explizit festgelegt werden, welche der beiden Kategorien erhalten bleibt.
|
- Beim Zusammenführen kann explizit festgelegt werden, welche der beiden Kategorien erhalten bleibt.
|
||||||
- Community-Level können zusätzlich die Rechte für Kategorien sowie für die Freigabe von Orten und Veranstaltungen tragen.
|
- Community-Level können zusätzlich die Rechte für Kategorien sowie für die Freigabe von Orten und Veranstaltungen tragen.
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ Papa-Kind-Treff is a PHP-based platform for fathers. Core areas are local events
|
|||||||
- New categories remain visible there until an authorized user confirms them or merges them into an existing category.
|
- New categories remain visible there until an authorized user confirms them or merges them into an existing category.
|
||||||
- The `Categories` area also includes a search across existing categories so they can be found and merged directly.
|
- The `Categories` area also includes a search across existing categories so they can be found and merged directly.
|
||||||
- During merging, the category that should not be kept is removed completely and the view is reloaded fresh afterwards.
|
- During merging, the category that should not be kept is removed completely and the view is reloaded fresh afterwards.
|
||||||
|
- Merged categories are additionally blocked internally through redirects so default seeding or later inputs cannot make them selectable again.
|
||||||
- During merging, it is now possible to explicitly choose which of the two categories should be kept.
|
- During merging, it is now possible to explicitly choose which of the two categories should be kept.
|
||||||
- Community levels can now additionally carry the rights for category handling as well as place and event approvals.
|
- Community levels can now additionally carry the rights for category handling as well as place and event approvals.
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter mit Fokus auf:
|
|||||||
- Neue Kategorien bleiben im Bereich `Kategorien` sichtbar, bis sie von einem Berechtigten bestätigt oder zusammengeführt werden
|
- Neue Kategorien bleiben im Bereich `Kategorien` sichtbar, bis sie von einem Berechtigten bestätigt oder zusammengeführt werden
|
||||||
- Im Bereich `Kategorien` gibt es zusätzlich eine Suche über bestehende Kategorien, damit sie gezielt gefunden und zusammengeführt werden können
|
- Im Bereich `Kategorien` gibt es zusätzlich eine Suche über bestehende Kategorien, damit sie gezielt gefunden und zusammengeführt werden können
|
||||||
- Beim Zusammenführen wird die nicht zu behaltende Kategorie anschließend vollständig entfernt und die Ansicht danach frisch neu geladen
|
- Beim Zusammenführen wird die nicht zu behaltende Kategorie anschließend vollständig entfernt und die Ansicht danach frisch neu geladen
|
||||||
|
- Zusammengeführte Kategorien werden zusätzlich intern als Redirect gesperrt, damit Standard-Seed oder spätere Eingaben sie nicht erneut auswählbar machen
|
||||||
- Beim Zusammenführen von Kategorien kann jetzt explizit festgelegt werden, welche der beiden Kategorien erhalten bleibt
|
- Beim Zusammenführen von Kategorien kann jetzt explizit festgelegt werden, welche der beiden Kategorien erhalten bleibt
|
||||||
- Community-Level können jetzt zusätzlich die Rechte für Kategorien sowie für die Freigabe von Orten und Veranstaltungen tragen
|
- Community-Level können jetzt zusätzlich die Rechte für Kategorien sowie für die Freigabe von Orten und Veranstaltungen tragen
|
||||||
- neue interne Grundstruktur: `listing_places`, `listings`, `listing_occurrences`, `listing_prices`, `listing_benefits`
|
- neue interne Grundstruktur: `listing_places`, `listings`, `listing_occurrences`, `listing_prices`, `listing_benefits`
|
||||||
|
|||||||
@@ -24,6 +24,13 @@ final class ListingCatalog
|
|||||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci',
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci',
|
||||||
|
'CREATE TABLE IF NOT EXISTS listing_category_redirects (
|
||||||
|
old_slug VARCHAR(120) NOT NULL PRIMARY KEY,
|
||||||
|
old_title VARCHAR(160) NOT NULL,
|
||||||
|
target_slug VARCHAR(120) NOT NULL,
|
||||||
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
INDEX idx_listing_category_redirects_target (target_slug)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci',
|
||||||
'CREATE TABLE IF NOT EXISTS listing_places (
|
'CREATE TABLE IF NOT EXISTS listing_places (
|
||||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||||
created_by BIGINT UNSIGNED NULL,
|
created_by BIGINT UNSIGNED NULL,
|
||||||
@@ -186,7 +193,15 @@ final class ListingCatalog
|
|||||||
VALUES (:slug, :title, :groupName, :sortOrder)
|
VALUES (:slug, :title, :groupName, :sortOrder)
|
||||||
ON DUPLICATE KEY UPDATE title = VALUES(title), category_group = VALUES(category_group), sort_order = VALUES(sort_order), updated_at = CURRENT_TIMESTAMP'
|
ON DUPLICATE KEY UPDATE title = VALUES(title), category_group = VALUES(category_group), sort_order = VALUES(sort_order), updated_at = CURRENT_TIMESTAMP'
|
||||||
);
|
);
|
||||||
|
$redirectedSlugs = [];
|
||||||
|
$redirectStmt = $this->pdo->query('SELECT old_slug FROM listing_category_redirects');
|
||||||
|
foreach (($redirectStmt ? $redirectStmt->fetchAll(\PDO::FETCH_COLUMN) : []) as $redirectedSlug) {
|
||||||
|
$redirectedSlugs[(string)$redirectedSlug] = true;
|
||||||
|
}
|
||||||
foreach ($this->defaultCategories() as $index => $category) {
|
foreach ($this->defaultCategories() as $index => $category) {
|
||||||
|
if (isset($redirectedSlugs[(string)$category['slug']])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$seed->execute([
|
$seed->execute([
|
||||||
'slug' => $category['slug'],
|
'slug' => $category['slug'],
|
||||||
'title' => $category['title'],
|
'title' => $category['title'],
|
||||||
@@ -247,6 +262,15 @@ final class ListingCatalog
|
|||||||
}
|
}
|
||||||
|
|
||||||
$slug = $this->slugify($input);
|
$slug = $this->slugify($input);
|
||||||
|
$redirect = $this->findCategoryRedirect($slug, $input);
|
||||||
|
if ($redirect !== null) {
|
||||||
|
$resolved = $this->findCategoryBySlug($redirect['target_slug']);
|
||||||
|
if ($resolved !== null) {
|
||||||
|
$resolved['is_new'] = false;
|
||||||
|
return $resolved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$stmt = $this->pdo->prepare(
|
$stmt = $this->pdo->prepare(
|
||||||
'SELECT id, slug, title, category_group, sort_order
|
'SELECT id, slug, title, category_group, sort_order
|
||||||
FROM listing_categories
|
FROM listing_categories
|
||||||
@@ -292,6 +316,8 @@ final class ListingCatalog
|
|||||||
(SELECT COUNT(*) FROM listing_category_map m WHERE m.category_id = c.id) AS listing_count,
|
(SELECT COUNT(*) FROM listing_category_map m WHERE m.category_id = c.id) AS listing_count,
|
||||||
(SELECT COUNT(*) FROM listing_places p WHERE p.place_kind = c.slug) AS place_count
|
(SELECT COUNT(*) FROM listing_places p WHERE p.place_kind = c.slug) AS place_count
|
||||||
FROM listing_categories c
|
FROM listing_categories c
|
||||||
|
LEFT JOIN listing_category_redirects r ON r.old_slug = c.slug
|
||||||
|
WHERE r.old_slug IS NULL
|
||||||
ORDER BY
|
ORDER BY
|
||||||
CASE WHEN c.sort_order >= 900 THEN 0 ELSE 1 END,
|
CASE WHEN c.sort_order >= 900 THEN 0 ELSE 1 END,
|
||||||
c.sort_order ASC,
|
c.sort_order ASC,
|
||||||
@@ -343,7 +369,9 @@ final class ListingCatalog
|
|||||||
(SELECT COUNT(*) FROM listing_category_map m WHERE m.category_id = c.id) AS listing_count,
|
(SELECT COUNT(*) FROM listing_category_map m WHERE m.category_id = c.id) AS listing_count,
|
||||||
(SELECT COUNT(*) FROM listing_places p WHERE p.place_kind = c.slug) AS place_count
|
(SELECT COUNT(*) FROM listing_places p WHERE p.place_kind = c.slug) AS place_count
|
||||||
FROM listing_categories c
|
FROM listing_categories c
|
||||||
WHERE ' . implode(' AND ', $conditions) . '
|
LEFT JOIN listing_category_redirects r ON r.old_slug = c.slug
|
||||||
|
WHERE r.old_slug IS NULL
|
||||||
|
AND ' . implode(' AND ', $conditions) . '
|
||||||
ORDER BY
|
ORDER BY
|
||||||
CASE
|
CASE
|
||||||
WHEN LOWER(c.title) = :exactTitle THEN 0
|
WHEN LOWER(c.title) = :exactTitle THEN 0
|
||||||
@@ -400,6 +428,17 @@ final class ListingCatalog
|
|||||||
|
|
||||||
$this->pdo->beginTransaction();
|
$this->pdo->beginTransaction();
|
||||||
try {
|
try {
|
||||||
|
$redirectUpsert = $this->pdo->prepare(
|
||||||
|
'INSERT INTO listing_category_redirects (old_slug, old_title, target_slug)
|
||||||
|
VALUES (:oldSlug, :oldTitle, :targetSlug)
|
||||||
|
ON DUPLICATE KEY UPDATE old_title = VALUES(old_title), target_slug = VALUES(target_slug)'
|
||||||
|
);
|
||||||
|
$redirectUpsert->execute([
|
||||||
|
'oldSlug' => $sourceSlug,
|
||||||
|
'oldTitle' => $sourceTitle,
|
||||||
|
'targetSlug' => $targetSlug,
|
||||||
|
]);
|
||||||
|
|
||||||
$mapRows = $this->pdo->prepare('SELECT listing_id FROM listing_category_map WHERE category_id = :categoryId');
|
$mapRows = $this->pdo->prepare('SELECT listing_id FROM listing_category_map WHERE category_id = :categoryId');
|
||||||
$mapRows->execute(['categoryId' => $sourceId]);
|
$mapRows->execute(['categoryId' => $sourceId]);
|
||||||
$listingIds = $mapRows->fetchAll(\PDO::FETCH_COLUMN) ?: [];
|
$listingIds = $mapRows->fetchAll(\PDO::FETCH_COLUMN) ?: [];
|
||||||
@@ -484,6 +523,12 @@ final class ListingCatalog
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$slug = $this->slugify($input);
|
||||||
|
$redirect = $this->findCategoryRedirect($slug, $input);
|
||||||
|
if ($redirect !== null) {
|
||||||
|
return $redirect['target_slug'];
|
||||||
|
}
|
||||||
|
|
||||||
$stmt = $this->pdo->prepare(
|
$stmt = $this->pdo->prepare(
|
||||||
'SELECT slug
|
'SELECT slug
|
||||||
FROM listing_categories
|
FROM listing_categories
|
||||||
@@ -492,13 +537,42 @@ final class ListingCatalog
|
|||||||
LIMIT 1'
|
LIMIT 1'
|
||||||
);
|
);
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
'slug' => $input,
|
'slug' => $slug,
|
||||||
'title' => $input,
|
'title' => $input,
|
||||||
]);
|
]);
|
||||||
$slug = $stmt->fetchColumn();
|
$slug = $stmt->fetchColumn();
|
||||||
return $slug !== false ? (string)$slug : null;
|
return $slug !== false ? (string)$slug : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function findCategoryRedirect(string $slug, string $title): ?array
|
||||||
|
{
|
||||||
|
$stmt = $this->pdo->prepare(
|
||||||
|
'SELECT old_slug, old_title, target_slug
|
||||||
|
FROM listing_category_redirects
|
||||||
|
WHERE old_slug = :slug OR LOWER(old_title) = LOWER(:title)
|
||||||
|
LIMIT 1'
|
||||||
|
);
|
||||||
|
$stmt->execute([
|
||||||
|
'slug' => $slug,
|
||||||
|
'title' => $title,
|
||||||
|
]);
|
||||||
|
$row = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||||
|
return $row ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function findCategoryBySlug(string $slug): ?array
|
||||||
|
{
|
||||||
|
$stmt = $this->pdo->prepare(
|
||||||
|
'SELECT id, slug, title, category_group, sort_order
|
||||||
|
FROM listing_categories
|
||||||
|
WHERE slug = :slug
|
||||||
|
LIMIT 1'
|
||||||
|
);
|
||||||
|
$stmt->execute(['slug' => $slug]);
|
||||||
|
$row = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||||
|
return $row ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
public function listPublishedDirectoryEntries(): array
|
public function listPublishedDirectoryEntries(): array
|
||||||
{
|
{
|
||||||
$this->ensureSchema();
|
$this->ensureSchema();
|
||||||
|
|||||||
Reference in New Issue
Block a user