GLPI 11: Cosa È Cambiato e Quali Plugin Si Sono Rotti

Perché i plugin si rompono su GLPI 11: i cambiamenti di architettura (Symfony/Twig, public/, PHP 8.2, driver senza SQL grezzo), la matrice di compatibilità e la checklist di collaudo che eseguiamo prima di migrare.

Su GLPI 11, "il plugin si è rotto" non è quasi mai un bug del plugin: è la fondazione che è cambiata sotto di esso. Nella manutenzione di ambienti clienti il copione si ripete - il cliente porta su il nuovo core, due o tre plugin spariscono dal menu, uno fa cadere lo schermo con errore 500 e il php-errors.log resta irritantemente vuoto. Questa guida separa ciò che è diventato nativo da ciò che ha davvero smesso di funzionare, mostra il frammento di codice che boccia un plugin su 11 e consegna la checklist che eseguiamo prima di pianificare la finestra di migrazione.

Cosa è cambiato nel core - e perché fa cadere i plugin

11 non è una nuova veste sopra 10. È un cambio di motore. Ogni cambiamento qui sotto invalida uno schema che i plugin di GLPI 10 usavano senza pensarci:

  • Frontend in Symfony + Twig. Il vecchio flusso procedurale (Html::header() e poi echo di HTML) ha lasciato il posto a controller e template Twig. Un plugin che costruiva la pagina "a mano" perde l'intestazione, il menu, a volte l'intero schermo.
  • L'applicazione viene servita da public/. Il routing ora è di Symfony. Gli include relativi del tipo include("../../../inc/includes.php") dipendono dalla directory di lavoro e smettono di risolversi.
  • PHP 8.2 minimo, con firme rigide. Un metodo ereditato ha bisogno del return type compatibile. Un canCreate() senza : bool lancia "Declaration must be compatible" e il plugin non si carica nemmeno.
  • Il driver del database rifiuta l'SQL grezzo. Questo è quello che fa più male. $DB->query() è stato rimosso e $DB->request() con stringa letterale è bloccato ("Building and executing raw queries is prohibited"). Qualsiasi query nascosta si rompe la prima volta che quel percorso viene eseguito.
  • Le flag di hook.php sono diventate canoniche. Marcatori come csrf_compliant sono trattati più rigidamente dal core; dichiarato male, il plugin può non essere riconosciuto come CSRF-compliant e prendere un 403 in POST.

In breve: "compatibile con 11" non è fortuna, è l'autore che ha portato questi schemi. Chi non ha portato si rompe - e di solito si rompe in silenzio.

Plugin diventati core: migra il dato, non reinstallare

Buona parte dei plugin più popolari non è sparita per incompatibilità - è sparita perché la funzione è entrata nel core. Qui il lavoro non è "trovare la versione 11", è portare il dato verso la funzionalità nativa:

  • FormCreator - è diventato il modulo Moduli nativo, un nuovo motore. Non c'è un importatore trasparente; esiste solo uno strumento di transizione, e i moduli non si spostano da soli.
  • GenericObject - gli oggetti personalizzati ora sono nativi. Rivaluta ogni tipo e mappalo su un asset o un dropdown del core.
  • FusionInventory e dashboard di plugin - già sostituiti da 10 dal GLPI Agent e dalle dashboard native. Su 11 non c'è motivo di insistere.
  • Webhook in uscita - il core ora notifica i sistemi esterni sugli eventi (apertura ticket, cambio di stato), coprendo parte di ciò che si risolveva con un plugin.

Matrice di compatibilità: perché cade ogni caso

Prima di prenotare la finestra, in manutenzione classifichiamo ogni plugin installato in una di queste righe. A decidere non è il nome, è il motivo tecnico:

Plugin / casoMotivo tecnicoAzione prima di migrare
FormCreatorLa funzione è diventata Moduli nativo (nuovo motore)Inventariare e migrare i moduli che reggono il service desk - non migrano da soli
GenericObjectOggetti personalizzati ora nativiMappare ogni tipo su un asset o dropdown del core
FusionInventorySostituito dal GLPI Agent (da 10)Spostare prima la raccolta sul GLPI Agent
Plugin con SQL grezzo / output proceduraleUsa $DB->query() o Html::header() - rimossi/rottiRichiede una release portata; senza, disattivare
Plugin senza return type nei can*()PHP 8.2 rifiuta la firma; il plugin non si caricaAttendere la versione dell'autore o ritirarlo
Fields, DataInjection, PDF, TagHanno una release per 11Aggiornare dopo il core, uno a uno, validando tra ciascuno
NexToolCompatibile con 10 e 11 (stesso codice portato)Aggiornare alla versione 11
Plugin senza release dal 2023Probabilmente non portatoDecisione di business: sostituire o ritirare

Diagnosi: misura, non decidere a memoria

Non classificare a mente. Rileva lo stato reale dei plugin e scansiona il loro codice cercando gli schemi che il core 11 ha rimosso:

# Stato reale dei plugin (esegui su GLPI 10 prima di migrare; sola lettura)
# state: 0=nuovo  1=attivo  2=non installato  3=da configurare
#        4=non attivato  5=da pulire  6=non aggiornato
mysql -u glpi -p glpi -e \
  "SELECT name, directory, version, state FROM glpi_plugins ORDER BY state, name;"

# Scansiona il codice dei plugin cercando i pattern che il core 11 ha rimosso
cd /var/www/glpi/plugins
grep -rln '$DB->query('   . --include='*.php'   # driver SQL grezzo rimosso in 11
grep -rln 'Html::header'  . --include='*.php'   # output procedurale, pre-Twig
grep -rln 'includes.php'  . --include='*.php'   # include relativo fragile con il routing Symfony

L'errore comune è fidarsi solo del bollino del marketplace. Una release taggata "GLPI 11" può ancora nascondere SQL grezzo su un percorso poco usato - che esplode solo quando quel report specifico viene aperto, settimane dopo il go-live.

Il codice che boccia un plugin su 11

Se mantieni un tuo plugin, o devi valutarne uno di terzi con il sorgente in mano, questi sono i tre schemi che compaiono più spesso quando portiamo codice da 10 a 11:

// GLPI 10 (funzionava): SQL grezzo direttamente nel driver
$res = $DB->query("SELECT id FROM glpi_tickets WHERE status = 1");

// GLPI 11: $DB->query() e stato RIMOSSO e request() con stringa grezza e bloccato.
// La SELECT diventa un query builder per criteri:
$rows = $DB->request([
    'SELECT' => 'id',
    'FROM'   => 'glpi_tickets',
    'WHERE'  => ['status' => 1],
]);

// DDL / SQL letterale inevitabile (ALTER, SHOW INDEX): usa doQuery()
$DB->doQuery("ALTER TABLE glpi_plugin_x ADD COLUMN attivo TINYINT DEFAULT 0");

// PHP 8.2+: un metodo ereditato richiede il return type; senza ": bool" il plugin non si carica
public static function canCreate(): bool
{
    return Session::haveRight('plugin_x', CREATE);
}

Nota che anche l'alias di colonna è cambiato: il vecchio trucco del backtick inline che GLPI 10 tollerava ora deve diventare 'name AS figlio', perché il query builder di 11 fa l'escape dei backtick correttamente.

Come testare la compatibilità prima della finestra

Non scoprire mai l'incompatibilità in produzione. La routine che applichiamo in collaudo:

  1. Clone di produzione. Porta su 11 su una copia del database reale, non su una base di esempio. Un plugin si rompe con i tuoi dati, non con dati puliti.
  2. Installa e attiva da console. php bin/console glpi:plugin:install <directory> e glpi:plugin:activate <directory>, come utente del web server. Se il plugin esegue una migrazione all'install/init, è qui che parte.
  3. Apri ogni pagina front/ del plugin. Attivare senza errori non basta; il motore Twig si lamenta solo quando lo schermo viene realmente renderizzato.
  4. Guarda il log giusto. Il fallimento di caricamento non diventa un fatal di PHP - diventa glpi.ERROR: Error while loading plugin X nel log di GLPI. Chi guarda solo il php-errors.log conclude, a torto, che "va tutto bene".
  5. Resetta l'OPcache tra i tentativi. Dopo aver sostituito i file, php-fpm serve ancora il vecchio bytecode; ricarica il processo (ad esempio, kill -USR2 sul master php-fpm), non solo Apache.

