From 95cb79cf0ca6530bbfa4f0fd916ea4f24b8f679e Mon Sep 17 00:00:00 2001 From: Linus Maximilian Nilson Date: Fri, 30 Jan 2026 14:32:00 +0000 Subject: [PATCH] Upload files to "includes" --- includes/admin-workshops.php | 721 +++++++++++++++++++++++++++++++++ includes/frontend-ergebnis.php | 238 +++++++++++ includes/frontend-form.php | 356 ++++++++++++++++ includes/zuteilungslogik.php | 421 +++++++++++++++++++ 4 files changed, 1736 insertions(+) create mode 100644 includes/admin-workshops.php create mode 100644 includes/frontend-ergebnis.php create mode 100644 includes/frontend-form.php create mode 100644 includes/zuteilungslogik.php diff --git a/includes/admin-workshops.php b/includes/admin-workshops.php new file mode 100644 index 0000000..80e7400 --- /dev/null +++ b/includes/admin-workshops.php @@ -0,0 +1,721 @@ +prefix; + kc_admin_tabs('kc_workshops'); + + // Liste aller Teamer für Multi-Select (sortiert wie in Teamer-Übersicht: Vorname A-Z) + $teamer_liste = $wpdb->get_results("SELECT * FROM {$prefix}kc_teamer ORDER BY vorname ASC"); + + // Liste aller Wahlen für Auswahl + $wahlen_liste = $wpdb->get_results("SELECT * FROM {$prefix}kc_wahlen ORDER BY id DESC"); + + // Liste aller Phasen für Auswahl + $phasen_liste = $wpdb->get_results("SELECT * FROM {$prefix}kc_phasen ORDER BY nummer"); + + // Workshop löschen + if (isset($_GET['delete_workshop'])) { + $wid = intval($_GET['delete_workshop']); + $wpdb->delete("{$prefix}kc_workshops", ['id' => $wid]); + echo '
Workshop gelöscht!
'; + } + + // Workshop speichern (neu/ändern) + if (isset($_POST['kc_workshop_save'])) { + $wid = !empty($_POST['wid']) ? intval($_POST['wid']) : null; + + // Nur Workshop-Daten speichern, wenn Name übergeben wurde (nicht bei reiner Teamer-Bearbeitung) + if (!empty($_POST['name'])) { + // Ensure DB has min_teilnehmer column + $col = $wpdb->get_results($wpdb->prepare("SHOW COLUMNS FROM {$prefix}kc_workshops LIKE %s", 'min_teilnehmer')); + if (empty($col)) { + $wpdb->query("ALTER TABLE {$prefix}kc_workshops ADD COLUMN min_teilnehmer INT DEFAULT 0"); + } + + $data = [ + 'name' => sanitize_text_field($_POST['name']), + 'beschreibung' => sanitize_text_field($_POST['beschreibung']), + 'max_teilnehmer' => intval($_POST['max_teilnehmer']), + 'min_teilnehmer' => intval($_POST['min_teilnehmer'] ?? 0) + ]; + if ($wid) { + $wpdb->update("{$prefix}kc_workshops", $data, ['id'=> $wid]); + echo '
Workshop aktualisiert!
'; + } else { + $wpdb->insert("{$prefix}kc_workshops", $data); + $wid = intval($wpdb->insert_id); + echo '
Workshop angelegt!
'; + } + } + + // Teamer-Zuordnungen speichern mit Wahl/Phase (auch für neue Workshops) + if (!empty($wid)) { + // Stelle sicher, dass wahl_id und phase Spalten existieren + $columns = $wpdb->get_col("SHOW COLUMNS FROM {$prefix}kc_workshop_teamer"); + if (!in_array('wahl_id', $columns)) { + $wpdb->query("ALTER TABLE {$prefix}kc_workshop_teamer ADD COLUMN wahl_id INT(11) NULL DEFAULT NULL"); + } + if (!in_array('phase', $columns)) { + $wpdb->query("ALTER TABLE {$prefix}kc_workshop_teamer ADD COLUMN phase INT(11) NULL DEFAULT NULL"); + } + + $is_feste = !empty($_POST['edit_feste']); + $wahl_id = !empty($_POST['select_wahl_id']) ? intval($_POST['select_wahl_id']) : null; + $phase = !empty($_POST['select_phase']) ? intval($_POST['select_phase']) : null; + + // Lösche alte Zuordnungen (nur wenn Teamer vorhanden sind, für neue Workshops) + if (!empty($_POST['teamer_ids'])) { + if ($is_feste) { + $wpdb->query($wpdb->prepare( + "DELETE FROM {$prefix}kc_workshop_teamer WHERE workshop_id=%d AND wahl_id IS NULL AND phase IS NULL", + $wid + )); + } elseif ($wahl_id !== null) { + if ($phase !== null) { + $wpdb->delete("{$prefix}kc_workshop_teamer", [ + 'workshop_id' => $wid, + 'wahl_id' => $wahl_id, + 'phase' => $phase + ]); + } else { + $wpdb->query($wpdb->prepare( + "DELETE FROM {$prefix}kc_workshop_teamer WHERE workshop_id=%d AND wahl_id=%d AND phase IS NULL", + $wid, $wahl_id + )); + } + } + } + + // Neue Zuordnungen einfügen + if (!empty($_POST['teamer_ids']) && is_array($_POST['teamer_ids'])) { + foreach ($_POST['teamer_ids'] as $tid) { + $tid = intval($tid); + if ($tid > 0) { + if ($is_feste) { + $wpdb->insert("{$prefix}kc_workshop_teamer", [ + 'workshop_id' => $wid, + 'teamer_id' => $tid, + 'wahl_id' => null, + 'phase' => null + ]); + } else { + $wpdb->insert("{$prefix}kc_workshop_teamer", [ + 'workshop_id' => $wid, + 'teamer_id' => $tid, + 'wahl_id' => $wahl_id, + 'phase' => $phase + ]); + } + } + } + } + + // Redirect nach Speichern von festen Teamern zur Gesamtübersicht + if ($is_feste && empty($_POST['name'])) { + echo '
Feste Teamer gespeichert!
'; + echo ""; + return; + } + + // Redirect nach Speichern von wahl-spezifischen Teamern zurück zur Workshop-Bearbeitung + if ($wahl_id !== null && empty($_POST['name'])) { + echo '
Teamer-Zuordnung gespeichert!
'; + echo ""; + return; + } + } + } + + // Workshop bearbeiten + if (isset($_GET['edit_workshop'])) { + $wid = intval($_GET['edit_workshop']); + $ws = $wpdb->get_row("SELECT * FROM {$prefix}kc_workshops WHERE id=$wid"); + if (!$ws) { + echo '
'; + echo '
Workshop nicht gefunden.
'; + echo 'Zur\u00fcck zur \u00dcbersicht'; + echo '
'; + return; + } + + echo '
'; + echo '

Workshop bearbeiten: '.esc_html($ws->name).'

