diff --git a/TODO.md b/TODO.md index e3d6d12..81c30cc 100644 --- a/TODO.md +++ b/TODO.md @@ -234,3 +234,10 @@ Hinweis: Die Eintraege sind direkt aus den Quelldateien aggregiert. - [ ] L253: - TODO: SVG-Editor um Drag & Drop für diese Objekte erweitern und Klicks direkt mit dem Modul verbinden. - [ ] //TODO infrastruktur patchfelder löschen soll implementiert werden. + +## Topologie-Abgleich (16. Februar 2026) + +- [ ] #TODO: `connections.port_a_type` und `connections.port_b_type` um einen Patchpanel-Port-Typ erweitern (z. B. `patchpanel`) und auf `floor_patchpanel_ports.id` referenzieren. +- [ ] #TODO: Business-Regeln fuer Topologie in der Verbindungs-Validierung hinterlegen: Patchpanel-Port nur mit Patchpanel-Port oder Netzwerkbuchsen-Port verbinden. +- [ ] #TODO: Port-CRUD fuer Patchpanels ergaenzen: `floor_patchpanel_ports` beim Speichern aus `port_count` erzeugen/synchronisieren. +- [ ] #TODO: Port-CRUD fuer Netzwerkbuchsen ergaenzen: `network_outlet_ports` pflegen (mindestens ein Port je Buchse) und fuer Verbindungen nutzbar machen. diff --git a/app/modules/connections/list.php b/app/modules/connections/list.php index 5c24022..52c13e5 100644 --- a/app/modules/connections/list.php +++ b/app/modules/connections/list.php @@ -14,6 +14,49 @@ $search = trim($_GET['search'] ?? ''); $deviceId = (int)($_GET['device_id'] ?? 0); +// Einheitliche Endpunkt-Aufloesung fuer polymorphe Port-Typen. +$endpointUnionSql = " + SELECT + 'device' AS endpoint_type, + dp.id AS endpoint_id, + dp.name AS port_name, + d.name AS owner_name, + d.id AS owner_device_id + FROM device_ports dp + JOIN devices d ON d.id = dp.device_id + UNION ALL + SELECT + 'module' AS endpoint_type, + mp.id AS endpoint_id, + mp.name AS port_name, + CONCAT(d.name, ' / ', m.name) AS owner_name, + d.id AS owner_device_id + FROM module_ports mp + JOIN modules m ON m.id = mp.module_id + JOIN devices d ON d.id = m.device_id + UNION ALL + SELECT + 'outlet' AS endpoint_type, + nop.id AS endpoint_id, + nop.name AS port_name, + CONCAT(no.name, ' / ', IFNULL(r.name, ''), ' / ', IFNULL(f.name, '')) AS owner_name, + NULL AS owner_device_id + FROM network_outlet_ports nop + JOIN network_outlets no ON no.id = nop.outlet_id + LEFT JOIN rooms r ON r.id = no.room_id + LEFT JOIN floors f ON f.id = r.floor_id + UNION ALL + SELECT + 'floor_patchpanel' AS endpoint_type, + fpp.id AS endpoint_id, + fpp.name AS port_name, + CONCAT(fp.name, ' / ', IFNULL(f.name, '')) AS owner_name, + NULL AS owner_device_id + FROM floor_patchpanel_ports fpp + JOIN floor_patchpanels fp ON fp.id = fpp.patchpanel_id + LEFT JOIN floors f ON f.id = fp.floor_id +"; + // ========================= // WHERE-Clause bauen // ========================= @@ -22,7 +65,7 @@ $types = ''; $params = []; if ($search !== '') { - $where[] = "(d1.name LIKE ? OR d2.name LIKE ? OR dpt1.name LIKE ? OR dpt2.name LIKE ?)"; + $where[] = "(e1.owner_name LIKE ? OR e2.owner_name LIKE ? OR e1.port_name LIKE ? OR e2.port_name LIKE ?)"; $types .= "ssss"; $params[] = "%$search%"; $params[] = "%$search%"; @@ -31,7 +74,7 @@ if ($search !== '') { } if ($deviceId > 0) { - $where[] = "(d1.id = ? OR d2.id = ?)"; + $where[] = "(e1.owner_device_id = ? OR e2.owner_device_id = ?)"; $types .= "ii"; $params[] = $deviceId; $params[] = $deviceId; @@ -46,19 +89,35 @@ $connections = $sql->get( "SELECT c.id, c.port_a_type, c.port_a_id, c.port_b_type, c.port_b_id, - d1.name AS device_a_name, - d2.name AS device_b_name, - dpt1.name AS port_a_name, - dpt2.name AS port_b_name, + e1.owner_name AS endpoint_a_name, + e2.owner_name AS endpoint_b_name, + e1.port_name AS port_a_name, + e2.port_name AS port_b_name, c.vlan_config, c.comment FROM connections c - LEFT JOIN device_ports dpt1 ON c.port_a_type = 'device' AND c.port_a_id = dpt1.id - LEFT JOIN devices d1 ON dpt1.device_id = d1.id - LEFT JOIN device_ports dpt2 ON c.port_b_type = 'device' AND c.port_b_id = dpt2.id - LEFT JOIN devices d2 ON dpt2.device_id = d2.id + LEFT JOIN ($endpointUnionSql) e1 + ON c.port_a_id = e1.endpoint_id + AND ( + c.port_a_type = e1.endpoint_type + OR (c.port_a_type = 'device_ports' AND e1.endpoint_type = 'device') + OR (c.port_a_type = 'module_ports' AND e1.endpoint_type = 'module') + OR (c.port_a_type = 'network_outlet_ports' AND e1.endpoint_type = 'outlet') + OR (c.port_a_type = 'floor_patchpanel_ports' AND e1.endpoint_type = 'floor_patchpanel') + OR (c.port_a_type = 'patchpanel' AND e1.endpoint_type = 'floor_patchpanel') + ) + LEFT JOIN ($endpointUnionSql) e2 + ON c.port_b_id = e2.endpoint_id + AND ( + c.port_b_type = e2.endpoint_type + OR (c.port_b_type = 'device_ports' AND e2.endpoint_type = 'device') + OR (c.port_b_type = 'module_ports' AND e2.endpoint_type = 'module') + OR (c.port_b_type = 'network_outlet_ports' AND e2.endpoint_type = 'outlet') + OR (c.port_b_type = 'floor_patchpanel_ports' AND e2.endpoint_type = 'floor_patchpanel') + OR (c.port_b_type = 'patchpanel' AND e2.endpoint_type = 'floor_patchpanel') + ) $whereSql - ORDER BY d1.name, d2.name", + ORDER BY e1.owner_name, e2.owner_name", $types, $params ); @@ -84,29 +143,65 @@ if ($deviceId > 0) { if ($selectedDevice) { $selectedDevice['port_count'] = (int)($sql->single( - "SELECT COUNT(*) AS cnt FROM device_ports WHERE device_id = ?", - "i", - [$deviceId] + "SELECT COUNT(*) AS cnt + FROM ( + SELECT dp.id + FROM device_ports dp + WHERE dp.device_id = ? + UNION ALL + SELECT mp.id + FROM module_ports mp + JOIN modules m ON m.id = mp.module_id + WHERE m.device_id = ? + ) p", + "ii", + [$deviceId, $deviceId] )['cnt'] ?? 0); $selectedDevice['connection_count'] = (int)($sql->single( "SELECT COUNT(DISTINCT c.id) AS cnt FROM connections c - LEFT JOIN device_ports dpt1 ON c.port_a_type = 'device' AND c.port_a_id = dpt1.id - LEFT JOIN device_ports dpt2 ON c.port_b_type = 'device' AND c.port_b_id = dpt2.id - WHERE dpt1.device_id = ? OR dpt2.device_id = ?", + LEFT JOIN ($endpointUnionSql) e1 + ON c.port_a_id = e1.endpoint_id + AND ( + c.port_a_type = e1.endpoint_type + OR (c.port_a_type = 'device_ports' AND e1.endpoint_type = 'device') + OR (c.port_a_type = 'module_ports' AND e1.endpoint_type = 'module') + OR (c.port_a_type = 'network_outlet_ports' AND e1.endpoint_type = 'outlet') + OR (c.port_a_type = 'floor_patchpanel_ports' AND e1.endpoint_type = 'floor_patchpanel') + OR (c.port_a_type = 'patchpanel' AND e1.endpoint_type = 'floor_patchpanel') + ) + LEFT JOIN ($endpointUnionSql) e2 + ON c.port_b_id = e2.endpoint_id + AND ( + c.port_b_type = e2.endpoint_type + OR (c.port_b_type = 'device_ports' AND e2.endpoint_type = 'device') + OR (c.port_b_type = 'module_ports' AND e2.endpoint_type = 'module') + OR (c.port_b_type = 'network_outlet_ports' AND e2.endpoint_type = 'outlet') + OR (c.port_b_type = 'floor_patchpanel_ports' AND e2.endpoint_type = 'floor_patchpanel') + OR (c.port_b_type = 'patchpanel' AND e2.endpoint_type = 'floor_patchpanel') + ) + WHERE e1.owner_device_id = ? OR e2.owner_device_id = ?", "ii", [$deviceId, $deviceId] )['cnt'] ?? 0); $selectedDevicePorts = $sql->get( "SELECT name, vlan_config - FROM device_ports - WHERE device_id = ? - ORDER BY id + FROM ( + SELECT dp.name, dp.vlan_config, dp.id AS sort_id + FROM device_ports dp + WHERE dp.device_id = ? + UNION ALL + SELECT CONCAT(m.name, ' / ', mp.name) AS name, NULL AS vlan_config, (1000000 + mp.id) AS sort_id + FROM module_ports mp + JOIN modules m ON m.id = mp.module_id + WHERE m.device_id = ? + ) p + ORDER BY sort_id LIMIT 12", - "i", - [$deviceId] + "ii", + [$deviceId, $deviceId] ); foreach ($selectedDevicePorts as $port) { @@ -179,7 +274,7 @@ if ($deviceId > 0) { 0) { ?> -
+
-
+
diff --git a/app/modules/connections/save.php b/app/modules/connections/save.php index dbad99f..96068d7 100644 --- a/app/modules/connections/save.php +++ b/app/modules/connections/save.php @@ -23,6 +23,25 @@ $portBId = (int)($_POST['port_b_id'] ?? 0); $vlanConfig = $_POST['vlan_config'] ?? ''; $comment = trim($_POST['comment'] ?? ''); +$normalizePortType = static function (string $value): string { + $map = [ + 'device' => 'device', + 'device_ports' => 'device', + 'module' => 'module', + 'module_ports' => 'module', + 'outlet' => 'outlet', + 'network_outlet_ports' => 'outlet', + 'patchpanel' => 'patchpanel', + 'floor_patchpanel' => 'patchpanel', + 'floor_patchpanel_ports' => 'patchpanel', + ]; + $key = strtolower(trim($value)); + return $map[$key] ?? $key; +}; + +$portAType = $normalizePortType((string)$portAType); +$portBType = $normalizePortType((string)$portBType); + // ========================= // Validierung (einfach) // =========================