diff --git a/application/controllers/OrgRoleController.php b/application/controllers/OrgRoleController.php index dd68f06..ce87407 100644 --- a/application/controllers/OrgRoleController.php +++ b/application/controllers/OrgRoleController.php @@ -316,11 +316,22 @@ class OrgRoleController extends BaseController $roots[] = $r; } } - $attach = function (array $node) use (&$attach, $childrenByParent) { - $kids = $childrenByParent[(int) $node['id']] ?? []; - $node['children'] = array_map($attach, $kids); + // Guardia anti-ciclo: se parent_role_id formasse un ciclo (dato legacy/corrotto), + // la ricorsione andrebbe in loop infinito → hang del backend e "blocco" della pagina. + // Portiamo la catena di antenati e non ridiscendiamo su un id già visto. + $attach = function (array $node, array $ancestry) use (&$attach, $childrenByParent) { + $id = (int) $node['id']; + $ancestry[$id] = true; + $children = []; + foreach ($childrenByParent[$id] ?? [] as $kid) { + if (isset($ancestry[(int) $kid['id']])) { + continue; // ciclo: interrompi questo ramo invece di ricorrere all'infinito + } + $children[] = $attach($kid, $ancestry); + } + $node['children'] = $children; return $node; }; - return array_map($attach, $roots); + return array_map(static fn(array $r) => $attach($r, []), $roots); } } diff --git a/public/js/organigramma.js b/public/js/organigramma.js index 8178e00..770e014 100644 --- a/public/js/organigramma.js +++ b/public/js/organigramma.js @@ -61,10 +61,15 @@ function orgRender() { el('org-stat-vacant').textContent = vacant; stats.style.display = 'flex'; - tree.innerHTML = ORG.tree.map(orgNodeHtml).join(''); + tree.innerHTML = ORG.tree.map(n => orgNodeHtml(n, new Set())).join(''); } -function orgNodeHtml(node) { +function orgNodeHtml(node, seen) { + // Guardia anti-ciclo: se un id ricompare nella catena il render si fermerebbe in loop + // infinito (il "blocco del sito" segnalato). Rompiamo il ciclo invece di ricorrere. + seen = seen || new Set(); + if (!node || seen.has(node.id)) return ''; + seen.add(node.id); const gov = node.is_governance_body; const holder = node.holder_name ? '