'; + + // Hole Spalten-Info + $columns = $wpdb->get_col("SHOW COLUMNS FROM {$prefix}kc_workshop_teamer"); + $has_wahl = in_array('wahl_id', $columns); + $has_phase = in_array('phase', $columns); + + // Zeige Feste Teamer (gelten für alle Wahlen) + if ($has_wahl && $has_phase) { + $feste_teamer = $wpdb->get_results($wpdb->prepare( + "SELECT t.vorname, t.nachname FROM {$prefix}kc_workshop_teamer wt + JOIN {$prefix}kc_teamer t ON wt.teamer_id=t.id + WHERE wt.workshop_id=%d AND wt.wahl_id IS NULL AND wt.phase IS NULL + ORDER BY t.vorname", + $wid + )); + + if (!empty($feste_teamer)) { + $teamer_names = array_map(function($t) { return $t->vorname.' '.$t->nachname; }, $feste_teamer); + $teamer_str = implode(', ', array_map('esc_html', $teamer_names)); + echo '
+ Feste Teamer (für alle Wahlen): '.$teamer_str.' + Bearbeiten +
'; + } + } + + // Zeige Wahl/Phase-Kombinationen mit ihren Teamern + echo '

Teamer pro Wahl:

'; + echo '
'; + if ($has_wahl && $has_phase) { + echo '+ Feste Teamer festlegen'; + } + echo '
'; + echo ''; + echo ''; + + // Hole alle Wahlen, die diesem Workshop zugeordnet sind + $wahlen_for_workshop = $wpdb->get_results($wpdb->prepare( + "SELECT DISTINCT ww.wahl_id, w.name, w.anzahl_einheiten + FROM {$prefix}kc_wahl_workshops ww + JOIN {$prefix}kc_wahlen w ON ww.wahl_id=w.id + WHERE ww.workshop_id=%d + ORDER BY w.id", + $wid + )); + + if (empty($wahlen_for_workshop)) { + echo ''; + } else { + foreach($wahlen_for_workshop as $w) { + // Sammle Teamer für diese Wahl + if ($has_wahl && $has_phase) { + // Prüfe ob es wahl-spezifische Teamer gibt + $wahl_teamer = $wpdb->get_results($wpdb->prepare( + "SELECT DISTINCT t.vorname, t.nachname FROM {$prefix}kc_workshop_teamer wt + JOIN {$prefix}kc_teamer t ON wt.teamer_id=t.id + WHERE wt.workshop_id=%d AND wt.wahl_id=%d + ORDER BY t.vorname", + $wid, $w->wahl_id + )); + + // Wenn keine wahl-spezifischen Teamer, nutze die Festen Teamer + if (empty($wahl_teamer) && !empty($feste_teamer)) { + $teamer = $feste_teamer; + } else { + $teamer = $wahl_teamer; + } + } else { + $teamer = []; + } + + $teamer_names = array_map(function($t) { return $t->vorname.' '.$t->nachname; }, $teamer); + $teamer_str = !empty($teamer_names) ? implode(', ', array_map('esc_html', $teamer_names)) : 'Keine'; + + echo ' + + + + '; + } + } + + echo '
WahlTeamerAktion
Dieser Workshop ist noch keiner Wahl zugeordnet.
'.esc_html($w->name).''.$teamer_str.'Bearbeiten
'; + + // Wenn Feste Teamer bearbeitet werden sollen + if (isset($_GET['edit_feste'])) { + echo '

Feste Teamer (gelten für alle Wahlen)

+
+ + + + +
'; + + // Feste Teamer auslesen + if ($has_wahl && $has_phase) { + $assigned = $wpdb->get_col($wpdb->prepare( + "SELECT teamer_id FROM {$prefix}kc_workshop_teamer WHERE workshop_id=%d AND wahl_id IS NULL AND phase IS NULL", + $wid + )); + } else { + $assigned = []; + } + + foreach($teamer_liste as $t) { + $checked = in_array($t->id, (array)$assigned) ? ' checked' : ''; + echo ''; + } + + echo '
+ + + Abbrechen +
'; + } + + // Wenn eine Wahl ausgewählt wurde, zeige Phase-Auswahl oder direkt Teamer-Bearbeitung + elseif (isset($_GET['select_wahl']) && !isset($_GET['edit_wahl'])) { + $select_wahl_id = intval($_GET['select_wahl']); + $wahl_info = $wpdb->get_row($wpdb->prepare("SELECT name, anzahl_einheiten FROM {$prefix}kc_wahlen WHERE id=%d", $select_wahl_id)); + if (!$wahl_info) { + echo '
Wahl nicht gefunden.
'; + echo 'Abbrechen'; + return; + } + + if (intval($wahl_info->anzahl_einheiten) > 1) { + // Mehrere Phasen: Frage stellen unter Berücksichtigung der tatsächlichen Zuordnung + // Ermittle, welchen Phasen dieser Workshop in dieser Wahl zugeordnet ist + $assigned_phases = $wpdb->get_col($wpdb->prepare( + "SELECT DISTINCT phase FROM {$prefix}kc_wahl_workshops WHERE workshop_id=%d AND wahl_id=%d AND phase IS NOT NULL", + $wid, $select_wahl_id + )); + $assigned_phases = array_map('intval', (array)$assigned_phases); + sort($assigned_phases); + + echo '
'; + echo '

Teamer für: '.esc_html($wahl_info->name).'

'; + echo '

Sollen die Teamer für eine bestimmte Phase gelten?'; + echo ' (Dieser Workshop ist zugeordnet: '.(!empty($assigned_phases) ? 'Phase '.esc_html(implode(', ', $assigned_phases)) : 'keiner Phase').')

'; + echo '
'; + + // "Für alle Phasen" nur anbieten, wenn wirklich allen Phasen dieser Wahl zugeordnet + if (!empty($assigned_phases) && count($assigned_phases) === intval($wahl_info->anzahl_einheiten)) { + echo 'Für alle Phasen'; + } + + // Buttons nur für tatsächlich zugeordnete Phasen + foreach ($assigned_phases as $p) { + echo 'Phase '.$p.''; + } + + if (empty($assigned_phases)) { + echo 'Dieser Workshop ist in dieser Wahl aktuell keiner Phase zugeordnet.'; + } + + echo '
'; + echo 'Abbrechen'; + echo '
'; + } else { + // Nur eine Phase: direkt weiterleiten + echo ""; + return; + } + } + + // Wenn eine Wahl ausgewählt wurde (mit oder ohne Phase), zeige Bearbeitung + elseif (isset($_GET['edit_wahl'])) { + $edit_wahl_id = intval($_GET['edit_wahl']); + $edit_phase = isset($_GET['edit_phase']) ? intval($_GET['edit_phase']) : null; + $edit_wahl = $wpdb->get_row($wpdb->prepare("SELECT name FROM {$prefix}kc_wahlen WHERE id=%d", $edit_wahl_id)); + if (!$edit_wahl) { + echo '
Wahl nicht gefunden.
'; + echo 'Abbrechen'; + return; + } + + if ($edit_phase !== null) { + $title = 'Teamer für '.esc_html($edit_wahl->name).' Phase '.$edit_phase; + } else { + $title = 'Teamer für '.esc_html($edit_wahl->name).' (Alle Phasen)'; + } + + echo '

