needlogin = true; $me = new User(); $me->loadMe(); $this->me = $me; $this->layout()->set("me", $me); if (!$me->is(["Admin", "netowner", "pipeplanner"])) { $this->redirect("Dashboard"); } } private function getMapCategories() { $categories = []; foreach (PopModel::$categoryArray as $id => $cat) { $categories[] = [ 'id' => $id, 'name' => $cat['name'], 'icon' => 'assets/img/markers/pop_' . $id . '.png', ]; } $categories[] = [ 'id' => null, 'name' => 'Unbekannt', 'icon' => 'assets/img/markers/pop_unknown.png', ]; return $categories; } protected function indexAction() { $networks = array_map(function ($network) { return [ "text" => $network->name, "value" => $network->name ]; }, NetworkModel::getAll()); $pops = array_map(function ($pop) { return [ "id" => $pop->id, "name" => $pop->name, "category" => $pop->category ?: 99, "networkArea" => $pop->networks, "location" => $pop->location, "zip" => $pop->zip, "city" => $pop->city, "street" => $pop->street, "number" => $pop->number, "state" => $pop->state, "folder_link" => $pop->folder_link, "doku_date" => $pop->doku_date, "vlan" => [ "public" => $pop->vlan_public, "nat" => $pop->vlan_nat, "ipv6" => $pop->vlan_ipv6 ], "gps" => $pop->gps_lat . ", " . $pop->gps_long ]; }, PopModel::getAlladv()); $categories = $this->getMapCategories(); $JSGlobals = ["BASE_URL" => self::getUrl(""), "DASHBOARD_URL" => self::getUrl("Dashboard"), "MFAPPNAME" => MFAPPNAME_SLUG, "PAGE_TITLE" => "Pops", "PATH" => [ ["text" => MFAPPNAME_SLUG, "href" => self::getUrl("Dashboard")], ["text" => "Pops", "href" => self::getUrl("Pop")] ], "NETWORKS" => $networks, "POPS" => $pops, "CATEGORIES" => $categories, "IS_ADMIN" => $this->me->is("Admin"), "MAPBOX_TOKEN" => TT_MAPBOX_TILE_API_TOKEN, ]; $this->layout()->set("vueViewName", "Pop"); $this->layout()->set("JSGlobals", $JSGlobals); $this->layout()->set("additionalCSS", [ "assets/css/leaflet.css", ]); $this->layout()->set("additionalJS", [ "assets/js/leaflet.js", "assets/js/leaflet.MakiMarkers.js" ]); $this->layout()->setTemplate("VueViews/Vue"); } protected function detailAction() { $id = $this->request->id; if (!is_numeric($id) || !$id) { $this->layout()->setFlash("pop nicht gefunden", "error"); $this->redirect("Pop"); } $pop = new Pop($id); if ($pop->id != $id) { $this->layout()->setFlash("Pop nicht gefunden", "error"); $this->redirect("Pop"); } $all_cables = FiberPlanCableModel::search(['network_id' => 90]); $cables_json = []; foreach ($all_cables as $cable) { if ($cable->coordinates) { $coords = json_decode($cable->coordinates, true); $cables_json[] = [ 'id' => $cable->id, 'description' => $cable->description, 'coordinates' => $coords ]; } } $this->layout()->set("cables_json", json_encode($cables_json)); $popnetwork = PopNetworkModel::getbyPopid($id); $stateArray = PopModel::$stateArray; $categoryArray=PopModel::$categoryArray; $this->layout()->set("stateArray", $stateArray); $this->layout()->set("categoryArray", $categoryArray); $this->layout()->set("popnetwork", implode(', ', $popnetwork['name'])); $this->layout()->set("popnetwork_ids", json_encode($popnetwork['network_id'])); $this->layout()->setTemplate("Pop/Detail"); $filter['pop_id'] = $id; $this->layout()->set("popracks", PoprackModel::getAllbyPop($id)); $this->layout()->set("devices", DeviceModel::search($filter)); $pops = PopModel::getOne($id); $this->layout()->set("pops", $pops); } protected function mapAction() { $network_id = 90; $this->layout()->set("network_id", $network_id); $this->layout()->set("networks", NetworkModel::getAll()); $this->layout()->set("categories", $this->getMapCategories()); $this->layout()->setTemplate("Pop/Map"); } protected function getCableDetailsAction() { $cable_name = $this->request->cable_name; $network_ids = $this->request->network_ids; $fiber_start = $this->request->fiber_start ?? null; $fiber_end = $this->request->fiber_end ?? null; if (!$cable_name) { return mfBaseController::returnJson(mfResponse::BadRequest(['message' => 'Kabel-Name fehlt'])); } $filter = ['description' => $cable_name]; if (!empty($network_ids)) { $filter['network_id'] = $network_ids; } $this->log->debug("Suche Kabel: '$cable_name' mit network_id=$network_id"); $cables = FiberPlanCableModel::search($filter); $this->log->debug("Gefundene Kabel: " . count($cables)); if (count($cables) === 0) { return mfBaseController::returnJson(mfResponse::NotFound(['message' => 'Kabel nicht gefunden'])); } $cable = $cables[0]; $db = FronkDB::singleton(); $cable_id = intval($cable->id); $this->log->debug("Lade Fasern für cable_id=$cable_id"); $where_clause = "cable_id=$cable_id"; if ($fiber_start !== null && $fiber_end !== null && $fiber_start !== '' && $fiber_end !== '') { $fiber_start_int = intval($fiber_start); $fiber_end_int = intval($fiber_end); $where_clause .= " AND CAST(fiber_nr_cable AS UNSIGNED) >= $fiber_start_int AND CAST(fiber_nr_cable AS UNSIGNED) <= $fiber_end_int"; $this->log->debug("Faser-Filter angewendet: Fasern $fiber_start_int - $fiber_end_int"); } $res = $db->select( "FiberPlanFiber", "*", "$where_clause ORDER BY CAST(fiber_nr_cable AS UNSIGNED) ASC" ); $fibers = []; if ($db->num_rows($res)) { while ($data = $db->fetch_object($res)) { $fibers[] = new FiberPlanFiber($data); } } $this->log->debug("Gefundene Fasern: " . count($fibers)); $cable_route_data = FiberPlanCableModel::getCableRoute($cable_id); $cable_route_array = []; foreach ($cable_route_data as $station) { $cable_route_array[] = $station['name']; } $cableData = [ 'id' => $cable->id, 'description' => $cable->description, 'fibers' => $cable->fibers, 'diameter' => $cable->diameter, 'state' => $cable->state, 'fiber_list' => [], 'branch_cables' => [], 'cable_route_array' => $cable_route_array, 'cable_route_full' => $cable_route_data, 'coordinates' => $cable->coordinates ]; $branchCables = []; foreach ($fibers as $fiber) { $fiberData = [ 'id' => $fiber->id, 'fiber_nr_cable' => $fiber->fiber_nr_cable, 'fiber_color' => $fiber->fiber_color, 'fiber_color_hex' => $fiber->fiber_color_hex, 'bundle_nr' => $fiber->bundle_nr, 'bundle_color' => $fiber->bundle_color, 'bundle_color_hex' => $fiber->bundle_color_hex, 'connector_nr' => $fiber->connector_nr, 'sheet_range' => $fiber->sheet_range, 'address' => $fiber->address, 'name' => $fiber->name, 'home_id' => $fiber->home_id, 'location' => $fiber->location, 'branch_type' => $fiber->branch_type, 'branch_cable_nr' => $fiber->branch_cable_nr, 'branch_fiber_nr' => $fiber->branch_fiber_nr, 'branch_to_location' => $fiber->branch_to_location, 'branch_from_location' => $fiber->branch_from_location, 'status' => $fiber->status, 'comment' => $fiber->comment, 'fiber_nr_bundle' => $fiber->fiber_nr_bundle ]; if ($fiber->branch_type === 'Abzweigkabel' && $fiber->branch_cable_nr) { $debug = []; $branchPath = $this->traceBranchPath($fiber, 0, 10, $debug); $lastEndpoint = $this->findLastEndpointInBranchPath($branchPath); if ($lastEndpoint) { $fiberData['final_home_id'] = $lastEndpoint['home_id']; $fiberData['final_location'] = $lastEndpoint['location']; } } $cableData['fiber_list'][] = $fiberData; if ($fiber->branch_type === 'Abzweigkabel' && $fiber->branch_cable_nr) { $branchKey = $fiber->branch_cable_nr; if (!isset($branchCables[$branchKey])) { $branchCables[$branchKey] = [ 'cable_name' => $fiber->branch_cable_nr, 'from_location' => $fiber->branch_from_location, 'to_location' => $fiber->branch_to_location, 'fiber_count' => 0, 'connections' => [] ]; } $branchCables[$branchKey]['connections'][] = [ 'main_fiber' => $fiber->fiber_nr_cable, 'branch_fiber' => $fiber->branch_fiber_nr, 'connector_nr' => $fiber->connector_nr ]; $branchCables[$branchKey]['fiber_count']++; } } $cableData['branch_cables'] = array_values($branchCables); return mfBaseController::returnJson(mfResponse::Ok(['cable' => $cableData])); } protected function getFiberPathAction() { $db = FronkDB::singleton(); $fiber_id = $this->request->fiber_id; $home_id = $this->request->home_id; if (!$fiber_id && !$home_id) { return mfBaseController::returnJson(mfResponse::BadRequest(['message' => 'Ungültige ID'])); } if ($home_id && !$fiber_id) { $sql = "SELECT id FROM FiberPlanFiber WHERE home_id = '" . $db->escape($home_id) . "' LIMIT 1"; $res = $db->query($sql); if ($db->num_rows($res)) { $row = $db->fetch_array($res); $fiber_id = $row['id']; } } $fiber = new FiberPlanFiber($fiber_id); if (!$fiber->id) { return mfBaseController::returnJson(mfResponse::NotFound(['message' => 'Faser nicht gefunden'])); } $details = $fiber->toArray(); $details['customer_cable_type'] = $fiber->customer_cable_type; $details['customer_cable_fiber_nr'] = $fiber->customer_cable_fiber_nr; $details['customer_connector_type'] = $fiber->customer_connector_type; $details['customer_cable_spec'] = $fiber->customer_cable_spec; $details['customer_fiber_range'] = $fiber->customer_fiber_range; $details['bundle_nr'] = $fiber->bundle_nr; $details['bundle_color'] = $fiber->bundle_color; $details['bundle_color_hex'] = $fiber->bundle_color_hex; $details['fiber_nr_bundle'] = $fiber->fiber_nr_bundle; if ($fiber->address || $fiber->home_id) { $customerGps = $this->geocodeAddress($fiber->address, $fiber->home_id); if ($customerGps) $details['customer_gps'] = $customerGps; } $debug = []; if ($home_id) { $cableChain = $this->buildCompleteCableChain($fiber); if (count($cableChain) > 0) { $mainCable = $cableChain[0]['cable']; $mainFiber = $cableChain[0]['fiber']; $cable_route_data = FiberPlanCableModel::getCableRoute($mainCable->id); $cable_route_array = []; foreach ($cable_route_data as $station) $cable_route_array[] = $station['name']; $allFibers = FiberPlanFiberModel::getByCableAndSheet($mainCable->id, null); $fibersArray = []; foreach ($allFibers as $f) { $fibersArray[] = [ 'id' => $f->id, 'fiber_nr_cable' => $f->fiber_nr_cable, 'fiber_color' => $f->fiber_color, 'fiber_color_hex' => $f->fiber_color_hex, 'bundle_nr' => $f->bundle_nr, 'bundle_color' => $f->bundle_color, 'bundle_color_hex' => $f->bundle_color_hex, 'branch_type' => $f->branch_type, 'branch_cable_nr' => $f->branch_cable_nr, 'branch_from_location' => $f->branch_from_location, 'branch_fiber_nr' => $f->branch_fiber_nr ]; } $branchPoints = []; $sql = "SELECT id, description as name, gps_lat, gps_long, object_type, 'dispatcher' as type FROM FiberPlanDispatcher WHERE network_id = 90 AND object_type = 4 AND gps_lat IS NOT NULL"; $res = $db->query($sql); while ($data = $db->fetch_array($res)) { $branchPoints[] = ['id' => $data['id'], 'name' => $data['name'], 'gps_lat' => $data['gps_lat'], 'gps_long' => $data['gps_long'], 'object_type' => intval($data['object_type']), 'type' => $data['type']]; } $details['cable_info'] = [ 'id' => $mainCable->id, 'description' => $mainCable->description, 'fibers' => $fibersArray, 'diameter' => $mainCable->diameter, 'cable_route_array' => $cable_route_array, 'cable_route_full' => $cable_route_data, 'coordinates' => $mainCable->coordinates, 'location' => $mainFiber->location, 'branch_points' => $branchPoints ]; $allCablesForMatching = []; foreach ($cableChain as $chainItem) { $c = $chainItem['cable']; $coords = json_decode($c->coordinates, true); if ($coords) $allCablesForMatching[] = ['id' => $c->id, 'description' => $c->description, 'coordinates' => $coords]; } $sql = "SELECT id, description, coordinates FROM FiberPlanCable WHERE network_id = 90 AND coordinates IS NOT NULL AND coordinates != '' AND coordinates != '[]'"; $res = $db->query($sql); while ($c = $db->fetch_array($res)) { $coords = json_decode($c['coordinates'], true); if ($coords) { $exists = false; foreach($allCablesForMatching as $ex) { if($ex['id'] == $c['id']) $exists=true; } if(!$exists) $allCablesForMatching[] = ['id' => $c['id'], 'description' => $c['description'], 'coordinates' => $coords]; } } $details['all_cables'] = $allCablesForMatching; } if (count($cableChain) > 1) { $details['branch_path'] = $this->buildBranchPathFromChain($cableChain, 1, $debug); } } else { $this->log->debug("=== MODUS: Vorwärts-Trace ==="); if ($fiber->cable_id) { $cable = new FiberPlanCable($fiber->cable_id); if ($cable->id) { $cable_route_data = FiberPlanCableModel::getCableRoute($cable->id); $cable_route_array = []; foreach ($cable_route_data as $station) $cable_route_array[] = $station['name']; $branchPoints = []; $sql = "SELECT id, description as name, gps_lat, gps_long, object_type, 'dispatcher' as type FROM FiberPlanDispatcher WHERE network_id = 90 AND object_type = 4 AND gps_lat IS NOT NULL"; $res = $db->query($sql); while ($data = $db->fetch_array($res)) { $branchPoints[] = ['id' => $data['id'], 'name' => $data['name'], 'gps_lat' => $data['gps_lat'], 'gps_long' => $data['gps_long'], 'object_type' => intval($data['object_type']), 'type' => $data['type']]; } $allFibers = FiberPlanFiberModel::getByCableAndSheet($cable->id, null); $fibersArray = []; foreach ($allFibers as $f) { $fibersArray[] = [ 'id' => $f->id, 'fiber_nr_cable' => $f->fiber_nr_cable, 'fiber_color' => $f->fiber_color, 'fiber_color_hex' => $f->fiber_color_hex, 'bundle_nr' => $f->bundle_nr, 'bundle_color' => $f->bundle_color, 'bundle_color_hex' => $f->bundle_color_hex, 'branch_type' => $f->branch_type, 'branch_cable_nr' => $f->branch_cable_nr, 'branch_from_location' => $f->branch_from_location, 'branch_fiber_nr' => $f->branch_fiber_nr ]; } $details['cable_info'] = [ 'id' => $cable->id, 'description' => $cable->description, 'fibers' => $fibersArray, 'diameter' => $cable->diameter, 'cable_route_array' => $cable_route_array, 'cable_route_full' => $cable_route_data, 'coordinates' => $cable->coordinates, 'location' => $fiber->location, 'branch_points' => $branchPoints ]; } } if ($fiber->branch_type === 'Abzweigkabel' && $fiber->branch_cable_nr) { $details['branch_path'] = $this->traceBranchPath($fiber, 0, 10, $debug); } $allCablesForMatching = []; $sql = "SELECT id, description, coordinates FROM FiberPlanCable WHERE network_id = 90 AND coordinates IS NOT NULL AND coordinates != '' AND coordinates != '[]'"; $res = $db->query($sql); while ($c = $db->fetch_array($res)) { $coords = json_decode($c['coordinates'], true); if ($coords) $allCablesForMatching[] = ['id' => $c['id'], 'description' => $c['description'], 'coordinates' => $coords]; } $details['all_cables'] = $allCablesForMatching; } $details['debug'] = $debug; return mfBaseController::returnJson(mfResponse::Ok(['fiber' => $details])); } protected function getAllFiberPathsForHomeAction() { $db = FronkDB::singleton(); $home_id = $this->request->home_id; if (!$home_id) { return mfBaseController::returnJson(mfResponse::BadRequest(['message' => 'Ungültige Home-ID'])); } $sql = "SELECT id FROM FiberPlanFiber WHERE home_id = '" . $db->escape($home_id) . "'"; $res = $db->query($sql); $fiberIds = []; if ($db->num_rows($res)) { while ($row = $db->fetch_array($res)) { $fiberIds[] = $row['id']; } } if (empty($fiberIds)) { return mfBaseController::returnJson(mfResponse::NotFound(['message' => 'Keine Fasern für Home-ID gefunden'])); } $globalBranchPoints = []; $sqlBP = "SELECT id, description as name, gps_lat, gps_long, object_type, 'dispatcher' as type FROM FiberPlanDispatcher WHERE network_id = 90 AND object_type IN (1,2,3,4) AND gps_lat IS NOT NULL AND gps_long IS NOT NULL"; $resBP = $db->query($sqlBP); if ($db->num_rows($resBP)) { while ($data = $db->fetch_array($resBP)) { $globalBranchPoints[] = [ 'id' => $data['id'], 'name' => $data['name'], 'gps_lat' => $data['gps_lat'], 'gps_long' => $data['gps_long'], 'object_type' => intval($data['object_type']), 'type' => $data['type'] ]; } } $globalCablesWithCoords = []; $sqlCables = "SELECT id, description, coordinates FROM FiberPlanCable WHERE network_id = 90 AND coordinates IS NOT NULL AND coordinates != '' AND coordinates != '[]'"; $resCables = $db->query($sqlCables); while ($cableData = $db->fetch_array($resCables)) { $coords = json_decode($cableData['coordinates'], true); if ($coords && is_array($coords) && count($coords) > 0) { $globalCablesWithCoords[] = [ 'id' => $cableData['id'], 'description' => $cableData['description'], 'coordinates' => $coords ]; } } $allPaths = []; foreach ($fiberIds as $fiber_id) { $fiber = new FiberPlanFiber($fiber_id); if (!$fiber->id) continue; $details = $fiber->toArray(); $details['customer_cable_type'] = $fiber->customer_cable_type; $details['customer_cable_fiber_nr'] = $fiber->customer_cable_fiber_nr; $details['customer_connector_type'] = $fiber->customer_connector_type; $details['customer_cable_spec'] = $fiber->customer_cable_spec; $details['customer_fiber_range'] = $fiber->customer_fiber_range; $details['bundle_nr'] = $fiber->bundle_nr; $details['bundle_color'] = $fiber->bundle_color; $details['bundle_color_hex'] = $fiber->bundle_color_hex; $details['fiber_nr_bundle'] = $fiber->fiber_nr_bundle; if ($fiber->address || $fiber->home_id) { $customerGps = $this->geocodeAddress($fiber->address, $fiber->home_id); if ($customerGps) { $details['customer_gps'] = $customerGps; } } $debug = []; $debug['start_fiber'] = [ 'id' => $fiber->id, 'fiber_nr_cable' => $fiber->fiber_nr_cable, 'branch_type' => $fiber->branch_type ]; $cableChain = $this->buildCompleteCableChain($fiber); $debug['cable_chain'] = array_map(function($item) { return [ 'cable_id' => $item['cable']->id, 'cable_name' => $item['cable']->description, 'fiber_id' => $item['fiber']->id, 'type' => $item['type'], 'depth' => $item['depth'] ]; }, $cableChain); if (count($cableChain) > 0) { $mainCable = $cableChain[0]['cable']; $mainFiber = $cableChain[0]['fiber']; $cable_route_data = FiberPlanCableModel::getCableRoute($mainCable->id); $cable_route_array = []; foreach ($cable_route_data as $station) { $cable_route_array[] = $station['name']; } $allMainFibers = FiberPlanFiberModel::getByCableAndSheet($mainCable->id, null); $fibersArray = []; foreach ($allMainFibers as $f) { $fibersArray[] = [ 'id' => $f->id, 'fiber_nr_cable' => $f->fiber_nr_cable, 'fiber_color' => $f->fiber_color, 'fiber_color_hex' => $f->fiber_color_hex, 'bundle_nr' => $f->bundle_nr, 'bundle_color' => $f->bundle_color, 'bundle_color_hex' => $f->bundle_color_hex, 'branch_type' => $f->branch_type, 'branch_cable_nr' => $f->branch_cable_nr, 'branch_from_location' => $f->branch_from_location, 'branch_fiber_nr' => $f->branch_fiber_nr ]; } $details['cable_info'] = [ 'id' => $mainCable->id, 'description' => $mainCable->description, 'fibers' => $fibersArray, 'diameter' => $mainCable->diameter, 'cable_route_array' => $cable_route_array, 'cable_route_full' => $cable_route_data, 'coordinates' => $mainCable->coordinates, 'location' => $mainFiber->location, 'branch_points' => $globalBranchPoints ]; $allCablesForMatching = []; foreach ($cableChain as $chainItem) { $c = $chainItem['cable']; $coords = $c->coordinates; if (is_string($coords)) { $coords = json_decode($coords, true); } if ($coords && is_array($coords) && count($coords) > 0) { $allCablesForMatching[] = [ 'id' => $c->id, 'description' => $c->description, 'coordinates' => $coords ]; } } foreach ($globalCablesWithCoords as $gc) { $exists = false; foreach ($allCablesForMatching as $existing) { if ($existing['id'] == $gc['id']) { $exists = true; break; } } if (!$exists) { $allCablesForMatching[] = $gc; } } $details['all_cables'] = $allCablesForMatching; } if (count($cableChain) > 1) { $details['branch_path'] = $this->buildBranchPathFromChain($cableChain, 1, $debug); } $details['debug'] = $debug; $allPaths[] = [ 'fiber' => $details ]; } return mfBaseController::returnJson(mfResponse::Ok(['paths' => $allPaths])); } private function buildCompleteCableChain($endFiber) { $db = FronkDB::singleton(); $chain = []; $currentFiber = $endFiber; $depth = 0; $maxDepth = 10; $this->log->debug("=== START: Build Complete Cable Chain (Rückwärts) ==="); $this->log->debug("End-Faser ID: {$endFiber->id}, Cable ID: {$endFiber->cable_id}"); $currentCable = new FiberPlanCable($currentFiber->cable_id); array_unshift($chain, [ 'cable' => $currentCable, 'fiber' => $currentFiber, 'type' => 'current', 'depth' => $depth ]); while ($depth < $maxDepth) { $currentFiberNr = intval($currentFiber->fiber_nr_cable); $sql = "SELECT * FROM FiberPlanFiber WHERE branch_type = 'Abzweigkabel' AND branch_cable_nr = '" . $db->escape($currentCable->description) . "' AND branch_fiber_nr = $currentFiberNr LIMIT 1"; $this->log->debug("Depth $depth: Suche Parent-Faser für Kabel: {$currentCable->description}"); $res = $db->query($sql); if ($db->num_rows($res)) { $parentFiberData = $db->fetch_object($res); $parentFiber = new FiberPlanFiber($parentFiberData); $parentCable = new FiberPlanCable($parentFiber->cable_id); $this->log->debug(" -> Parent gefunden: Faser ID {$parentFiber->id} in Kabel {$parentCable->description}"); array_unshift($chain, [ 'cable' => $parentCable, 'fiber' => $parentFiber, 'type' => $depth == 0 ? 'parent' : 'main', 'depth' => $depth + 1, 'branches_to' => $currentCable->description ]); $currentCable = $parentCable; $currentFiber = $parentFiber; $depth++; } else { $this->log->debug(" -> Kein Parent gefunden - Hauptkabel erreicht"); break; } } if (count($chain) > 0) { $chain[0]['type'] = 'main'; } $this->log->debug("=== ENDE: Cable Chain hat " . count($chain) . " Segmente ==="); return $chain; } private function buildBranchPathFromChain($cableChain, $startIndex, &$debug) { if ($startIndex >= count($cableChain)) { return null; } $current = $cableChain[$startIndex]; $cable = $current['cable']; $fiber = $current['fiber']; $cable_route_data = FiberPlanCableModel::getCableRoute($cable->id); $cable_route_array = []; foreach ($cable_route_data as $station) { $cable_route_array[] = $station['name']; } $dropoutLocation = null; if ($startIndex > 0) { $parentChainItem = $cableChain[$startIndex - 1]; $parentFiber = $parentChainItem['fiber']; if ($parentFiber->branch_from_location) { $dropoutLocation = $parentFiber->branch_from_location; $this->log->debug("Branch {$cable->description}: Dropout bei {$dropoutLocation}"); } } $path = [ 'cable' => [ 'id' => $cable->id, 'description' => $cable->description, 'fibers' => $cable->fibers, 'location' => $dropoutLocation ?: $fiber->location, 'from_location' => $fiber->branch_from_location, 'to_location' => $fiber->branch_to_location, 'cable_route_array' => $cable_route_array, 'cable_route_full' => $cable_route_data, 'coordinates' => $cable->coordinates, 'cable_info' => [ 'id' => $cable->id, 'description' => $cable->description, 'coordinates' => $cable->coordinates ] ], 'target_fiber' => [ 'id' => $fiber->id, 'fiber_nr_cable' => $fiber->fiber_nr_cable, 'fiber_color' => $fiber->fiber_color, 'fiber_color_hex' => $fiber->fiber_color_hex, 'bundle_nr' => $fiber->bundle_nr, 'bundle_color' => $fiber->bundle_color, 'bundle_color_hex' => $fiber->bundle_color_hex, 'home_id' => $fiber->home_id, 'address' => $fiber->address, 'location' => $dropoutLocation ?: $fiber->location, 'branch_from_location' => $fiber->branch_from_location, 'branch_to_location' => $fiber->branch_to_location ], 'next_branch' => null ]; if ($fiber->address || $fiber->home_id) { $customerGps = $this->geocodeAddress($fiber->address, $fiber->home_id); if ($customerGps) { $path['target_fiber']['customer_gps'] = $customerGps; } } if ($startIndex + 1 < count($cableChain)) { $path['next_branch'] = $this->buildBranchPathFromChain($cableChain, $startIndex + 1, $debug); } return $path; } private function traceBranchPath($startFiber, $depth = 0, $maxDepth = 10, &$debug = []) { $stepKey = "step_depth_" . $depth; $debug[$stepKey] = []; $debug[$stepKey]['input'] = [ 'fiber_id' => $startFiber->id, 'branch_cable_nr' => $startFiber->branch_cable_nr, 'branch_fiber_nr' => $startFiber->branch_fiber_nr, 'depth' => $depth ]; if ($depth >= $maxDepth) { $debug[$stepKey]['error'] = 'Maximale Verschachtelungstiefe erreicht'; return ['error' => 'Maximale Verschachtelungstiefe erreicht']; } $path = []; $db = FronkDB::singleton(); $branch_cable_nr = $db->escape($startFiber->branch_cable_nr); $debug[$stepKey]['search_cable'] = [ 'searching_for' => $startFiber->branch_cable_nr, 'escaped' => $branch_cable_nr ]; $cables = FiberPlanCableModel::search(['description' => $startFiber->branch_cable_nr]); $debug[$stepKey]['cable_search_result'] = [ 'found_count' => count($cables), 'cables' => [] ]; foreach ($cables as $c) { $debug[$stepKey]['cable_search_result']['cables'][] = [ 'id' => $c->id, 'description' => $c->description ]; } if (count($cables) > 0) { $branchCable = $cables[0]; $debug[$stepKey]['found_cable'] = [ 'id' => $branchCable->id, 'description' => $branchCable->description, 'fibers' => $branchCable->fibers ]; $locationRes = $db->select( "FiberPlanFiber", "location", "cable_id={$branchCable->id} AND location IS NOT NULL AND location != '' LIMIT 1" ); $cableLocation = null; if ($db->num_rows($locationRes)) { $locationData = $db->fetch_object($locationRes); $cableLocation = $locationData->location; $this->log->debug("Location für Abzweigkabel {$branchCable->description}: $cableLocation"); } $path['cable'] = [ 'id' => $branchCable->id, 'description' => $branchCable->description, 'fibers' => $branchCable->fibers, 'location' => $cableLocation, 'from_location' => $startFiber->branch_from_location, 'to_location' => $startFiber->branch_to_location, 'cable_route_array' => null, 'cable_route_full' => null, 'coordinates' => $branchCable->coordinates, 'cable_info' => [ 'id' => $branchCable->id, 'description' => $branchCable->description, 'coordinates' => $branchCable->coordinates ] ]; $branch_route_data = FiberPlanCableModel::getCableRoute($branchCable->id); $branch_route_array = []; foreach ($branch_route_data as $station) { $branch_route_array[] = $station['name']; } $path['cable']['cable_route_array'] = $branch_route_array; $path['cable']['cable_route_full'] = $branch_route_data; if ($branchCable->cable_route) { $path['cable']['cable_route'] = $branchCable->cable_route; $routeArray = json_decode($branchCable->cable_route, true); if (is_array($routeArray)) { $path['cable']['cable_route_array'] = $routeArray; } } if ($startFiber->branch_fiber_nr) { $branch_fiber_nr = intval($startFiber->branch_fiber_nr); $sql_where = "cable_id={$branchCable->id} AND fiber_nr_cable=$branch_fiber_nr"; $debug[$stepKey]['search_fiber'] = [ 'cable_id' => $branchCable->id, 'fiber_nr_cable' => $branch_fiber_nr, 'sql_where' => $sql_where ]; $res = $db->select( "FiberPlanFiber", "*", "$sql_where LIMIT 1" ); $debug[$stepKey]['fiber_search_result'] = [ 'num_rows' => $db->num_rows($res) ]; if ($db->num_rows($res)) { $branchFiberData = $db->fetch_object($res); $branchFiber = new FiberPlanFiber($branchFiberData); $debug[$stepKey]['found_fiber'] = [ 'id' => $branchFiber->id, 'fiber_nr_cable' => $branchFiber->fiber_nr_cable, 'fiber_color' => $branchFiber->fiber_color, 'home_id' => $branchFiber->home_id, 'address' => $branchFiber->address, 'branch_type' => $branchFiber->branch_type, 'branch_cable_nr' => $branchFiber->branch_cable_nr, 'branch_fiber_nr' => $branchFiber->branch_fiber_nr ]; $path['target_fiber'] = [ 'id' => $branchFiber->id, 'fiber_nr_cable' => $branchFiber->fiber_nr_cable, 'fiber_color' => $branchFiber->fiber_color, 'fiber_color_hex' => $branchFiber->fiber_color_hex, 'bundle_nr' => $branchFiber->bundle_nr, 'bundle_color' => $branchFiber->bundle_color, 'bundle_color_hex' => $branchFiber->bundle_color_hex, 'fiber_nr_bundle' => $branchFiber->fiber_nr_bundle, 'connector_nr' => $branchFiber->connector_nr, 'home_id' => $branchFiber->home_id, 'address' => $branchFiber->address, 'name' => $branchFiber->name, 'location' => $branchFiber->location, 'branch_type' => $branchFiber->branch_type, 'branch_cable_nr' => $branchFiber->branch_cable_nr, 'branch_fiber_nr' => $branchFiber->branch_fiber_nr, 'branch_from_location' => $branchFiber->branch_from_location, 'branch_to_location' => $branchFiber->branch_to_location, 'customer_cable_type' => $branchFiber->customer_cable_type, 'customer_cable_fiber_nr' => $branchFiber->customer_cable_fiber_nr, 'customer_connector_type' => $branchFiber->customer_connector_type, 'customer_cable_spec' => $branchFiber->customer_cable_spec, 'customer_fiber_range' => $branchFiber->customer_fiber_range, 'status' => $branchFiber->status, 'comment' => $branchFiber->comment ]; if ($branchFiber->address || $branchFiber->home_id) { $customerGps = $this->geocodeAddress($branchFiber->address, $branchFiber->home_id); if ($customerGps) { $path['target_fiber']['customer_gps'] = $customerGps; $this->log->debug("GPS für Branch-Kunde gefunden: " . json_encode($customerGps)); } else { $this->log->debug("Kein GPS für Branch-Kunde - Adresse: {$branchFiber->address}, Home-ID: {$branchFiber->home_id}"); } } if ($branchFiber->branch_type === 'Abzweigkabel' && $branchFiber->branch_cable_nr) { $debug[$stepKey]['next_branch_detected'] = [ 'next_cable' => $branchFiber->branch_cable_nr, 'next_fiber' => $branchFiber->branch_fiber_nr ]; $path['next_branch'] = $this->traceBranchPath($branchFiber, $depth + 1, $maxDepth, $debug); } if ($branchFiber->home_id) { $debug[$stepKey]['endpoint_found'] = true; $path['endpoint'] = [ 'type' => 'customer', 'home_id' => $branchFiber->home_id, 'address' => $branchFiber->address, 'name' => $branchFiber->name ]; } } else { $debug[$stepKey]['error'] = "Faser #$branch_fiber_nr nicht gefunden in Kabel {$branchCable->description}"; } } else { $debug[$stepKey]['error'] = "branch_fiber_nr ist leer"; } $res = $db->select( "FiberPlanFiber", "*", "cable_id={$branchCable->id} ORDER BY fiber_nr_cable ASC" ); $allFibers = []; if ($db->num_rows($res)) { while ($data = $db->fetch_object($res)) { $f = new FiberPlanFiber($data); $allFibers[] = [ 'id' => $f->id, 'fiber_nr_cable' => $f->fiber_nr_cable, 'fiber_color' => $f->fiber_color, 'fiber_color_hex' => $f->fiber_color_hex, 'connector_nr' => $f->connector_nr, 'home_id' => $f->home_id, 'address' => $f->address, 'branch_type' => $f->branch_type, 'branch_cable_nr' => $f->branch_cable_nr ]; } } $path['all_fibers'] = $allFibers; $path['fiber_count'] = count($allFibers); $debug[$stepKey]['all_fibers_count'] = count($allFibers); } else { $debug[$stepKey]['error'] = "Abzweigkabel '{$startFiber->branch_cable_nr}' nicht gefunden in FiberPlanCable"; $path['error'] = "Abzweigkabel '{$startFiber->branch_cable_nr}' nicht gefunden"; $allCables = FiberPlanCableModel::getAll(); $debug[$stepKey]['available_cables'] = []; foreach ($allCables as $c) { $debug[$stepKey]['available_cables'][] = [ 'id' => $c->id, 'description' => $c->description ]; } } return $path; } protected function getCableFibersForEditAction() { $cable_id = $this->request->cable_id; if (!$cable_id || !is_numeric($cable_id)) { return mfBaseController::returnJson(mfResponse::BadRequest([ 'message' => 'Ungültige Kabel-ID' ])); } $this->log->debug("Lade Fasern für Excel-Editor: cable_id=$cable_id"); try { $cable = new FiberPlanCable($cable_id); if (!$cable->id) { return mfBaseController::returnJson(mfResponse::NotFound([ 'message' => 'Kabel nicht gefunden' ])); } $cableRoute = null; if ($cable->cable_route) { $routeArray = json_decode($cable->cable_route, true); if (is_array($routeArray)) { $cableRoute = $routeArray; } } $db = FronkDB::singleton(); $res = $db->select( "FiberPlanFiber", "*", "cable_id=$cable_id ORDER BY CAST(fiber_nr_cable AS UNSIGNED) ASC" ); $fibers = []; if ($db->num_rows($res)) { while ($data = $db->fetch_object($res)) { $fiber = new FiberPlanFiber($data); $fibers[] = [ 'id' => $fiber->id, 'connector_nr' => $fiber->connector_nr, 'fiber_nr_cable' => $fiber->fiber_nr_cable, 'bundle_nr' => $fiber->bundle_nr, 'fiber_nr_bundle' => $fiber->fiber_nr_bundle, 'fiber_color' => $fiber->fiber_color, 'fiber_color_hex' => $fiber->fiber_color_hex, 'bundle_color' => $fiber->bundle_color, 'bundle_color_hex' => $fiber->bundle_color_hex, 'branch_type' => $fiber->branch_type, 'branch_cable_nr' => $fiber->branch_cable_nr, 'branch_fiber_count' => $fiber->branch_fiber_count, 'branch_fiber_nr' => $fiber->branch_fiber_nr, 'branch_bundle_nr' => $fiber->branch_bundle_nr, 'branch_fiber_in_bundle' => $fiber->branch_fiber_in_bundle, 'branch_bundle_color' => $fiber->branch_bundle_color, 'branch_bundle_color_hex' => $fiber->branch_bundle_color_hex, 'branch_from_location' => $fiber->branch_from_location, 'branch_to_location' => $fiber->branch_to_location, 'branch_gis_id' => $fiber->branch_gis_id, 'address' => $fiber->address, 'name' => $fiber->name, 'home_id' => $fiber->home_id, 'location' => $fiber->location, 'rack_unit' => $fiber->rack_unit, 'termination_type' => $fiber->termination_type, 'customer_cable_type' => $fiber->customer_cable_type, 'customer_cable_fiber_nr' => $fiber->customer_cable_fiber_nr, 'customer_connector_type' => $fiber->customer_connector_type, 'customer_cable_spec' => $fiber->customer_cable_spec, 'customer_fiber_range' => $fiber->customer_fiber_range, 'splitter_location' => $fiber->splitter_location, 'splitter_factor' => $fiber->splitter_factor, 'uuid_qgis_kabel' => $fiber->uuid_qgis_kabel, 'status' => $fiber->status, 'comment' => $fiber->comment ]; } } $this->log->debug("Gefundene Fasern für Excel-Editor: " . count($fibers)); return mfBaseController::returnJson(mfResponse::Ok([ 'success' => true, 'data' => $fibers, 'route' => $cableRoute, 'cable_info' => [ 'id' => $cable->id, 'description' => $cable->description, 'fibers' => $cable->fibers, 'diameter' => $cable->diameter ] ])); } catch (Exception $e) { $this->log->error("Fehler beim Laden der Fasern: " . $e->getMessage()); return mfBaseController::returnJson(mfResponse::InternalServerError([ 'success' => false, 'message' => $e->getMessage() ])); } } protected function saveCableFibersAction() { $cable_id = $this->request->cable_id; $fibers_json = $this->request->fibers; if (!$cable_id || !is_numeric($cable_id)) { return mfBaseController::returnJson(mfResponse::BadRequest([ 'success' => false, 'message' => 'Ungültige Kabel-ID' ])); } if (!$fibers_json) { return mfBaseController::returnJson(mfResponse::BadRequest([ 'success' => false, 'message' => 'Keine Faser-Daten übergeben' ])); } $fibers = json_decode($fibers_json, true); if (!is_array($fibers)) { return mfBaseController::returnJson(mfResponse::BadRequest([ 'success' => false, 'message' => 'Ungültiges Datenformat' ])); } $this->log->debug("Speichere " . count($fibers) . " Fasern für cable_id=$cable_id"); try { $db = FronkDB::singleton(); $updatedCount = 0; $errorCount = 0; foreach ($fibers as $fiberData) { if (!isset($fiberData['id']) || empty($fiberData['id'])) { continue; } $fiber_id = intval($fiberData['id']); $fiber = new FiberPlanFiber($fiber_id); if (!$fiber->id) { $this->log->warning("Faser ID $fiber_id nicht gefunden - überspringe"); $errorCount++; continue; } $updateData = [ 'connector_nr' => $fiberData['connector_nr'] ?? null, 'fiber_nr_cable' => isset($fiberData['fiber_nr_cable']) ? intval($fiberData['fiber_nr_cable']) : null, 'bundle_nr' => $fiberData['bundle_nr'] ?? null, 'fiber_nr_bundle' => $fiberData['fiber_nr_bundle'] ?? null, 'fiber_color' => $fiberData['fiber_color'] ?? null, 'bundle_color' => $fiberData['bundle_color'] ?? null, 'branch_type' => $fiberData['branch_type'] ?? null, 'branch_cable_nr' => $fiberData['branch_cable_nr'] ?? null, 'branch_fiber_count' => $fiberData['branch_fiber_count'] ?? null, 'branch_fiber_nr' => $fiberData['branch_fiber_nr'] ?? null, 'branch_bundle_nr' => $fiberData['branch_bundle_nr'] ?? null, 'branch_fiber_in_bundle' => $fiberData['branch_fiber_in_bundle'] ?? null, 'branch_bundle_color' => $fiberData['branch_bundle_color'] ?? null, 'branch_from_location' => $fiberData['branch_from_location'] ?? null, 'branch_to_location' => $fiberData['branch_to_location'] ?? null, 'branch_gis_id' => $fiberData['branch_gis_id'] ?? null, 'address' => $fiberData['address'] ?? null, 'name' => $fiberData['name'] ?? null, 'home_id' => $fiberData['home_id'] ?? null, 'location' => $fiberData['location'] ?? null, 'rack_unit' => $fiberData['rack_unit'] ?? null, 'termination_type' => $fiberData['termination_type'] ?? null, 'customer_cable_type' => $fiberData['customer_cable_type'] ?? null, 'customer_cable_fiber_nr' => $fiberData['customer_cable_fiber_nr'] ?? null, 'customer_connector_type' => $fiberData['customer_connector_type'] ?? null, 'customer_cable_spec' => $fiberData['customer_cable_spec'] ?? null, 'customer_fiber_range' => $fiberData['customer_fiber_range'] ?? null, 'splitter_location' => $fiberData['splitter_location'] ?? null, 'splitter_factor' => $fiberData['splitter_factor'] ?? null, 'uuid_qgis_kabel' => $fiberData['uuid_qgis_kabel'] ?? null, 'status' => $fiberData['status'] ?? null, 'comment' => $fiberData['comment'] ?? null, 'edit_by' => $this->me->id ?? 1, 'edit' => time() ]; $fiber->update($updateData); $result = $fiber->save(); if ($result) { $updatedCount++; } else { $errorCount++; $this->log->error("Fehler beim Speichern von Faser ID $fiber_id"); } } $this->log->info("Fasern gespeichert: $updatedCount erfolgreich, $errorCount Fehler"); return mfBaseController::returnJson(mfResponse::Ok([ 'success' => true, 'message' => "$updatedCount Fasern erfolgreich gespeichert", 'updated_count' => $updatedCount, 'error_count' => $errorCount ])); } catch (Exception $e) { $this->log->error("Fehler beim Speichern der Fasern: " . $e->getMessage()); return mfBaseController::returnJson(mfResponse::InternalServerError([ 'success' => false, 'message' => 'Fehler beim Speichern: ' . $e->getMessage() ])); } } protected function addAction() { $stateArray = PopModel::$stateArray; $categoryArray=PopModel::$categoryArray; $this->layout()->set("stateArray", $stateArray); $this->layout()->set("categoryArray", $categoryArray); $this->layout()->setTemplate("Pop/Form"); $this->layout()->set("networks", NetworkModel::getAll()); if ($this->request->network_id) { $pop = new Pop(); $pop->network_id = $this->request->network_id; $this->layout()->set("pop", $pop); } } protected function editAction() { $id = $this->request->id; if (!is_numeric($id) || !$id) { $this->layout()->setFlash("POP nicht gefunden", "error"); $this->redirect("Network"); } $pop = new Pop($id); if ($pop->id != $id) { $this->layout()->setFlash("POP nicht gefunden", "error"); $this->redirect("Network"); } $popnetwork = PopNetworkModel::getbyPopid($id); $this->layout()->set("popnetwork", $popnetwork['network_id']); $this->layout()->set("pop", $pop); $this->addAction(); } protected function saveAction() { $r = $this->request; $id = $r->id; //var_dump($r);exit; if (is_numeric($id) && $id > 0) { $mode = "edit"; $pop = new Pop($id); if (!$pop->id) { $this->layout()->setFlash("POP nicht gefunden", "error"); $this->redirect("Network"); } } else { $mode = "add"; } $this->log->debug(print_r($r, true)); if (!$r->network_id || !$r->name) { $this->layout()->setFlash("Bitte Name und Netzgebiet eintragen", "error"); $this->layout()->set("pop", $pop); unset($r->network_id); return $this->add(); } $data = []; $data['name'] = $r->name; $data['category']=$r->category; $data['gps_lat'] = ($r->gps_lat) ? $r->gps_lat : null; $data['gps_long'] = ($r->gps_long) ? $r->gps_long : null; $data['location'] = $r->location; $data['zip'] = $r->zip; $data['city'] = $r->city; $data['street'] = $r->street; $data['number'] = $r->number; $data['vlan_public'] = ($r->vlan_public) ? $r->vlan_public : null; $data['vlan_nat'] = ($r->vlan_nat) ? $r->vlan_nat : null; $data['vlan_ipv6'] = ($r->vlan_ipv6) ? $r->vlan_ipv6 : null; $data['state'] = ($r->state) ? $r->state : null; $data['folder_link'] = ($r->folder_link) ? $r->folder_link : null; $data['doku_date'] = ($r->doku_date) ? strtotime($r->doku_date) : null; $data['note'] = $r->note; // $data['edit_by'] = 1; if ($mode == "add") { // $data['create_by'] = 1; $pop = PopModel::create($data); } else { $pop->update($data); } $new_id = $pop->save(); if (!$new_id) { $this->layout()->setFlash("Fehler beim Speichern", "error"); if (isset($network)) $this->layout()->set("network", $network); $this->addAction(); } if ($r->network_id) { $oldPopnetworks = json_encode(PopNetworkModel::getbyPopid($new_id)); if ($oldPopnetworks != json_encode($r->network_id)) { PopNetworkModel::deletebyPopid($new_id); unset($data); $data = []; foreach ($r->network_id as $networkid) { $data['network_id'] = $networkid; $data['pop_id'] = $new_id; $popNetwork = PopNetworkModel::create($data); $popNetwork->save(); } } } if ($this->request->returnto) { $returnAction = "Index"; $returnVariables = array(); $returnAnker = ""; if (strpos($this->request->returnto, "-") !== false) { $urls = explode('-', $this->request->returnto); $urlCounter = 0; $returnUrl = ""; foreach ($urls as $url) { if ($urlCounter > 0) { $returnUrl .= "/"; } $returnUrl .= ucfirst($url); $urlCounter++; } $returnAction = ""; $returnVariables['id'] = $id; $this->returUrl = $returnUrl; } else { $this->returUrl = ucfirst($this->request->returnto); } } else { $returnAnker = "view=pops&net=" . $pop->network_id; } $this->layout()->setFlash("Pop erfolgreich gespeichert.", "success"); $this->redirect($this->returUrl, $returnAction, $returnVariables, $returnAnker); } protected function apiAction() { $do = $this->request->do; $data = []; switch ($do) { case "getPops": $return = $this->getPopsApi(); break; case "getCableDetails": return $this->getCableDetailsAction(); break; case "getFiberPath": return $this->getFiberPathAction(); break; case "getAllFiberPathsForHome": return $this->getAllFiberPathsForHomeAction(); break; case "saveCableFibers": return $this->saveCableFibersAction(); break; case "getCableFibersForEdit": return $this->getCableFibersForEditAction(); break; case "getNetworkMapData": return $this->getNetworkMapDataAction(); break; case "getSplicePlanForElement": return $this->getSplicePlanForElementAction(); break; default: $return = false; } if (!is_array($return) || !count($return)) { $data = ["status" => "error"]; $this->returnJson($data); } $data['status'] = "OK"; $data['result'] = $return; $this->returnJson($data); } private function getPopsApi() { $network_id = $this->request->network_id; if (!is_numeric($network_id) || $network_id < 1) { return false; } $network = new Network($network_id); if (!$network->id) { return false; } $pops = []; foreach ($network->pops as $pop) { $pops[$pop->id] = $pop->name; } return ["pops" => $pops]; } protected function deleteAction() { $id = $this->request->id; $pop = new Pop($id); if (!$pop->id || $pop->id != $id) { $this->layout()->setFlash("Datei nicht gefunden.", "error"); $this->redirect("Pop"); } $pop->delete(); $this->redirect("Pop"); } private function findLastEndpointInBranchPath($branchPath) { if (!$branchPath || isset($branchPath['error'])) { return null; } if (isset($branchPath['endpoint']) && $branchPath['endpoint']['type'] === 'customer') { return [ 'home_id' => $branchPath['endpoint']['home_id'] ?? null, 'location' => $branchPath['endpoint']['address'] ?? null ]; } if (isset($branchPath['target_fiber']) && !empty($branchPath['target_fiber']['home_id'])) { return [ 'home_id' => $branchPath['target_fiber']['home_id'], 'location' => $branchPath['target_fiber']['address'] ?? $branchPath['cable']['to_location'] ?? null ]; } if (isset($branchPath['next_branch'])) { $nextEndpoint = $this->findLastEndpointInBranchPath($branchPath['next_branch']); if ($nextEndpoint) { return $nextEndpoint; } } if (isset($branchPath['cable']['to_location'])) { return [ 'home_id' => null, 'location' => $branchPath['cable']['to_location'] ]; } return null; } private function geocodeAddress($address, $home_id = null) { if (empty($address)) { return null; } $db = FronkDB::singleton(); $address_escaped = $db->escape($address); $home_id_escaped = $db->escape($home_id); if (!empty($home_id)) { $sql = "SELECT gps_lat, gps_long FROM FiberPlanAddress WHERE tt_object_id = '$home_id_escaped' AND network_id = 90 AND gps_lat IS NOT NULL AND gps_long IS NOT NULL LIMIT 1"; $res = $db->query($sql); if ($db->num_rows($res) > 0) { $data = $db->fetch_object($res); return [ 'lat' => $data->gps_lat, 'lng' => $data->gps_long, 'source' => 'fiber_plan_address' ]; } } $sql = "SELECT gps_lat, gps_long FROM FiberPlanAddress WHERE address LIKE '%$address_escaped%' AND network_id = 90 AND gps_lat IS NOT NULL AND gps_long IS NOT NULL LIMIT 1"; $res = $db->query($sql); if ($db->num_rows($res) > 0) { $data = $db->fetch_object($res); return [ 'lat' => $data->gps_lat, 'lng' => $data->gps_long, 'source' => 'fiber_plan_address' ]; } $sql = "SELECT gps_lat, gps_long FROM Building WHERE code = '$home_id_escaped' LIMIT 1"; $res = $db->query($sql); if ($db->num_rows($res) == 0) { $sql = "SELECT gps_lat, gps_long FROM Building WHERE street LIKE '%$address_escaped%' LIMIT 1"; $res = $db->query($sql); } if ($db->num_rows($res)) { $data = $db->fetch_object($res); if ($data->gps_lat && $data->gps_long) { return [ 'lat' => $data->gps_lat, 'lng' => $data->gps_long, 'source' => 'building_db' ]; } } return null; } protected function getNetworkMapDataAction() { $network_id = $this->request->network_id ?? 90; $db = FronkDB::singleton(); $pops = []; $popQuery = " SELECT DISTINCT p.id, p.name, p.gps_lat, p.gps_long, p.zip, p.city, p.street, p.number FROM Pop p INNER JOIN PopNetwork pn ON p.id = pn.pop_id INNER JOIN Network n ON pn.network_id = n.id WHERE n.id = $network_id AND p.gps_lat IS NOT NULL AND p.gps_long IS NOT NULL "; $popRes = $db->query($popQuery); if ($db->num_rows($popRes)) { while ($popData = $db->fetch_object($popRes)) { $pops[] = [ 'id' => intval($popData->id), 'name' => $popData->name, 'lat' => floatval($popData->gps_lat), 'lng' => floatval($popData->gps_long), 'zip' => $popData->zip, 'city' => $popData->city, 'street' => $popData->street, 'number' => $popData->number, 'type' => 'pop' ]; } } $cables = []; $cableRes = $db->select( "FiberPlanCable", "id, description, fibers, diameter, state, coordinates, level, cable_type, status", "network_id=$network_id" ); if ($db->num_rows($cableRes)) { while ($cableData = $db->fetch_object($cableRes)) { if (!empty($cableData->coordinates)) { $coords_array = json_decode($cableData->coordinates, true); if (is_array($coords_array) && count($coords_array) > 0) { $convertedCoords = []; foreach ($coords_array as $coord) { if (isset($coord['gps_lat']) && isset($coord['gps_long'])) { $convertedCoords[] = [ 'lat' => floatval($coord['gps_lat']), 'lng' => floatval($coord['gps_long']) ]; } elseif (isset($coord['lat']) && isset($coord['lng'])) { $convertedCoords[] = [ 'lat' => floatval($coord['lat']), 'lng' => floatval($coord['lng']) ]; } } if (count($convertedCoords) >= 2) { $cables[] = [ 'id' => intval($cableData->id), 'name' => $cableData->description, 'coordinates' => $convertedCoords, 'fibers' => $cableData->fibers, 'diameter' => $cableData->diameter, 'state' => $cableData->state, 'level' => $cableData->level, 'cable_type' => $cableData->cable_type, 'status' => $cableData->status ]; } } } } } $distributors = []; $dispRes = $db->select( "FiberPlanDispatcher", "id, description, gps_lat, gps_long, object_type", "network_id=$network_id AND gps_lat IS NOT NULL AND gps_long IS NOT NULL" ); if ($db->num_rows($dispRes)) { while ($dispData = $db->fetch_object($dispRes)) { $type_names = [ 1 => 'Verteiler', 2 => 'Schacht', 3 => 'Greenfield', 4 => 'Abzweigpunkt' ]; $distributors[] = [ 'id' => intval($dispData->id), 'name' => $dispData->description, 'lat' => floatval($dispData->gps_lat), 'lng' => floatval($dispData->gps_long), 'type' => $type_names[$dispData->object_type] ?? 'Verteiler', 'object_type' => intval($dispData->object_type) ]; } } $customerConnections = []; $customerQuery = " SELECT MIN(f.id) as id, f.home_id, f.address, f.name, fa.gps_lat, fa.gps_long, GROUP_CONCAT(DISTINCT c.description ORDER BY c.description SEPARATOR ', ') as cable_name, GROUP_CONCAT(f.fiber_nr_cable ORDER BY f.fiber_nr_cable SEPARATOR ', ') as fiber_nrs, COUNT(f.id) as fiber_count, MAX(f.status) as status FROM FiberPlanFiber f INNER JOIN FiberPlanCable c ON f.cable_id = c.id LEFT JOIN FiberPlanAddress fa ON f.address COLLATE utf8mb4_unicode_ci = fa.address COLLATE utf8mb4_unicode_ci AND fa.network_id = $network_id WHERE c.network_id = $network_id AND f.home_id IS NOT NULL AND f.home_id != '' AND fa.gps_lat IS NOT NULL AND fa.gps_long IS NOT NULL GROUP BY f.home_id, f.address, f.name, fa.gps_lat, fa.gps_long "; $customerRes = $db->query($customerQuery); if ($db->num_rows($customerRes)) { while ($custData = $db->fetch_object($customerRes)) { $customerConnections[] = [ 'id' => intval($custData->id), 'home_id' => $custData->home_id, 'address' => $custData->address, 'name' => $custData->name, 'lat' => floatval($custData->gps_lat), 'lng' => floatval($custData->gps_long), 'cable_name' => $custData->cable_name, 'fiber_nrs' => $custData->fiber_nrs, 'fiber_count' => intval($custData->fiber_count), 'status' => $custData->status ]; } } $splices = []; $spliceQuery = " SELECT cable_id, branch_cable_nr, COUNT(*) as connection_count, branch_from_location FROM FiberPlanFiber WHERE branch_type='Abzweigkabel' AND branch_cable_nr IS NOT NULL GROUP BY cable_id, branch_cable_nr, branch_from_location "; $spliceRes = $db->query($spliceQuery); if ($db->num_rows($spliceRes)) { while ($spliceData = $db->fetch_object($spliceRes)) { $mainCableId = $spliceData->cable_id; $branchCableName = $spliceData->branch_cable_nr; $location = $spliceData->branch_from_location; $mainCableCheckRes = $db->select("FiberPlanCable", "id, description", "id=$mainCableId AND network_id=$network_id"); if (!$db->num_rows($mainCableCheckRes)) { continue; } $mainCableData = $db->fetch_object($mainCableCheckRes); $mainCableName = $mainCableData->description; $branchCableName_escaped = $db->escape($branchCableName); $branchCableRes = $db->select( "FiberPlanCable", "id, description", "description='$branchCableName_escaped' AND network_id=$network_id LIMIT 1" ); $branchCableId = null; if ($db->num_rows($branchCableRes)) { $branchCableData = $db->fetch_object($branchCableRes); $branchCableId = $branchCableData->id; } $connections = []; $connRes = $db->select( "FiberPlanFiber", "fiber_nr_cable, branch_fiber_nr, fiber_color, connector_nr", "cable_id=$mainCableId AND branch_cable_nr='$branchCableName_escaped'" ); if ($db->num_rows($connRes)) { while ($connData = $db->fetch_object($connRes)) { $connections[] = [ 'main_fiber' => $connData->fiber_nr_cable, 'branch_fiber' => $connData->branch_fiber_nr, 'main_color' => $connData->fiber_color, 'connector' => $connData->connector_nr ]; } } $splices[] = [ 'main_cable_id' => intval($mainCableId), 'main_cable_name' => $mainCableName, 'branch_cable_id' => $branchCableId, 'branch_cable_name' => $branchCableName, 'location' => $location, 'connection_count' => intval($spliceData->connection_count), 'connections' => $connections ]; } } $pipes = []; $pipeQuery = " SELECT DISTINCT p.id, p.description, p.coordinates, p.type_tmp, p.coat_color, p.layer, p.status, p.state FROM FiberPlanPipe p INNER JOIN FiberPlanPipeEndpoint pe ON p.id = pe.fiberPlanPipe_id LEFT JOIN FiberPlanDispatcher d ON pe.fiberPlanDispatcher_id = d.id LEFT JOIN FiberPlanAddress a ON pe.fiberPlanAddress_id = a.id LEFT JOIN PopNetwork pn ON pe.pop_id = pn.pop_id WHERE (d.network_id = $network_id) OR (a.network_id = $network_id) OR (pn.network_id = $network_id) "; $pipeRes = $db->query($pipeQuery); if ($db->num_rows($pipeRes)) { while ($pipeData = $db->fetch_object($pipeRes)) { if (!empty($pipeData->coordinates)) { $coords_array = json_decode($pipeData->coordinates, true); if (is_array($coords_array) && count($coords_array) > 0) { $convertedCoords = []; foreach ($coords_array as $coord) { if (isset($coord['gps_lat']) && isset($coord['gps_long'])) { $convertedCoords[] = [ 'lat' => floatval($coord['gps_lat']), 'lng' => floatval($coord['gps_long']) ]; } elseif (isset($coord['lat']) && isset($coord['lng'])) { $convertedCoords[] = [ 'lat' => floatval($coord['lat']), 'lng' => floatval($coord['lng']) ]; } } if (count($convertedCoords) >= 2) { $pipes[] = [ 'id' => intval($pipeData->id), 'name' => $pipeData->description, 'coordinates' => $convertedCoords, 'type' => $pipeData->type_tmp, 'color' => $pipeData->coat_color, 'layer' => $pipeData->layer, 'status' => $pipeData->status, 'state' => $pipeData->state ]; } } } } } return mfBaseController::returnJson(mfResponse::Ok([ 'pops' => $pops, 'cables' => $cables, 'pipes' => $pipes, 'distributors' => $distributors, 'splices' => $splices, 'customerConnections' => $customerConnections ])); } protected function getSplicePlanForElementAction() { $id = $this->request->id; if (!is_numeric($id)) { return mfBaseController::returnJson(mfResponse::BadRequest(['message' => 'Invalid ID'])); } $db = FronkDB::singleton(); $dispatcherRes = $db->select("FiberPlanDispatcher", "*", "id=$id"); if (!$db->num_rows($dispatcherRes)) { return mfBaseController::returnJson(mfResponse::NotFound(['message' => 'Verteiler nicht gefunden'])); } $dispatcher = $db->fetch_object($dispatcherRes); $dispatcherName = $dispatcher->description; $cableIds = []; $sql = "SELECT DISTINCT cable_id FROM FiberPlanCableStation WHERE station_type='dispatcher' AND station_id=$id"; $res = $db->query($sql); if ($db->num_rows($res)) { while ($row = $db->fetch_array($res)) { $cableIds[] = $row['cable_id']; } } $result = []; if (!empty($cableIds)) { $cableIdsStr = implode(',', $cableIds); $cableMap = []; $cableRes = $db->select("FiberPlanCable", "id, description", "id IN ($cableIdsStr)"); while ($c = $db->fetch_object($cableRes)) { $cableMap[$c->id] = $c->description; } $escapedName = $db->escape($dispatcherName); $sqlFibers = "SELECT * FROM FiberPlanFiber WHERE cable_id IN ($cableIdsStr) AND (branch_from_location = '$escapedName' OR location = '$escapedName')"; $fiberRes = $db->query($sqlFibers); $rawFibers = []; $targetCableNames = []; while ($fiber = $db->fetch_object($fiberRes)) { $rawFibers[] = $fiber; if ($fiber->branch_cable_nr) { $targetCableNames[$fiber->branch_cable_nr] = true; } } $targetColorMap = []; if (!empty($targetCableNames)) { $namesList = []; foreach (array_keys($targetCableNames) as $name) { $namesList[] = "'" . $db->escape($name) . "'"; } $namesStr = implode(',', $namesList); $targetCablesRes = $db->select("FiberPlanCable", "id, description", "description IN ($namesStr)"); $targetCableIds = []; $targetCableIdToName = []; while ($tc = $db->fetch_object($targetCablesRes)) { $targetCableIds[] = $tc->id; $targetCableIdToName[$tc->id] = $tc->description; } if (!empty($targetCableIds)) { $tcIdsStr = implode(',', $targetCableIds); $targetFibersRes = $db->select("FiberPlanFiber", "cable_id, fiber_nr_cable, fiber_color, fiber_color_hex", "cable_id IN ($tcIdsStr)"); while ($tf = $db->fetch_object($targetFibersRes)) { $cName = $targetCableIdToName[$tf->cable_id] ?? null; if ($cName) { $targetColorMap[$cName][$tf->fiber_nr_cable] = [ 'color' => $tf->fiber_color, 'hex' => $tf->fiber_color_hex ]; } } } } foreach ($rawFibers as $fiber) { $targetColorInfo = null; if ($fiber->branch_cable_nr && $fiber->branch_fiber_nr) { $targetColorInfo = $targetColorMap[$fiber->branch_cable_nr][$fiber->branch_fiber_nr] ?? null; } $result[] = [ 'cable_name' => $cableMap[$fiber->cable_id] ?? 'Unknown', 'fiber_nr' => $fiber->fiber_nr_cable, 'fiber_color' => $fiber->fiber_color, 'fiber_color_hex' => $fiber->fiber_color_hex, 'bundle_color' => $fiber->bundle_color, 'bundle_color_hex' => $fiber->bundle_color_hex, 'target_cable' => $fiber->branch_cable_nr, 'target_fiber' => $fiber->branch_fiber_nr, 'target_fiber_color' => $targetColorInfo['color'] ?? null, 'target_fiber_color_hex' => $targetColorInfo['hex'] ?? null, 'target_bundle_color' => $fiber->branch_bundle_color, 'target_bundle_color_hex' => $fiber->branch_bundle_color_hex, 'connector' => $fiber->connector_nr, 'description' => $fiber->comment, 'home_id' => $fiber->home_id, 'address' => $fiber->address ?? null, 'customer_cable_type' => $fiber->customer_cable_type ?? null, 'customer_cable_fiber_nr' => $fiber->customer_cable_fiber_nr ?? null, 'customer_connector_type' => $fiber->customer_connector_type ?? null, 'customer_cable_spec' => $fiber->customer_cable_spec ?? null, 'customer_fiber_range' => $fiber->customer_fiber_range ?? null, ]; } } return mfBaseController::returnJson(mfResponse::Ok([ 'dispatcher' => $dispatcher, 'connections' => $result ])); } }