[FEAT] #384 p.2.2/3 — colonne multi-valore + link attivi bidirezionali Policy<->Misure e Requisiti

Misure e Requisiti: colonna Policy (default) mostra tutte le policy collegate al
requisito come codici Policy.NN cliccabili -> aprono la policy (policies.html?policy=ID).
Policy: colonna Requisito NIS2 mostra tutti i requisiti collegati (codifica MISURA+
REQUISITO, es. 'DE.CM-01 comma 1.') come link -> evidenziano il requisito
(misure-requisiti.html?requisito=ID). Backend: FrameworkController::catalog espone
policies[] per requisito e PolicyController::list espone requisiti[] per policy
(org-scoped, tabella requisito_policy mig.059, try/catch con degrado al dato di default).
Solo lettura/visualizzazione: nessuna modifica dati, nessuna migrazione.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile
2026-06-18 19:25:16 +02:00
co-authored by Claude Opus 4.8
parent 02f3e69227
commit cb238e8380
5 changed files with 114 additions and 5 deletions
@@ -79,6 +79,32 @@ class FrameworkController extends BaseController
}
}
// Ticket #384 p.2.2/p.3 — policy d'organizzazione collegate a ciascun requisito
// (M:N org-scoped, tabella requisito_policy mig.059). try/catch: l'eventuale assenza
// della tabella NON deve rompere il catalogo (degrada al solo proc_code di default).
$policiesByReq = [];
if ($orgId) {
try {
foreach (Database::fetchAll(
'SELECT rp.requisito_id, p.id AS policy_id, p.title, p.proc_code, p.status
FROM requisito_policy rp
JOIN policies p ON p.id = rp.policy_id
WHERE rp.organization_id = ?
ORDER BY (p.proc_code IS NULL), p.proc_code, p.title',
[$orgId]
) as $rp) {
$policiesByReq[(int) $rp['requisito_id']][] = [
'id' => (int) $rp['policy_id'],
'proc_code' => $rp['proc_code'],
'title' => $rp['title'],
'status' => $rp['status'],
];
}
} catch (\Throwable $e) {
error_log('[FrameworkController] requisito_policy lookup (org ' . $orgId . '): ' . $e->getMessage());
}
}
$ambiti = Database::fetchAll('SELECT nist_code, nist_descr FROM cfg_nis2_ambiti ORDER BY nist_code ASC');
$misure = Database::fetchAll(
@@ -108,6 +134,7 @@ class FrameworkController extends BaseController
'requisito_descr' => $q['requisito_descr'],
'proc_code' => $q['proc_code'],
'proc_descr' => $q['proc_descr'],
'policies' => $policiesByReq[$rid] ?? [], // #384 p.2.2/p.3 (multi-valore)
'risk_code' => $q['risk_code'],
'risk_descr' => $q['risk_descr'],
'applies_important' => (int) $q['applies_important'],