'.$title.'

+
+ + '; + + if ($edit_phase !== null) { + echo ''; + } + + echo ' + +
'; + + // Stelle sicher, dass Spalten existieren + $columns = $wpdb->get_col("SHOW COLUMNS FROM {$prefix}kc_workshop_teamer"); + $has_wahl = in_array('wahl_id', $columns); + $has_phase = in_array('phase', $columns); + + // Teamer für diese Wahl/Phase auslesen + if ($has_wahl && $has_phase) { + if ($edit_phase !== null) { + $assigned = $wpdb->get_col($wpdb->prepare( + "SELECT teamer_id FROM {$prefix}kc_workshop_teamer WHERE workshop_id=%d AND wahl_id=%d AND phase=%d", + $wid, $edit_wahl_id, $edit_phase + )); + } else { + $assigned = $wpdb->get_col($wpdb->prepare( + "SELECT teamer_id FROM {$prefix}kc_workshop_teamer WHERE workshop_id=%d AND wahl_id=%d AND phase IS NULL", + $wid, $edit_wahl_id + )); + } + } else { + $assigned = []; + } + + foreach($teamer_liste as $t) { + $checked = in_array($t->id, (array)$assigned) ? ' checked' : ''; + echo ''; + } + + echo '
+ + + Abbrechen +
'; + } else { + // Workshop-Details bearbeiten + echo '

Workshop-Details

+
+ + + +
+ + +
+ + Abbrechen +
'; + } + + echo '
'; + return; + } + + // Neuer Workshop anlegen + if (isset($_GET['new'])) { + echo '
'; + echo '

Neuen Workshop anlegen

'; + + echo '
'; + echo ''; + echo ''; + + echo '
'; + echo ''; + echo ''; + echo '
'; + + echo ''; + echo 'Abbrechen'; + echo '
'; + + echo '
'; + return; + } + + // Übersicht + echo '
'; + echo '

Alle Workshops

'; + echo '+ Neuer Workshop'; + echo '
' + .'' + .'' + .'Alle anzeigen' + .'
' + .'' + .'' + .'' + .'' + .'' + .'' + .'
' + .'
'; + echo '
' + .'' + .'' + .'Alle anzeigen' + .'
'; + + // Sortierung + $sort = isset($_GET['sort']) ? sanitize_text_field($_GET['sort']) : 'id'; + $order = isset($_GET['order']) ? (($_GET['order'] === 'desc') ? 'DESC' : 'ASC') : 'DESC'; + $allowed_sort = ['id', 'name', 'beschreibung']; + if (!in_array($sort, $allowed_sort)) { + $sort = 'id'; + } + + // Sortier-Links + $name_order = ($sort === 'name' && $order === 'ASC') ? 'desc' : 'asc'; + $beschreibung_order = ($sort === 'beschreibung' && $order === 'ASC') ? 'desc' : 'asc'; + $name_arrow = ($sort === 'name') ? ($order === 'ASC' ? ' ▲' : ' ▼') : ''; + $beschreibung_arrow = ($sort === 'beschreibung') ? ($order === 'ASC' ? ' ▲' : ' ▼') : ''; + + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + + $workshops = $wpdb->get_results("SELECT * FROM {$prefix}kc_workshops ORDER BY {$sort} {$order}"); + foreach ($workshops as $ws) { + // Teamer anzeigen + $trows = $wpdb->get_results($wpdb->prepare("SELECT t.vorname, t.nachname FROM {$prefix}kc_workshop_teamer wt JOIN {$prefix}kc_teamer t ON wt.teamer_id=t.id WHERE wt.workshop_id=%d", $ws->id)); + $tnames = array_map(function($r){ return $r->vorname.' '.$r->nachname; }, $trows); + $tnames_str = implode(', ', array_map('esc_html', $tnames)); + if (empty($tnames_str)) $tnames_str = 'Keine'; + + // Wahlen und Phasen anzeigen + $wahl_rows = $wpdb->get_results($wpdb->prepare( + "SELECT w.name, ww.phase + FROM {$prefix}kc_wahl_workshops ww + JOIN {$prefix}kc_wahlen w ON ww.wahl_id=w.id + WHERE ww.workshop_id=%d + ORDER BY w.id, ww.phase", + $ws->id + )); + $wahl_info = []; + foreach($wahl_rows as $wr) { + $wahl_info[] = esc_html($wr->name) . ($wr->phase ? ' (P'.intval($wr->phase).')' : ''); + } + $wahl_str = !empty($wahl_info) ? implode(', ', $wahl_info) : 'Keine'; + + echo " + + + + + + + "; + } + echo '
Name'.$name_arrow.'Beschreibung'.$beschreibung_arrow.'Teilnehmer (Min - Max)TeamerWahlenAktion
".esc_html($ws->name)."".esc_html($ws->beschreibung)."".(isset($ws->min_teilnehmer)?intval($ws->min_teilnehmer):0)." - ".intval($ws->max_teilnehmer)."". $tnames_str ."". $wahl_str ." + Bearbeiten + Loeschen +
'; + echo ''; + echo '
'; +} +?> \ No newline at end of file diff --git a/includes/frontend-ergebnis.php b/includes/frontend-ergebnis.php new file mode 100644 index 0000000..34b32e3 --- /dev/null +++ b/includes/frontend-ergebnis.php @@ -0,0 +1,238 @@ +null], $atts); + $wahl_id = intval($atts['wahl']); + + global $wpdb; + $wahl = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}kc_wahlen WHERE id=$wahl_id"); + if(!$wahl) return ''; + if($wahl->freigegeben) return '
'; + + // Workshops für diese Wahl holen + $workshops = $wpdb->get_results( + "SELECT ws.id, ws.name + FROM {$wpdb->prefix}kc_workshops ws + JOIN {$wpdb->prefix}kc_wahl_workshops ww ON ws.id = ww.workshop_id + WHERE ww.wahl_id = ".intval($wahl_id) + ); + $ws_names = []; + $ws_ids = []; + foreach($workshops as $ws) { + $ws_names[$ws->id] = $ws->name; + $ws_ids[] = intval($ws->id); + } + + // Zuteilungen holen + $rows = $wpdb->get_results( + "SELECT * FROM {$wpdb->prefix}kc_zuteilung WHERE wahl_id=".intval($wahl_id) + ); + + // Gruppieren nach Workshop, sortieren nach Teilnehmerzahl + $workshop_groups = []; + $nicht_zugeteilt = []; + $phases = []; + foreach($rows as $row) { + // Einträge ohne Phase komplett ignorieren + if ($row->phase === null || $row->phase === '') { + continue; + } + $phaseNum = intval($row->phase); + $phases[$phaseNum] = true; + if ($row->workshop_id && isset($ws_names[$row->workshop_id])) { + $workshop_groups[$row->workshop_id][] = $row; + } else { + $nicht_zugeteilt[] = $row; + } + } + uasort($workshop_groups, function($a, $b) { + return count($a) - count($b); + }); + + $phases = array_keys($phases); + sort($phases, SORT_NUMERIC); + + // Teamer pro Workshop und Phase laden (mit Hierarchie: Phase-spezifisch > Wahl-weit > Feste) + $ws_teamers = []; + if (!empty($ws_ids)) { + // Für JEDEN Workshop einzeln laden + foreach($ws_ids as $ws_id) { + foreach($phases as $phase) { + // 1. Versuche Phase-spezifische Teamer zu laden + $trows = $wpdb->get_results($wpdb->prepare( + "SELECT t.vorname, t.nachname FROM {$wpdb->prefix}kc_workshop_teamer wt + JOIN {$wpdb->prefix}kc_teamer t ON wt.teamer_id = t.id + WHERE wt.workshop_id = %d AND wt.wahl_id = %d AND wt.phase = %d", + $ws_id, $wahl_id, $phase + )); + + // 2. Falls nicht: Versuche Wahl-weite Teamer zu laden + if (empty($trows)) { + $trows = $wpdb->get_results($wpdb->prepare( + "SELECT t.vorname, t.nachname FROM {$wpdb->prefix}kc_workshop_teamer wt + JOIN {$wpdb->prefix}kc_teamer t ON wt.teamer_id = t.id + WHERE wt.workshop_id = %d AND wt.wahl_id = %d AND wt.phase IS NULL", + $ws_id, $wahl_id + )); + } + + // 3. Falls nicht: Lade Feste Teamer + if (empty($trows)) { + $trows = $wpdb->get_results($wpdb->prepare( + "SELECT t.vorname, t.nachname FROM {$wpdb->prefix}kc_workshop_teamer wt + JOIN {$wpdb->prefix}kc_teamer t ON wt.teamer_id = t.id + WHERE wt.workshop_id = %d AND wt.wahl_id IS NULL AND wt.phase IS NULL", + $ws_id + )); + } + + if (!empty($trows)) { + $key = intval($ws_id) . '_' . intval($phase); + $ws_teamers[$key] = []; + foreach ($trows as $tr) { + $ws_teamers[$key][] = trim($tr->vorname.' '.$tr->nachname); + } + } + } + } + } + + // Versuche, Teilnehmer-IDs aus Cookie zu lesen (falls vorhanden) + $my_ids = []; + $cookie_name = 'kc_my_part_' . intval($wahl_id); + if (!empty($_COOKIE[$cookie_name])) { + $decoded = json_decode(stripslashes($_COOKIE[$cookie_name]), true); + if (is_array($decoded)) $my_ids = array_map('intval', $decoded); + } + + ob_start(); + // Inline styles, angepasst an konfi-castle.com Look (dezent, grün/türkis Akzent) + echo ''; + + echo '
'; + echo '

