Files
thetool/application/Pop/PopController.php
Daniel Spitzer bb07cd1fb2 Pop Feature Updates
* Vorbereitung für erweiterte Faserdarstellungen
* Pop Map Übersicht
* Leere Pop Kategorien werden nun als Unbekannt dargestellt
2025-12-27 19:31:08 +01:00

1902 lines
76 KiB
PHP

<?php
class PopController extends mfBaseController
{
private $returUrl = "Network";
protected function init()
{
$this->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,
"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("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['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
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),
'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
];
}
}
return mfBaseController::returnJson(mfResponse::Ok([
'pops' => $pops,
'cables' => $cables,
'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
]));
}
}