This commit is contained in:
@@ -39,6 +39,8 @@ final class ListingCatalog
|
||||
website_url VARCHAR(255) NULL,
|
||||
phone VARCHAR(60) NULL,
|
||||
place_kind VARCHAR(80) NULL,
|
||||
opening_hours_note TEXT NULL,
|
||||
opening_hours_json LONGTEXT NULL,
|
||||
provider_hint ENUM("manual","osm","google") NOT NULL DEFAULT "manual",
|
||||
external_place_id VARCHAR(190) NULL,
|
||||
google_place_id VARCHAR(190) NULL,
|
||||
@@ -62,6 +64,8 @@ final class ListingCatalog
|
||||
title VARCHAR(200) NOT NULL,
|
||||
teaser_public VARCHAR(280) NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
image_path VARCHAR(255) NULL,
|
||||
special_conditions_note TEXT NULL,
|
||||
visibility ENUM("public","members") NOT NULL DEFAULT "public",
|
||||
status ENUM("draft","published","cancelled","archived") NOT NULL DEFAULT "draft",
|
||||
supports_registration TINYINT(1) NOT NULL DEFAULT 0,
|
||||
@@ -145,6 +149,9 @@ final class ListingCatalog
|
||||
|
||||
$columnStatements = [
|
||||
'listing_places.opening_hours_note' => 'ALTER TABLE listing_places ADD COLUMN opening_hours_note TEXT NULL AFTER place_kind',
|
||||
'listing_places.opening_hours_json' => 'ALTER TABLE listing_places ADD COLUMN opening_hours_json LONGTEXT NULL AFTER opening_hours_note',
|
||||
'listings.image_path' => 'ALTER TABLE listings ADD COLUMN image_path VARCHAR(255) NULL AFTER description',
|
||||
'listings.special_conditions_note' => 'ALTER TABLE listings ADD COLUMN special_conditions_note TEXT NULL AFTER image_path',
|
||||
];
|
||||
foreach ($columnStatements as $key => $sql) {
|
||||
[$table, $column] = explode('.', $key, 2);
|
||||
@@ -214,7 +221,7 @@ final class ListingCatalog
|
||||
{
|
||||
$this->ensureSchema();
|
||||
$stmt = $this->pdo->prepare(
|
||||
'SELECT l.id, l.listing_type, l.title, l.teaser_public, l.visibility, l.status,
|
||||
'SELECT l.id, l.listing_type, l.title, l.teaser_public, l.visibility, l.status, l.image_path,
|
||||
lp.title AS place_title, lp.city, lp.region, lp.place_kind,
|
||||
lo.starts_at, lo.ends_at, lo.occurrence_type,
|
||||
lc.title AS category_title, lc.slug AS category_slug
|
||||
@@ -241,9 +248,9 @@ final class ListingCatalog
|
||||
{
|
||||
$this->ensureSchema();
|
||||
$stmt = $this->pdo->prepare(
|
||||
'SELECT l.*, lp.title AS place_title, lp.description AS place_description, lp.street, lp.zip, lp.city, lp.region, lp.lat, lp.lng, lp.place_kind, lp.opening_hours_note,
|
||||
'SELECT l.*, lp.title AS place_title, lp.description AS place_description, lp.street, lp.zip, lp.city, lp.region, lp.lat, lp.lng, lp.place_kind, lp.phone, lp.website_url, lp.opening_hours_note, lp.opening_hours_json,
|
||||
lo.id AS occurrence_id, lo.starts_at, lo.ends_at, lo.occurrence_type,
|
||||
lo.recurrence_rule, lo.recurrence_until,
|
||||
lo.recurrence_rule, lo.recurrence_until, lo.capacity_total,
|
||||
lc.slug AS category_slug
|
||||
FROM listings l
|
||||
LEFT JOIN listing_places lp ON lp.id = l.primary_place_id
|
||||
@@ -262,6 +269,7 @@ final class ListingCatalog
|
||||
return null;
|
||||
}
|
||||
$row['prices'] = $this->listPrices((int)$row['id']);
|
||||
$row['opening_hours'] = $this->decodeJsonRows((string)($row['opening_hours_json'] ?? ''));
|
||||
return $row;
|
||||
}
|
||||
|
||||
@@ -292,22 +300,28 @@ final class ListingCatalog
|
||||
$teaser = trim((string)($data['teaser'] ?? ''));
|
||||
$description = trim((string)($data['description'] ?? ''));
|
||||
$openingHoursNote = trim((string)($data['opening_hours_note'] ?? ''));
|
||||
$openingHoursRows = $this->normalizeOpeningHoursRows($data);
|
||||
$visibility = (string)($data['visibility'] ?? 'public');
|
||||
$placeKind = trim((string)($data['category_slug'] ?? ''));
|
||||
$customCategoryTitle = trim((string)($data['category_custom_title'] ?? ''));
|
||||
$street = trim((string)($data['street'] ?? ''));
|
||||
$zip = trim((string)($data['zip'] ?? ''));
|
||||
$city = trim((string)($data['city'] ?? ''));
|
||||
$region = trim((string)($data['region'] ?? ''));
|
||||
$phone = trim((string)($data['phone'] ?? ''));
|
||||
$websiteUrl = trim((string)($data['website_url'] ?? ''));
|
||||
$lat = isset($data['lat']) && $data['lat'] !== '' ? (float)$data['lat'] : null;
|
||||
$lng = isset($data['lng']) && $data['lng'] !== '' ? (float)$data['lng'] : null;
|
||||
$startsAt = trim((string)($data['starts_at'] ?? ''));
|
||||
$recurrenceMode = (string)($data['recurrence_mode'] ?? 'single');
|
||||
$recurrenceUntil = trim((string)($data['recurrence_until'] ?? ''));
|
||||
$weekdayValues = array_values(array_filter(array_map('strval', (array)($data['recurrence_weekdays'] ?? []))));
|
||||
$priceMode = (string)($data['price_mode'] ?? 'none');
|
||||
$specialConditionsNote = trim((string)($data['special_conditions_note'] ?? ''));
|
||||
$imagePath = trim((string)($data['image_path'] ?? ''));
|
||||
$capacityTotal = isset($data['capacity_total']) && $data['capacity_total'] !== '' ? (int)$data['capacity_total'] : null;
|
||||
|
||||
if ($title === '' || $teaser === '' || $description === '') {
|
||||
throw new \RuntimeException('Bitte fülle Titel, Kurzbeschreibung und Beschreibung aus.');
|
||||
if ($title === '' || $description === '') {
|
||||
throw new \RuntimeException('Bitte fülle Titel und Beschreibung aus.');
|
||||
}
|
||||
if (!in_array($visibility, ['public', 'members'], true)) {
|
||||
$visibility = 'public';
|
||||
@@ -315,16 +329,13 @@ final class ListingCatalog
|
||||
if ($entryType === 'editorial_event' && $startsAt === '') {
|
||||
throw new \RuntimeException('Bitte gib für sonstige Veranstaltungen ein Datum an.');
|
||||
}
|
||||
if ($entryType === 'editorial_event' && $recurrenceUntil === '') {
|
||||
throw new \RuntimeException('Bitte gib für Veranstaltungen ein Gültig-bis-Datum an.');
|
||||
}
|
||||
|
||||
$this->pdo->beginTransaction();
|
||||
try {
|
||||
$categoryId = null;
|
||||
if ($placeKind !== '') {
|
||||
$catStmt = $this->pdo->prepare('SELECT id FROM listing_categories WHERE slug = :slug LIMIT 1');
|
||||
$catStmt->execute(['slug' => $placeKind]);
|
||||
$categoryId = $catStmt->fetchColumn();
|
||||
$categoryId = $categoryId !== false ? (int)$categoryId : null;
|
||||
}
|
||||
[$placeKind, $categoryId] = $this->resolveCategory($placeKind, $customCategoryTitle);
|
||||
|
||||
if ($listingId !== null && $listingId > 0) {
|
||||
$existing = $this->getDashboardEntry($userId, $listingId);
|
||||
@@ -335,7 +346,9 @@ final class ListingCatalog
|
||||
if ($placeId > 0) {
|
||||
$placeStmt = $this->pdo->prepare(
|
||||
'UPDATE listing_places
|
||||
SET title = :title, description = :description, street = :street, zip = :zip, city = :city, region = :region, lat = :lat, lng = :lng, place_kind = :placeKind, opening_hours_note = :openingHoursNote, updated_at = NOW()
|
||||
SET title = :title, description = :description, street = :street, zip = :zip, city = :city, region = :region,
|
||||
lat = :lat, lng = :lng, website_url = :websiteUrl, phone = :phone, place_kind = :placeKind,
|
||||
opening_hours_note = :openingHoursNote, opening_hours_json = :openingHoursJson, updated_at = NOW()
|
||||
WHERE id = :id'
|
||||
);
|
||||
$placeStmt->execute([
|
||||
@@ -347,33 +360,43 @@ final class ListingCatalog
|
||||
'region' => $region !== '' ? $region : null,
|
||||
'lat' => $lat,
|
||||
'lng' => $lng,
|
||||
'websiteUrl' => $websiteUrl !== '' ? $websiteUrl : null,
|
||||
'phone' => $phone !== '' ? $phone : null,
|
||||
'placeKind' => $placeKind !== '' ? $placeKind : null,
|
||||
'openingHoursNote' => $openingHoursNote !== '' ? $openingHoursNote : null,
|
||||
'openingHoursJson' => $openingHoursRows !== [] ? json_encode($openingHoursRows, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) : null,
|
||||
'id' => $placeId,
|
||||
]);
|
||||
}
|
||||
$listingStmt = $this->pdo->prepare(
|
||||
'UPDATE listings
|
||||
SET listing_type = :listingType, title = :title, teaser_public = :teaser, description = :description, visibility = :visibility,
|
||||
supports_registration = 0, supports_capacity = 0, supports_pricing = 0, is_recurring = 0, status = "published", updated_at = NOW()
|
||||
SET listing_type = :listingType, title = :title, teaser_public = :teaser, description = :description,
|
||||
image_path = :imagePath, special_conditions_note = :specialConditionsNote, visibility = :visibility,
|
||||
supports_registration = 0, supports_capacity = :supportsCapacity, supports_pricing = :supportsPricing,
|
||||
is_recurring = :isRecurring, status = "published", updated_at = NOW()
|
||||
WHERE id = :id AND created_by = :uid'
|
||||
);
|
||||
$listingStmt->execute([
|
||||
'listingType' => $entryType,
|
||||
'title' => $title,
|
||||
'teaser' => $teaser,
|
||||
'teaser' => $teaser !== '' ? $teaser : $title,
|
||||
'description' => $description,
|
||||
'imagePath' => $imagePath !== '' ? $imagePath : null,
|
||||
'specialConditionsNote' => $specialConditionsNote !== '' ? $specialConditionsNote : null,
|
||||
'visibility' => $visibility,
|
||||
'supportsCapacity' => $capacityTotal !== null ? 1 : 0,
|
||||
'supportsPricing' => $this->hasPriceRows($data) || $specialConditionsNote !== '' ? 1 : 0,
|
||||
'isRecurring' => $entryType === 'editorial_event' && $recurrenceMode !== 'single' ? 1 : 0,
|
||||
'id' => $listingId,
|
||||
'uid' => $userId,
|
||||
]);
|
||||
|
||||
$this->pdo->prepare('DELETE FROM listing_occurrences WHERE listing_id = :listingId')->execute(['listingId' => $listingId]);
|
||||
$this->saveOccurrenceAndPrices($listingId, $entryType, $startsAt, $recurrenceMode, $weekdayValues, $recurrenceUntil, $priceMode, $data);
|
||||
$this->saveOccurrenceAndPrices($listingId, $entryType, $startsAt, $recurrenceMode, $weekdayValues, $recurrenceUntil, $capacityTotal, $data);
|
||||
} else {
|
||||
$placeStmt = $this->pdo->prepare(
|
||||
'INSERT INTO listing_places (created_by, source_type, title, description, street, zip, city, region, lat, lng, place_kind, opening_hours_note, provider_hint, status, created_at, updated_at)
|
||||
VALUES (:uid, "user", :title, :description, :street, :zip, :city, :region, :lat, :lng, :placeKind, :openingHoursNote, "manual", "published", NOW(), NOW())'
|
||||
'INSERT INTO listing_places (created_by, source_type, title, description, street, zip, city, region, lat, lng, website_url, phone, place_kind, opening_hours_note, opening_hours_json, provider_hint, status, created_at, updated_at)
|
||||
VALUES (:uid, "user", :title, :description, :street, :zip, :city, :region, :lat, :lng, :websiteUrl, :phone, :placeKind, :openingHoursNote, :openingHoursJson, "manual", "published", NOW(), NOW())'
|
||||
);
|
||||
$placeStmt->execute([
|
||||
'uid' => $userId,
|
||||
@@ -385,27 +408,35 @@ final class ListingCatalog
|
||||
'region' => $region !== '' ? $region : null,
|
||||
'lat' => $lat,
|
||||
'lng' => $lng,
|
||||
'websiteUrl' => $websiteUrl !== '' ? $websiteUrl : null,
|
||||
'phone' => $phone !== '' ? $phone : null,
|
||||
'placeKind' => $placeKind !== '' ? $placeKind : null,
|
||||
'openingHoursNote' => $openingHoursNote !== '' ? $openingHoursNote : null,
|
||||
'openingHoursJson' => $openingHoursRows !== [] ? json_encode($openingHoursRows, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) : null,
|
||||
]);
|
||||
$placeId = (int)$this->pdo->lastInsertId();
|
||||
|
||||
$listingStmt = $this->pdo->prepare(
|
||||
'INSERT INTO listings (created_by, owner_type, listing_type, primary_place_id, title, teaser_public, description, visibility, status, supports_registration, supports_capacity, supports_pricing, is_recurring, created_at, updated_at)
|
||||
VALUES (:uid, "user", :listingType, :placeId, :title, :teaser, :description, :visibility, "published", 0, 0, 0, 0, NOW(), NOW())'
|
||||
'INSERT INTO listings (created_by, owner_type, listing_type, primary_place_id, title, teaser_public, description, image_path, special_conditions_note, visibility, status, supports_registration, supports_capacity, supports_pricing, is_recurring, created_at, updated_at)
|
||||
VALUES (:uid, "user", :listingType, :placeId, :title, :teaser, :description, :imagePath, :specialConditionsNote, :visibility, "published", 0, :supportsCapacity, :supportsPricing, :isRecurring, NOW(), NOW())'
|
||||
);
|
||||
$listingStmt->execute([
|
||||
'uid' => $userId,
|
||||
'listingType' => $entryType,
|
||||
'placeId' => $placeId,
|
||||
'title' => $title,
|
||||
'teaser' => $teaser,
|
||||
'teaser' => $teaser !== '' ? $teaser : $title,
|
||||
'description' => $description,
|
||||
'imagePath' => $imagePath !== '' ? $imagePath : null,
|
||||
'specialConditionsNote' => $specialConditionsNote !== '' ? $specialConditionsNote : null,
|
||||
'visibility' => $visibility,
|
||||
'supportsCapacity' => $capacityTotal !== null ? 1 : 0,
|
||||
'supportsPricing' => $this->hasPriceRows($data) || $specialConditionsNote !== '' ? 1 : 0,
|
||||
'isRecurring' => $entryType === 'editorial_event' && $recurrenceMode !== 'single' ? 1 : 0,
|
||||
]);
|
||||
$listingId = (int)$this->pdo->lastInsertId();
|
||||
|
||||
$this->saveOccurrenceAndPrices($listingId, $entryType, $startsAt, $recurrenceMode, $weekdayValues, $recurrenceUntil, $priceMode, $data);
|
||||
$this->saveOccurrenceAndPrices($listingId, $entryType, $startsAt, $recurrenceMode, $weekdayValues, $recurrenceUntil, $capacityTotal, $data);
|
||||
}
|
||||
|
||||
$this->pdo->prepare('DELETE FROM listing_category_map WHERE listing_id = :listingId')->execute(['listingId' => $listingId]);
|
||||
@@ -427,14 +458,14 @@ final class ListingCatalog
|
||||
}
|
||||
}
|
||||
|
||||
private function saveOccurrenceAndPrices(int $listingId, string $entryType, string $startsAt, string $recurrenceMode, array $weekdayValues, string $recurrenceUntil, string $priceMode, array $data): void
|
||||
private function saveOccurrenceAndPrices(int $listingId, string $entryType, string $startsAt, string $recurrenceMode, array $weekdayValues, string $recurrenceUntil, ?int $capacityTotal, array $data): void
|
||||
{
|
||||
$occurrenceId = null;
|
||||
if ($entryType === 'editorial_event') {
|
||||
[$occurrenceType, $recurrenceRule] = $this->buildRecurrence($recurrenceMode, $weekdayValues);
|
||||
$occStmt = $this->pdo->prepare(
|
||||
'INSERT INTO listing_occurrences (listing_id, occurrence_type, starts_at, recurrence_rule, recurrence_until, status, created_at, updated_at)
|
||||
VALUES (:listingId, :occurrenceType, :startsAt, :recurrenceRule, :recurrenceUntil, "scheduled", NOW(), NOW())'
|
||||
'INSERT INTO listing_occurrences (listing_id, occurrence_type, starts_at, recurrence_rule, recurrence_until, capacity_total, status, created_at, updated_at)
|
||||
VALUES (:listingId, :occurrenceType, :startsAt, :recurrenceRule, :recurrenceUntil, :capacityTotal, "scheduled", NOW(), NOW())'
|
||||
);
|
||||
$occStmt->execute([
|
||||
'listingId' => $listingId,
|
||||
@@ -442,12 +473,14 @@ final class ListingCatalog
|
||||
'startsAt' => $startsAt !== '' ? $startsAt : null,
|
||||
'recurrenceRule' => $recurrenceRule,
|
||||
'recurrenceUntil' => $recurrenceUntil !== '' ? $recurrenceUntil : null,
|
||||
'capacityTotal' => $capacityTotal,
|
||||
]);
|
||||
$occurrenceId = (int)$this->pdo->lastInsertId();
|
||||
}
|
||||
|
||||
$this->pdo->prepare('DELETE FROM listing_prices WHERE listing_id = :listingId')->execute(['listingId' => $listingId]);
|
||||
if ($priceMode === 'none') {
|
||||
$priceRows = $this->normalizePriceRows($data);
|
||||
if ($priceRows === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -456,52 +489,16 @@ final class ListingCatalog
|
||||
VALUES (:listingId, :occurrenceId, :label, :audience, :priceType, :amount, :amountSecondary, "EUR", :note, NOW(), NOW())'
|
||||
);
|
||||
|
||||
if ($priceMode === 'free_child_rule') {
|
||||
$freeUntil = trim((string)($data['free_child_until_age'] ?? ''));
|
||||
foreach ($priceRows as $row) {
|
||||
$insertPrice->execute([
|
||||
'listingId' => $listingId,
|
||||
'occurrenceId' => $occurrenceId,
|
||||
'label' => 'Eintritt frei',
|
||||
'audience' => 'child',
|
||||
'priceType' => 'free',
|
||||
'amount' => null,
|
||||
'amountSecondary' => null,
|
||||
'note' => $freeUntil !== '' ? 'Kinder bis ' . $freeUntil . ' Jahre frei' : 'Kinder frei',
|
||||
]);
|
||||
}
|
||||
|
||||
$childAmount = trim((string)($data['price_child_amount'] ?? ''));
|
||||
if ($childAmount !== '') {
|
||||
$childFrom = trim((string)($data['price_child_age_from'] ?? ''));
|
||||
$childTo = trim((string)($data['price_child_age_to'] ?? ''));
|
||||
$note = 'Preis pro Kind';
|
||||
if ($childFrom !== '' || $childTo !== '') {
|
||||
$note .= ' (' . trim(($childFrom !== '' ? 'ab ' . $childFrom : '') . ($childTo !== '' ? ' bis ' . $childTo : '') . ' Jahre') . ')';
|
||||
}
|
||||
$insertPrice->execute([
|
||||
'listingId' => $listingId,
|
||||
'occurrenceId' => $occurrenceId,
|
||||
'label' => 'Kinder',
|
||||
'audience' => 'child',
|
||||
'priceType' => 'fixed',
|
||||
'amount' => (float)str_replace(',', '.', $childAmount),
|
||||
'amountSecondary' => null,
|
||||
'note' => $note,
|
||||
]);
|
||||
}
|
||||
|
||||
$adultAmount = trim((string)($data['price_adult_amount'] ?? ''));
|
||||
if ($adultAmount !== '') {
|
||||
$adultFrom = trim((string)($data['price_adult_age_from'] ?? ''));
|
||||
$insertPrice->execute([
|
||||
'listingId' => $listingId,
|
||||
'occurrenceId' => $occurrenceId,
|
||||
'label' => 'Erwachsene',
|
||||
'audience' => 'adult',
|
||||
'priceType' => 'fixed',
|
||||
'amount' => (float)str_replace(',', '.', $adultAmount),
|
||||
'amountSecondary' => null,
|
||||
'note' => $adultFrom !== '' ? 'Preis pro Erwachsener ab ' . $adultFrom . ' Jahre' : 'Preis pro Erwachsener',
|
||||
'label' => $row['label'],
|
||||
'audience' => $row['audience'],
|
||||
'priceType' => $row['price_type'],
|
||||
'amount' => $row['amount'],
|
||||
'amountSecondary' => $row['amount_secondary'],
|
||||
'note' => $row['note'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -539,6 +536,126 @@ final class ListingCatalog
|
||||
return ['single', null];
|
||||
}
|
||||
|
||||
private function resolveCategory(string $slug, string $customTitle): array
|
||||
{
|
||||
$slug = trim($slug);
|
||||
$customTitle = trim($customTitle);
|
||||
if ($customTitle !== '') {
|
||||
$slug = $this->slugify($customTitle);
|
||||
$stmt = $this->pdo->prepare(
|
||||
'INSERT INTO listing_categories (slug, title, category_group, sort_order)
|
||||
VALUES (:slug, :title, "general", 999)
|
||||
ON DUPLICATE KEY UPDATE title = VALUES(title), updated_at = CURRENT_TIMESTAMP'
|
||||
);
|
||||
$stmt->execute([
|
||||
'slug' => $slug,
|
||||
'title' => $customTitle,
|
||||
]);
|
||||
}
|
||||
if ($slug === '') {
|
||||
return ['', null];
|
||||
}
|
||||
$stmt = $this->pdo->prepare('SELECT id FROM listing_categories WHERE slug = :slug LIMIT 1');
|
||||
$stmt->execute(['slug' => $slug]);
|
||||
$categoryId = $stmt->fetchColumn();
|
||||
return [$slug, $categoryId !== false ? (int)$categoryId : null];
|
||||
}
|
||||
|
||||
private function normalizeOpeningHoursRows(array $data): array
|
||||
{
|
||||
$labels = (array)($data['opening_day_label'] ?? []);
|
||||
$fromValues = (array)($data['opening_time_from'] ?? []);
|
||||
$toValues = (array)($data['opening_time_to'] ?? []);
|
||||
$notes = (array)($data['opening_note'] ?? []);
|
||||
$count = max(count($labels), count($fromValues), count($toValues), count($notes));
|
||||
$rows = [];
|
||||
for ($index = 0; $index < $count; $index++) {
|
||||
$row = [
|
||||
'day_label' => trim((string)($labels[$index] ?? '')),
|
||||
'time_from' => trim((string)($fromValues[$index] ?? '')),
|
||||
'time_to' => trim((string)($toValues[$index] ?? '')),
|
||||
'note' => trim((string)($notes[$index] ?? '')),
|
||||
];
|
||||
if ($row['day_label'] === '' && $row['time_from'] === '' && $row['time_to'] === '' && $row['note'] === '') {
|
||||
continue;
|
||||
}
|
||||
$rows[] = $row;
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
private function normalizePriceRows(array $data): array
|
||||
{
|
||||
$labels = (array)($data['price_label'] ?? []);
|
||||
$audiences = (array)($data['price_audience'] ?? []);
|
||||
$types = (array)($data['price_type'] ?? []);
|
||||
$amounts = (array)($data['price_amount'] ?? []);
|
||||
$secondaryAmounts = (array)($data['price_amount_secondary'] ?? []);
|
||||
$ageFroms = (array)($data['price_age_from'] ?? []);
|
||||
$ageTos = (array)($data['price_age_to'] ?? []);
|
||||
$notes = (array)($data['price_note'] ?? []);
|
||||
$count = max(count($labels), count($audiences), count($types), count($amounts), count($secondaryAmounts), count($ageFroms), count($ageTos), count($notes));
|
||||
$rows = [];
|
||||
for ($index = 0; $index < $count; $index++) {
|
||||
$label = trim((string)($labels[$index] ?? ''));
|
||||
$audience = trim((string)($audiences[$index] ?? 'general'));
|
||||
$priceType = trim((string)($types[$index] ?? 'fixed'));
|
||||
$amount = trim((string)($amounts[$index] ?? ''));
|
||||
$secondary = trim((string)($secondaryAmounts[$index] ?? ''));
|
||||
$ageFrom = trim((string)($ageFroms[$index] ?? ''));
|
||||
$ageTo = trim((string)($ageTos[$index] ?? ''));
|
||||
$note = trim((string)($notes[$index] ?? ''));
|
||||
if ($label === '' && $amount === '' && $secondary === '' && $note === '' && $ageFrom === '' && $ageTo === '') {
|
||||
continue;
|
||||
}
|
||||
$noteParts = [];
|
||||
if ($note !== '') {
|
||||
$noteParts[] = $note;
|
||||
}
|
||||
if ($ageFrom !== '' || $ageTo !== '') {
|
||||
$ageText = [];
|
||||
if ($ageFrom !== '') {
|
||||
$ageText[] = 'ab ' . $ageFrom . ' Jahre';
|
||||
}
|
||||
if ($ageTo !== '') {
|
||||
$ageText[] = 'bis ' . $ageTo . ' Jahre';
|
||||
}
|
||||
$noteParts[] = implode(', ', $ageText);
|
||||
}
|
||||
$rows[] = [
|
||||
'label' => $label !== '' ? $label : 'Preis',
|
||||
'audience' => in_array($audience, ['general', 'adult', 'child', 'family', 'group'], true) ? $audience : 'general',
|
||||
'price_type' => in_array($priceType, ['free', 'fixed', 'from', 'up_to', 'range', 'request'], true) ? $priceType : 'fixed',
|
||||
'amount' => $amount !== '' ? (float)str_replace(',', '.', $amount) : null,
|
||||
'amount_secondary' => $secondary !== '' ? (float)str_replace(',', '.', $secondary) : null,
|
||||
'note' => $noteParts !== [] ? implode(' | ', $noteParts) : null,
|
||||
];
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
private function hasPriceRows(array $data): bool
|
||||
{
|
||||
return $this->normalizePriceRows($data) !== [];
|
||||
}
|
||||
|
||||
private function decodeJsonRows(string $json): array
|
||||
{
|
||||
if ($json === '') {
|
||||
return [];
|
||||
}
|
||||
$decoded = json_decode($json, true);
|
||||
return is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
|
||||
private function slugify(string $value): string
|
||||
{
|
||||
$value = mb_strtolower(trim($value));
|
||||
$value = strtr($value, ['ä' => 'ae', 'ö' => 'oe', 'ü' => 'ue', 'ß' => 'ss']);
|
||||
$value = preg_replace('/[^a-z0-9]+/u', '-', $value) ?: '';
|
||||
return trim($value, '-');
|
||||
}
|
||||
|
||||
public function deleteDashboardEntry(int $userId, int $listingId): void
|
||||
{
|
||||
$this->ensureSchema();
|
||||
|
||||
Reference in New Issue
Block a user