Ergebnis für diese Wahl

'; + + // Falls persönliche IDs vorhanden: zeige persönliche Zuteilung oben + $personal_shown = false; + if (!empty($my_ids)) { + // Suche Zuteilungen für meine IDs + $my_rows = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}kc_zuteilung WHERE wahl_id=".intval($wahl_id)." AND id IN (" . implode(',', array_map('intval', $my_ids)) . ")"); + if (!empty($my_rows)) { + // Entferntes
nach "Deine Zuteilung" + echo '
'; + echo 'Deine Zuteilung
    '; + foreach($my_rows as $mr) { + $wslabel = ($mr->workshop_id && isset($ws_names[$mr->workshop_id])) ? $ws_names[$mr->workshop_id] : ($mr->workshop_id ? 'ID '.$mr->workshop_id : 'Nicht zugeteilt'); + echo '
  • '.esc_html($mr->vorname.' '.$mr->nachname).' (Phase '.intval($mr->phase).') — '.esc_html($wslabel).'
  • '; + } + echo '
'; + $personal_shown = true; + } + } + + // Für jede Phase: Workshops nebeneinander darstellen + foreach($phases as $phase) { + echo '
'; + echo '

Phase '.intval($phase).'

'; + echo '
'; + // Sammle nur Workshops mit Teilnehmern in dieser Phase + $display = []; + foreach($ws_names as $ws_id => $ws_name) { + $teilnehmer = []; + if (isset($workshop_groups[$ws_id])) { + foreach($workshop_groups[$ws_id] as $t) { + if (intval($t->phase) === intval($phase)) $teilnehmer[] = $t; + } + } + $count = count($teilnehmer); + if ($count === 0) continue; // nur Workshops mit TN anzeigen + $display[] = [ + 'id' => $ws_id, + 'name' => $ws_name, + 'teilnehmer' => $teilnehmer, + 'count' => $count + ]; + } + + // Nach Teilnehmerzahl aufsteigend sortieren (kleinste oben, größte unten) + usort($display, function($a, $b) { + return $a['count'] - $b['count']; + }); + + // Ausgabe der sortierten Kacheln + foreach($display as $d) { + $ws_name = $d['name']; + $teilnehmer = $d['teilnehmer']; + $count = $d['count']; + + // Sortiere so, dass persönliche Teilnehmer zuerst kommen + if (!empty($my_ids) && !empty($teilnehmer)) { + usort($teilnehmer, function($a, $b) use ($my_ids) { + $a_my = in_array(intval($a->id), $my_ids); + $b_my = in_array(intval($b->id), $my_ids); + if ($a_my && !$b_my) return -1; + if (!$a_my && $b_my) return 1; + return 0; + }); + } + + echo '
'; + // Teamernamen (falls vorhanden) anzeigen - mit Phase-Key + $teamer_html = ''; + $teamer_key = intval($d['id']) . '_' . intval($phase); + if (!empty($ws_teamers[$teamer_key])) { + $teamer_html = ''.esc_html(implode(', ', $ws_teamers[$teamer_key])).''; + } + echo '
'.esc_html($ws_name).' '. $teamer_html .'('.$count.' TN)
'; + echo '
'; + echo '
'; + foreach($teilnehmer as $t) { + $is_me = in_array(intval($t->id), $my_ids); + $name = esc_html($t->vorname.' '.$t->nachname); + $label = $name . ' ('.intval($t->phase).')'; + echo '
'. $label .'
'; + } + echo '
'; // kc-participants + echo '
'; // content + echo '
'; + } + + echo '
'; // kc-workshops-grid + echo '
'; // kc-phase + } + + // Extra: Nicht zugeteilt + if (!empty($nicht_zugeteilt)) { + echo '
'; + echo 'Nicht zugeteilt:
'; + echo '
    '; + foreach($nicht_zugeteilt as $t) { + echo '
  • '.esc_html($t->vorname.' '.$t->nachname).' (Phase '.intval($t->phase).')
  • '; + } + echo '