Cosa ci ha insegnato la manutenzione

L'incidente più insidioso che abbiamo visto non è comparso nella migrazione in sé - è comparso mesi dopo, su un semplice bump di versione di un plugin amministrativo. Eseguiva la sua migrazione di schema dentro plugin_init, uno schema comune e apparentemente innocuo: il blocco viene eseguito solo finché lo schema_version salvato è inferiore alla versione di setup.php. Un bug latente lì è rimasto dormiente fino al bump successivo - e quando finalmente è partito e ha lanciato un'eccezione, GLPI 11 l'ha catturata in Plugin::load e ha disattivato il plugin da solo. Il sintomo per il cliente era quel "si attiva e si disattiva senza errore visibile", con il plugin che oscillava allo stato 4 (non attivato, che sembra normale). Da allora la regola è dura: ogni bump di un plugin con migrazione-nell'init richiede uno smoke test di attivazione dopo il bump, e il blocco di migrazione va sempre in try/catch, con lo schema_version scritto FUORI dal try - altrimenti riprova a ogni richiesta ed entra in loop. È il tipo di dettaglio che solo chi opera GLPI di cliente ogni giorno porta nella memoria muscolare.

Devo migrare adesso?

Se la tua matrice di plugin è verde (release portata per tutti gli essenziali) e hai un collaudo con clone di produzione, sì - 11 è più moderno, sicuro e veloce. Se dipendi da un plugin senza versione 11, la decisione diventa di business: sostituirlo con la funzione nativa, cambiare plugin o rimandare. Ciò che non si può fare è migrare al buio e scoprire l'incompatibilità con l'ambiente in linea.

Se il tuo team non ha una finestra per provare la migrazione e classificare ogni plugin con calma, NexTool guida l'upgrade del tuo GLPI con inventario dei plugin, collaudo su clone e rollback provato. Parla con noi di supporto e manutenzione GLPI.


Revisionato dal team NexTool Solutions.

Domande Frequenti

Perché è cambiata la fondazione: frontend in Symfony/Twig, applicazione servita da public/, PHP 8.2+ con return type rigidi e un driver che rifiuta l'SQL grezzo ($DB->query() è stato rimosso). Un plugin di GLPI 10 che si appoggia a uno di questi schemi, caricato sul nuovo core, dà errore 500 o viene disattivato al caricamento.

Non fidarti solo del bollino del marketplace. Testa in collaudo su un clone del database di produzione: installa e attiva da console, apri ogni pagina front/ del plugin e verifica il glpi.ERROR, non solo il php-errors.log. Una release può nascondere SQL grezzo su un percorso poco usato che esplode solo settimane dopo il go-live.

Non come plugin di creazione. La funzione è diventata il modulo Moduli nativo, un nuovo motore senza importatore trasparente. Esiste solo uno strumento di transizione per i vecchi moduli, e non si spostano da soli. Inventaria quanti moduli hai prima di pianificare la migrazione.

Il fallimento di caricamento del plugin non diventa un fatal di PHP. GLPI cattura l'eccezione in Plugin::load e la registra come 'glpi.ERROR: Error while loading plugin X' nel log di GLPI. Guarda il log di GLPI, non solo quello di PHP - è l'errore più comune quando si diagnostica un plugin che 'è sparito dal menu'.

Probabilmente esegue la sua migrazione di schema in plugin_init, che viene eseguita solo finché lo schema_version salvato è inferiore alla versione di setup.php. Un bug latente lì dorme fino al bump successivo; quando parte e lancia un'eccezione, GLPI 11 disattiva il plugin. Avvolgi la migrazione in try/catch e scrivi lo schema_version fuori dal try, altrimenti si ripete a ogni richiesta.

L'OPcache di php-fpm serve ancora il vecchio bytecode compilato in memoria. Ricarica il processo php-fpm (ad esempio, kill -USR2 sul master php-fpm), non solo Apache. È la causa più comune di un 'fix che non prende' subito dopo aver sostituito i file del plugin.

Hai bisogno di aiuto?