0) { $connection = $sql->single( "SELECT id, port_a_type, port_a_id, port_b_type, port_b_id, vlan_config, comment FROM connections WHERE id = ?", "i", [$connectionId] ); } $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] ?? 'device'; }; $portAType = $normalizePortType((string)($connection['port_a_type'] ?? 'device')); $portBType = $normalizePortType((string)($connection['port_b_type'] ?? 'device')); $portAId = (int)($connection['port_a_id'] ?? 0); $portBId = (int)($connection['port_b_id'] ?? 0); $endpointOptions = [ 'device' => [], 'module' => [], 'outlet' => [], 'patchpanel' => [], ]; $occupiedByType = [ 'device' => [], 'module' => [], 'outlet' => [], 'patchpanel' => [], ]; $occupiedRows = $sql->get( "SELECT id, port_a_type, port_a_id, port_b_type, port_b_id FROM connections WHERE id <> ?", "i", [$connectionId] ); foreach ((array)$occupiedRows as $row) { $typeA = $normalizePortType((string)($row['port_a_type'] ?? '')); $idA = (int)($row['port_a_id'] ?? 0); if ($idA > 0 && isset($occupiedByType[$typeA])) { $occupiedByType[$typeA][$idA] = true; } $typeB = $normalizePortType((string)($row['port_b_type'] ?? '')); $idB = (int)($row['port_b_id'] ?? 0); if ($idB > 0 && isset($occupiedByType[$typeB])) { $occupiedByType[$typeB][$idB] = true; } } $isEndpointAllowed = static function (string $type, int $id) use ($occupiedByType, $portAType, $portAId, $portBType, $portBId): bool { if ($id <= 0) { return false; } if ($type === 'outlet') { return true; } if ($type === $portAType && $id === $portAId) { return true; } if ($type === $portBType && $id === $portBId) { return true; } return empty($occupiedByType[$type][$id]); }; // Auto-heal: ensure each outlet has at least one selectable port. $outletsWithoutPorts = $sql->get( "SELECT o.id FROM network_outlets o LEFT JOIN network_outlet_ports nop ON nop.outlet_id = o.id GROUP BY o.id HAVING COUNT(nop.id) = 0", "", [] ); foreach ((array)$outletsWithoutPorts as $outletRow) { $outletId = (int)($outletRow['id'] ?? 0); if ($outletId <= 0) { continue; } $sql->set( "INSERT INTO network_outlet_ports (outlet_id, name) VALUES (?, 'Port 1')", "i", [$outletId] ); } $devicePorts = $sql->get( "SELECT dp.id, dp.name, d.name AS owner_name FROM device_ports dp JOIN devices d ON d.id = dp.device_id ORDER BY d.name, dp.name", "", [] ); foreach ($devicePorts as $row) { $id = (int)$row['id']; if (!$isEndpointAllowed('device', $id)) { continue; } $endpointOptions['device'][] = [ 'id' => $id, 'label' => $row['owner_name'] . ' / ' . $row['name'], ]; } $modulePorts = $sql->get( "SELECT mp.id, mp.name, m.name AS module_name, MIN(d.name) AS device_name FROM module_ports mp JOIN modules m ON m.id = mp.module_id LEFT JOIN device_port_modules dpm ON dpm.module_id = m.id LEFT JOIN device_ports dp ON dp.id = dpm.device_port_id LEFT JOIN devices d ON d.id = dp.device_id GROUP BY mp.id, mp.name, m.name ORDER BY device_name, module_name, mp.name", "", [] ); foreach ($modulePorts as $row) { $id = (int)$row['id']; if (!$isEndpointAllowed('module', $id)) { continue; } $deviceName = trim((string)($row['device_name'] ?? '')) ?: 'Unzugeordnet'; $endpointOptions['module'][] = [ 'id' => $id, 'label' => $deviceName . ' / ' . $row['module_name'] . ' / ' . $row['name'], ]; } $outletPorts = $sql->get( "SELECT nop.id, nop.name, o.name AS outlet_name, r.name AS room_name, f.name AS floor_name FROM network_outlet_ports nop JOIN network_outlets o ON o.id = nop.outlet_id LEFT JOIN rooms r ON r.id = o.room_id LEFT JOIN floors f ON f.id = r.floor_id ORDER BY floor_name, room_name, outlet_name, nop.name", "", [] ); foreach ($outletPorts as $row) { $id = (int)$row['id']; if (!$isEndpointAllowed('outlet', $id)) { continue; } $parts = array_filter([(string)($row['floor_name'] ?? ''), (string)($row['room_name'] ?? ''), (string)$row['outlet_name'], (string)$row['name']]); $endpointOptions['outlet'][] = [ 'id' => $id, 'label' => implode(' / ', $parts), ]; } $patchpanelPorts = $sql->get( "SELECT fpp.id, fpp.name, fp.name AS patchpanel_name, f.name AS floor_name 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 ORDER BY floor_name, patchpanel_name, fpp.name", "", [] ); foreach ($patchpanelPorts as $row) { $id = (int)$row['id']; if (!$isEndpointAllowed('patchpanel', $id)) { continue; } $parts = array_filter([(string)($row['floor_name'] ?? ''), (string)$row['patchpanel_name'], (string)$row['name']]); $endpointOptions['patchpanel'][] = [ 'id' => $id, 'label' => implode(' / ', $parts), ]; } $vlanValue = ''; if (!empty($connection['vlan_config'])) { $decoded = json_decode((string)$connection['vlan_config'], true); if (is_array($decoded)) { $vlanValue = implode(',', array_map('trim', $decoded)); } else { $vlanValue = (string)$connection['vlan_config']; } } $renderEndpointOptions = static function (array $optionsByType, int $selectedId): void { foreach ($optionsByType as $type => $options) { foreach ($options as $entry) { $isSelected = ((int)$entry['id'] === $selectedId) ? ' selected' : ''; echo ''; } } }; ?>