'; + } + + echo '
'; // kc-result + return ob_get_clean(); +}); +?> \ No newline at end of file diff --git a/includes/frontend-form.php b/includes/frontend-form.php new file mode 100644 index 0000000..a83effd --- /dev/null +++ b/includes/frontend-form.php @@ -0,0 +1,356 @@ +null], $atts); + $wahl_id = intval($atts['wahl']); + + global $wpdb; + + // KRITISCHER TEST: Ausgabe ganz am Anfang + //$debug_output = '
'; + //$debug_output .= '

DEBUG INFO

'; + //$debug_output .= 'Shortcode läuft!
'; + //$debug_output .= 'REQUEST_METHOD: ' . ($_SERVER['REQUEST_METHOD'] ?? 'NICHT GESETZT') . '
'; + //$debug_output .= 'POST vorhanden: ' . (empty($_POST) ? 'NEIN' : 'JA') . '
'; + //$debug_output .= 'POST Inhalt:
' . print_r($_POST, true) . '
'; + //$debug_output .= '
'; + + $wahl = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}kc_wahlen WHERE id=%d", $wahl_id)); + if(!$wahl || !$wahl->freigegeben) { + return $debug_output . '
Die Workshopwahl ist aktuell nicht freigeschaltet.
'; + } + + // Ermittle erlaubte Workshops pro Phase für diese Wahl. + $phasen = (int)$wahl->anzahl_einheiten; + $workshops_by_phase = []; + $mapping_candidates = [ + "{$wpdb->prefix}kc_wahl_workshops", + "{$wpdb->prefix}kc_workshop_wahlen", + "{$wpdb->prefix}kc_wahl_workshop" + ]; + $mapping_table = null; + foreach ($mapping_candidates as $t) { + $found = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $t)); + if ($found === $t) { $mapping_table = $t; break; } + } + if ($mapping_table) { + $has_phase_col = (bool) $wpdb->get_var("SHOW COLUMNS FROM {$mapping_table} LIKE 'phase'"); + for ($phase = 1; $phase <= $phasen; $phase++) { + if ($has_phase_col) { + $workshops_by_phase[$phase] = $wpdb->get_results($wpdb->prepare( + "SELECT w.* FROM {$wpdb->prefix}kc_workshops w + JOIN {$mapping_table} m ON w.id = m.workshop_id + WHERE m.wahl_id = %d AND m.phase = %d + ORDER BY w.name", + $wahl_id, $phase + )); + } else { + $workshops_by_phase[$phase] = $wpdb->get_results($wpdb->prepare( + "SELECT w.* FROM {$wpdb->prefix}kc_workshops w + JOIN {$mapping_table} m ON w.id = m.workshop_id + WHERE m.wahl_id = %d + ORDER BY w.name", + $wahl_id + )); + } + } + } else { + $all = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}kc_workshops ORDER BY name"); + for ($phase = 1; $phase <= $phasen; $phase++) $workshops_by_phase[$phase] = $all; + } + + // POST Verarbeitung + $error_message = null; + $success_redirect = false; + + if($_SERVER['REQUEST_METHOD']=='POST' && isset($_POST['kc_workshop_submit'])) { + //$debug_output .= '
POST WIRD VERARBEITET!
'; + + if(empty($_POST['vorname']) || empty($_POST['nachname'])) { + $error_message = 'Bitte Vor- und Nachname ausfüllen.'; + } else { + $inserted_ids = []; + $vorname = sanitize_text_field($_POST['vorname']); + $nachname = sanitize_text_field($_POST['nachname']); + $norm_v = mb_strtolower(trim($vorname)); + $norm_n = mb_strtolower(trim($nachname)); + + // Duplikatsprüfung + $exists = $wpdb->get_var($wpdb->prepare( + "SELECT COUNT(*) FROM {$wpdb->prefix}kc_teilnehmer WHERE LOWER(TRIM(vorname))=%s AND LOWER(TRIM(nachname))=%s AND wahl_id=%d", + $norm_v, $norm_n, $wahl_id + )); + + if ($exists && $exists > 0) { + $error_message = 'Diese Kombination aus Vorname und Nachname existiert bereits für diese Wahl.'; + } else { + // Validierung und Insert + $validation_passed = true; + + for ($phase = 1; $phase <= $phasen; $phase++) { + $allowed = array_map('intval', wp_list_pluck($workshops_by_phase[$phase] ?? [], 'id')); + $w1 = intval($_POST["phase{$phase}_wunsch1"] ?? 0); + $w2 = intval($_POST["phase{$phase}_wunsch2"] ?? 0); + $w3 = intval($_POST["phase{$phase}_wunsch3"] ?? 0); + + if (empty($allowed) || !in_array($w1, $allowed, true) || !in_array($w2, $allowed, true) || !in_array($w3, $allowed, true)) { + $error_message = "Ungültige Workshop-Auswahl für Phase {$phase}."; + $validation_passed = false; + break; + } + // Ensure the three wishes in this phase are not duplicates + $selected = [$w1, $w2, $w3]; + if (count(array_unique($selected)) !== count($selected)) { + $error_message = "Bitte wähle in Phase {$phase} drei verschiedene Workshops (keine Duplikate)."; + $validation_passed = false; + break; + } + } + + if ($validation_passed) { + for ($phase = 1; $phase <= $phasen; $phase++) { + $w1 = intval($_POST["phase{$phase}_wunsch1"]); + $w2 = intval($_POST["phase{$phase}_wunsch2"]); + $w3 = intval($_POST["phase{$phase}_wunsch3"]); + + $result = $wpdb->insert("{$wpdb->prefix}kc_teilnehmer", [ + 'vorname' => $vorname, + 'nachname' => $nachname, + 'wahl_id' => $wahl_id, + 'phase' => $phase, + 'wunsch1' => $w1, + 'wunsch2' => $w2, + 'wunsch3' => $w3, + 'deleted' => 0 + ]); + + if ($result === false) { + $error_message = 'Datenbankfehler: ' . $wpdb->last_error; + break; + } else { + $inserted_ids[] = intval($wpdb->insert_id); + } + } + + if (empty($error_message)) { + // Cookie setzen + $cookie_name = 'kc_my_part_' . intval($wahl_id); + $existing = []; + if (!empty($_COOKIE[$cookie_name])) { + $dec = json_decode(stripslashes($_COOKIE[$cookie_name]), true); + if (is_array($dec)) $existing = array_map('intval', $dec); + } + $all_ids = array_values(array_unique(array_merge($existing, $inserted_ids))); + @setcookie($cookie_name, wp_json_encode($all_ids), time() + 30*24*3600, '/'); + + // Erfolg + $success_redirect = true; + } + } + } + } + } + + ob_start(); +?> + + + + +
+

name) ?>

+ beschreibung): ?> +
beschreibung)) ?>
+ + + +
+ + + +
+ Danke! Deine Wünsche wurden gespeichert.
+ Erfolgreich eingefügte IDs: +
+ +
+ +
+ + +
+
+ + +
+ +
+ 1): ?>Phase +
+ +
+ + +
+ + + +
+ +
+
+ +
+prefix; + $msg = ''; + + if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['kc_teamer_create_nonce'])) { + if (empty($_POST['kc_teamer_create_nonce']) || !wp_verify_nonce($_POST['kc_teamer_create_nonce'], 'kc_teamer_create_action')) { + $msg = '
Ungültiger Request.
'; + } else { + $pw = trim($_POST['kc_teamer_pw'] ?? ''); + $saved_hash = get_option('kc_teamer_password_hash', ''); + if (empty($saved_hash) || !wp_check_password($pw, $saved_hash)) { + $msg = '
Falsches Passwort.
'; + } else { + $vorname = sanitize_text_field($_POST['vorname'] ?? ''); + $nachname = sanitize_text_field($_POST['nachname'] ?? ''); + $ws_name = sanitize_text_field($_POST['workshop_name'] ?? ''); + if ($vorname === '' || $nachname === '' || $ws_name === '') { + $msg = '
Bitte alle Felder ausfüllen.
'; + } else { + $existing = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$prefix}kc_teamer WHERE vorname=%s AND nachname=%s", $vorname, $nachname)); + if ($existing) { + $tid = intval($existing->id); + } else { + $wpdb->insert("{$prefix}kc_teamer", ['vorname'=>$vorname,'nachname'=>$nachname]); + $tid = intval($wpdb->insert_id); + } + $min_t = max(0, intval($_POST['min_teilnehmer'] ?? 0)); + $max_t = max(1, intval($_POST['max_teilnehmer'] ?? 10)); + if ($min_t > $max_t) { + $msg = '
Die minimale Teilnehmerzahl darf nicht größer als die maximale sein.
'; + } else { + $col = $wpdb->get_var("SHOW COLUMNS FROM {$prefix}kc_workshops LIKE 'min_teilnehmer'"); + if (empty($col)) { + $wpdb->query("ALTER TABLE {$prefix}kc_workshops ADD COLUMN min_teilnehmer INT NOT NULL DEFAULT 0"); + } + $wpdb->insert("{$prefix}kc_workshops", ['name'=>$ws_name, 'beschreibung'=>'', 'max_teilnehmer'=>$max_t, 'min_teilnehmer'=>$min_t]); + $wid = intval($wpdb->insert_id); + + if ($wid) { + $wpdb->insert("{$prefix}kc_workshop_teamer", ['workshop_id'=>$wid, 'teamer_id'=>$tid]); + $msg = '
Workshop angelegt und Teamer zugeordnet.
'; + } else { + $msg = '
Fehler beim Anlegen des Workshops.
'; + } + } + } + } + } + } + + ob_start(); + $nonce = wp_create_nonce('kc_teamer_create_action'); + ?> +
+

Teamer: Workshop erstellen

+ +
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+
+
+ +
+
+
+ prefix; + + $wahl_id = intval($wahl_id); + error_log('kc_run_zuteilung: Start für Wahl '.$wahl_id); + + // 0. Entferne alte Zuteilungen für diese Wahl + $wpdb->delete("{$prefix}kc_zuteilung", ['wahl_id' => $wahl_id]); + + // 1. Teilnehmer einlesen (alle Phasen werden getrennt verarbeitet) + $phasen = intval($wpdb->get_var($wpdb->prepare("SELECT anzahl_einheiten FROM {$prefix}kc_wahlen WHERE id=%d", $wahl_id))); + if($phasen < 1) $phasen = 1; + + // 2. Workshops einlesen (inkl. Kapazität) + $workshops_rows = $wpdb->get_results($wpdb->prepare( + "SELECT ws.id, ws.name, ws.max_teilnehmer FROM {$prefix}kc_workshops ws JOIN {$prefix}kc_wahl_workshops ww ON ws.id = ww.workshop_id WHERE ww.wahl_id=%d", + $wahl_id + )); + $workshops = []; + $workshop_caps = []; + foreach($workshops_rows as $w) { + $workshops[$w->id] = $w; + $workshop_caps[$w->id] = intval($w->max_teilnehmer); + } + + // 3. Force-Zuteilungen lesen (global, nach Phase filtern) + $forces_all = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$prefix}kc_force_zuteilung WHERE wahl_id=%d", $wahl_id)); + + // Prozessiere jede Phase einzeln + for($phase=1; $phase<=$phasen; $phase++) { + error_log("kc_run_zuteilung: Verarbeite Phase $phase"); + + // 1) Teilnehmer einlesen (alle TN dieser Wahl+Phase) + $teilnehmer = $wpdb->get_results($wpdb->prepare( + "SELECT * FROM {$prefix}kc_teilnehmer WHERE wahl_id=%d AND phase=%d", + $wahl_id, $phase + )); + + // Prepare helper maps + $teilnehmer_by_id = []; + foreach($teilnehmer as $t) $teilnehmer_by_id[$t->id] = $t; + // keep a full copy for later reassignments if needed + $all_teilnehmer_by_id = $teilnehmer_by_id; + + // 2) Kopie der Kapazitäten für diese Phase (werden während Zuordnung reduziert) + $caps = $workshop_caps; + + // 3) Force-Zuteilungen anwenden (nur für diese Phase) + foreach($forces_all as $f) { + if(intval($f->phase) !== $phase) continue; + $tn_id = intval($f->teilnehmer_id); + $ws_id = intval($f->workshop_id); + if(!isset($teilnehmer_by_id[$tn_id])) continue; // Teilnehmer nicht in dieser Phase + // Nur wenn Workshop existiert und noch Kapazität >=1 + if(isset($caps[$ws_id]) && $caps[$ws_id] > 0) { + $t = $teilnehmer_by_id[$tn_id]; + $wpdb->insert("{$prefix}kc_zuteilung", [ + 'wahl_id' => $wahl_id, + 'teilnehmer_id' => $t->id, + 'vorname' => $t->vorname, + 'nachname' => $t->nachname, + 'phase' => $phase, + 'workshop_id' => $ws_id, + 'wunsch_rang' => 0 + ]); + $caps[$ws_id]--; + // Entferne TN aus Liste (er ist bereits zugeteilt) + unset($teilnehmer_by_id[$tn_id]); + } + } + + // 4) Teilnehmer mischen (zufällige Reihenfolge) + $remaining = array_values($teilnehmer_by_id); + if(count($remaining) > 1) shuffle($remaining); + + // Hilfsfunktion: Try assign participant to workshop if cap>0 + $assign = function($tn, $ws_id, $rang) use (&$caps, $wpdb, $prefix, $wahl_id, $phase, &$assigned_ids) { + if(!isset($caps[$ws_id]) || $caps[$ws_id] <= 0) return false; + $wpdb->insert("{$prefix}kc_zuteilung", [ + 'wahl_id' => $wahl_id, + 'teilnehmer_id' => $tn->id, + 'vorname' => $tn->vorname, + 'nachname' => $tn->nachname, + 'phase' => $phase, + 'workshop_id' => $ws_id, + 'wunsch_rang' => $rang + ]); + $caps[$ws_id]--; + return true; + }; + + // 5) Wunschrunden 1..3 + for($wunsch=1;$wunsch<=3;$wunsch++) { + $not_assigned = []; + foreach($remaining as $tn) { + $ws_choice = intval($tn->{"wunsch$wunsch"}); + if($ws_choice > 0 && isset($caps[$ws_choice]) && $caps[$ws_choice] > 0) { + $assigned = $assign($tn, $ws_choice, $wunsch); + if(!$assigned) $not_assigned[] = $tn; + } else { + $not_assigned[] = $tn; + } + } + $remaining = $not_assigned; + // optional: reshuffle after each round to keep fairness + if(count($remaining) > 1) shuffle($remaining); + } + + // 6) Restliche zufällig verteilen (auf alle freie Workshops) + $freie = array_keys(array_filter($caps, function($c){return $c>0;})); + foreach($remaining as $tn) { + $freie = array_keys(array_filter($caps, function($c){return $c>0;})); + if(count($freie) === 0) { + // Kein Platz mehr: TN bleibt unzugeordnet + $wpdb->insert("{$prefix}kc_zuteilung", [ + 'wahl_id' => $wahl_id, + 'teilnehmer_id' => $tn->id, + 'vorname' => $tn->vorname, + 'nachname' => $tn->nachname, + 'phase' => $phase, + 'workshop_id' => null, + 'wunsch_rang' => -1 + ]); + continue; + } + $ws_id = $freie[array_rand($freie)]; + $assign($tn, $ws_id, 99); + } + + // 6.5 Consolidate workshops that did not reach their minimal Teilnehmerzahl + // Load minimal requirements for workshops in this Wahl + $ws_ids_in_wahl = array_keys($workshops); + if (!empty($ws_ids_in_wahl)) { + $placeholders = implode(',', array_fill(0, count($ws_ids_in_wahl), '%d')); + $min_rows = $wpdb->get_results($wpdb->prepare("SELECT id, min_teilnehmer FROM {$prefix}kc_workshops WHERE id IN ($placeholders)", $ws_ids_in_wahl)); + $min_map = []; + foreach($min_rows as $r) $min_map[intval($r->id)] = intval($r->min_teilnehmer); + + // Count current assignments per workshop + $assigned_counts_raw = $wpdb->get_results($wpdb->prepare("SELECT workshop_id, COUNT(*) AS cnt FROM {$prefix}kc_zuteilung WHERE wahl_id=%d AND phase=%d AND workshop_id IS NOT NULL GROUP BY workshop_id", $wahl_id, $phase), ARRAY_A); + $assigned_counts = []; + foreach($assigned_counts_raw as $ar) $assigned_counts[intval($ar['workshop_id'])] = intval($ar['cnt']); + + // Find failing workshops (assigned >0 but < min) + $failing = []; + foreach($ws_ids_in_wahl as $wsid) { + $min_req = intval($min_map[$wsid] ?? 0); + $cnt = intval($assigned_counts[$wsid] ?? 0); + if ($cnt > 0 && $min_req > 0 && $cnt < $min_req) { + $failing[] = $wsid; + } + } + + if (!empty($failing)) { + // collect participants from failing workshops + $to_reassign = []; + foreach($failing as $fw) { + $rows = $wpdb->get_results($wpdb->prepare("SELECT teilnehmer_id FROM {$prefix}kc_zuteilung WHERE wahl_id=%d AND phase=%d AND workshop_id=%d", $wahl_id, $phase, $fw)); + foreach($rows as $r) $to_reassign[] = intval($r->teilnehmer_id); + } + + if (!empty($to_reassign)) { + // remove those assignments + $fw_placeholders = implode(',', array_map('intval', $failing)); + $wpdb->query("DELETE FROM {$prefix}kc_zuteilung WHERE wahl_id=".intval($wahl_id)." AND phase=".intval($phase)." AND workshop_id IN ($fw_placeholders)"); + + // free capacity for the failing workshops + foreach($failing as $fw) { + $freed = intval($assigned_counts[$fw] ?? 0); + if (!isset($caps[$fw])) $caps[$fw] = 0; + $caps[$fw] += $freed; + } + + // Try to reassign each participant preferring their wishes 1..3 + foreach($to_reassign as $tid) { + $tn = isset($all_teilnehmer_by_id[$tid]) ? $all_teilnehmer_by_id[$tid] : $wpdb->get_row($wpdb->prepare("SELECT * FROM {$prefix}kc_teilnehmer WHERE id=%d", $tid)); + if (!$tn) continue; + $reassigned = false; + for($w=1;$w<=3;$w++) { + $choice = intval($tn->{"wunsch$w"}); + if ($choice > 0 && isset($caps[$choice]) && $caps[$choice] > 0) { + $assigned = $assign($tn, $choice, $w); + if ($assigned) { $reassigned = true; break; } + } + } + if ($reassigned) continue; + + // otherwise assign to any workshop with free capacity + $available = array_keys(array_filter($caps, function($c){return $c>0;})); + if (!empty($available)) { + $target = $available[array_rand($available)]; + $assign($tn, $target, 99); + continue; + } + + // lastly, mark as unassigned + $wpdb->insert("{$prefix}kc_zuteilung", [ + 'wahl_id' => $wahl_id, + 'teilnehmer_id' => $tn->id, + 'vorname' => $tn->vorname, + 'nachname' => $tn->nachname, + 'phase' => $phase, + 'workshop_id' => null, + 'wunsch_rang' => -1 + ]); + } + } + } + } + + // 7) Kapazitätsprüfung (Debug / Log) + foreach($caps as $wsid=>$capleft) { + if($capleft < 0) { + error_log("kc_run_zuteilung: Überbuchung Workshop $wsid in Wahl $wahl_id Phase $phase (restcap=$capleft)"); + } + } + + // 8) Ergebnis: alles in DB geschrieben (kc_zuteilung). Logge Zusammenfassung + $total_assigned = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM {$prefix}kc_zuteilung WHERE wahl_id=%d AND phase=%d AND workshop_id IS NOT NULL", $wahl_id, $phase)); + $total_unassigned = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM {$prefix}kc_zuteilung WHERE wahl_id=%d AND phase=%d AND workshop_id IS NULL", $wahl_id, $phase)); + error_log("kc_run_zuteilung: Phase $phase - zugeteilt: $total_assigned, ohne Platz: $total_unassigned"); + } + + error_log('kc_run_zuteilung: Fertig für Wahl '.$wahl_id); +} + +function kc_execute_blocks($blocks, &$context, &$i = 0) { + $count = count($blocks); + while($i < $count) { + $block = $blocks[$i]; + $block_name = is_array($block) && isset($block['block']) ? $block['block'] : (is_string($block) && strpos($block, ':') !== false ? explode(':', $block, 2)[0] : $block); + switch($block_name) { + case 'repeat': + $repeat_count = 3; + if(is_array($block) && isset($block['repeat_count'])) { + $repeat_count = intval($block['repeat_count']); + } elseif(is_string($block) && strpos($block, ':') !== false) { + $parts = explode(':', $block, 2); + $repeat_count = intval($parts[1]); + } + $i++; + $start = $i; + $inner = []; + $depth = 1; + while($i < $count && $depth > 0) { + $inner_block = $blocks[$i]; + $inner_block_name = is_array($inner_block) && isset($inner_block['block']) ? $inner_block['block'] : (is_string($inner_block) && strpos($inner_block, ':') !== false ? explode(':', $inner_block, 2)[0] : $inner_block); + if($inner_block_name === 'repeat') $depth++; + if($inner_block_name === 'endrepeat') $depth--; + if($depth > 0) $inner[] = $inner_block; + $i++; + } + for($r=0;$r<$repeat_count;$r++) { + $j = 0; + kc_execute_blocks($inner, $context, $j); + } + break; + case 'for_teilnehmer': + $i++; + $start = $i; + $inner = []; + $depth = 1; + while($i < $count && $depth > 0) { + if($blocks[$i] === 'for_teilnehmer') $depth++; + if($blocks[$i] === 'endfor_teilnehmer') $depth--; + if($depth > 0) $inner[] = $blocks[$i]; + $i++; + } + foreach($context['teilnehmer'] as $tn) { + $context['tn'] = $tn; + $j = 0; + kc_execute_blocks($inner, $context, $j); + } + break; + case 'for_workshop': + $i++; + $start = $i; + $inner = []; + $depth = 1; + while($i < $count && $depth > 0) { + if($blocks[$i] === 'for_workshop') $depth++; + if($blocks[$i] === 'endfor_workshop') $depth--; + if($depth > 0) $inner[] = $blocks[$i]; + $i++; + } + foreach($context['workshops'] as $ws) { + $context['ws'] = $ws; + $j = 0; + kc_execute_blocks($inner, $context, $j); + } + break; + case 'for_wunsch': + $i++; + $start = $i; + $inner = []; + $depth = 1; + while($i < $count && $depth > 0) { + if($blocks[$i] === 'for_wunsch') $depth++; + if($blocks[$i] === 'endfor_wunsch') $depth--; + if($depth > 0) $inner[] = $blocks[$i]; + $i++; + } + for($w=1;$w<=3;$w++) { + $context['wunsch_nr'] = $w; + $j = 0; + kc_execute_blocks($inner, $context, $j); + } + break; + // --- Hier die eigentliche Blocklogik einfügen --- + case 'shuffle': + $rest = array_filter($context['teilnehmer'], function($tn) use ($context) { + return !in_array($tn->id, $context['zugeteilt_ids']); + }); + $rest = array_values($rest); + if(count($rest) > 1) { + shuffle($rest); + $neu = []; + $i2 = 0; + foreach($context['teilnehmer'] as $tn) { + if(!in_array($tn->id, $context['zugeteilt_ids'])) { + $neu[] = $rest[$i2++]; + } else { + $neu[] = $tn; + } + } + $context['teilnehmer'] = $neu; + } + $i++; + break; + case 'force': + foreach($context['forces'] as $f) { + $tn = $context['wpdb']->get_row("SELECT * FROM {$context['prefix']}kc_teilnehmer WHERE id=".intval($f->teilnehmer_id)); + if(!$tn) continue; + if(isset($context['workshop_caps'][$f->workshop_id]) && $context['workshop_caps'][$f->workshop_id] > 0 && !in_array($tn->id, $context['zugeteilt_ids'])) { + $context['wpdb']->insert("{$context['prefix']}kc_zuteilung", [ + 'wahl_id' => $context['wahl_id'], + 'teilnehmer_id' => $tn->id, + 'vorname' => $tn->vorname, + 'nachname' => $tn->nachname, + 'phase' => $context['phase'], + 'workshop_id' => $f->workshop_id, + 'wunsch_rang' => 0 + ]); + $context['workshop_caps'][$f->workshop_id]--; + $context['zugeteilt_ids'][] = $tn->id; + } + } + $i++; + break; + case 'wunsch1': + case 'wunsch1_kapazitaet': + case 'wunsch2': + case 'wunsch2_kapazitaet': + case 'wunsch3': + case 'wunsch3_kapazitaet': + $wunsch_num = ($block === 'wunsch1' || $block === 'wunsch1_kapazitaet') ? 1 : (($block === 'wunsch2' || $block === 'wunsch2_kapazitaet') ? 2 : 3); + foreach($context['teilnehmer'] as $tn) { + if(in_array($tn->id, $context['zugeteilt_ids'])) continue; + $ws_id = intval($tn->{"wunsch$wunsch_num"}); + if(isset($context['workshop_caps'][$ws_id]) && $context['workshop_caps'][$ws_id] > 0) { + $context['wpdb']->insert("{$context['prefix']}kc_zuteilung", [ + 'wahl_id' => $context['wahl_id'], + 'teilnehmer_id' => $tn->id, + 'vorname' => $tn->vorname, + 'nachname' => $tn->nachname, + 'phase' => $context['phase'], + 'workshop_id' => $ws_id, + 'wunsch_rang' => $wunsch_num + ]); + $context['workshop_caps'][$ws_id]--; + $context['zugeteilt_ids'][] = $tn->id; + } + } + $i++; + break; + case 'random': + $freie_workshops = array_keys(array_filter($context['workshop_caps'], function($cap){return $cap>0;})); + $rest = array_filter($context['teilnehmer'], function($tn) use ($context) { + return !in_array($tn->id, $context['zugeteilt_ids']); + }); + $rest = array_values($rest); + foreach($rest as $tn) { + if(count($freie_workshops)>0) { + $ws_id = $freie_workshops[array_rand($freie_workshops)]; + $context['wpdb']->insert("{$context['prefix']}kc_zuteilung", [ + 'wahl_id' => $context['wahl_id'], + 'teilnehmer_id' => $tn->id, + 'vorname' => $tn->vorname, + 'nachname' => $tn->nachname, + 'phase' => $context['phase'], + 'workshop_id' => $ws_id, + 'wunsch_rang' => 99 + ]); + $context['workshop_caps'][$ws_id]--; + $context['zugeteilt_ids'][] = $tn->id; + $freie_workshops = array_keys(array_filter($context['workshop_caps'], function($cap){return $cap>0;})); + } else { + $context['wpdb']->insert("{$context['prefix']}kc_zuteilung", [ + 'wahl_id' => $context['wahl_id'], + 'teilnehmer_id' => $tn->id, + 'vorname' => $tn->vorname, + 'nachname' => $tn->nachname, + 'phase' => $context['phase'], + 'workshop_id' => null, + 'wunsch_rang' => -1 + ]); + } + } + $i++; + break; + default: + $i++; + break; + } + } +} +