No GLPI 11, "o plugin deixou de funcionar" quase nunca é um bug do plugin: é a fundação que mudou por baixo dele. Na sustentação de ambientes de clientes o guião repete-se - o cliente sobe o core novo, dois ou três plugins desaparecem do menu, um deita a página abaixo com erro 500 e o php-errors.log fica irritantemente vazio. Este guia separa o que passou a ser nativo do que de facto deixou de funcionar, mostra o excerto de código que reprova um plugin no 11 e entrega a checklist que corremos antes de agendar a janela de migração.
O que mudou no core - e porque é que isso deita os plugins abaixo
O 11 não é um tema novo por cima do 10. É troca de motor. Cada mudança abaixo invalida um padrão que os plugins de GLPI 10 usavam sem cerimónia:
- Frontend em Symfony + Twig. O antigo fluxo procedural (
Html::header()e depoisechode HTML) deu lugar a controladores e templates Twig. Um plugin que montava a página "à mão" perde o cabeçalho, o menu, às vezes o ecrã inteiro. - A aplicação é servida a partir de
public/. O encaminhamento é do Symfony agora. Os includes relativos do tipoinclude("../../../inc/includes.php")dependem do diretório de trabalho e deixam de resolver. - PHP 8.2 no mínimo, com assinaturas estritas. Um método herdado precisa do return type compatível. Um
canCreate()sem: boollança "Declaration must be compatible" e o plugin nem sequer carrega. - O controlador da base de dados recusa SQL cru. É o que mais custa. O
$DB->query()foi removido e o$DB->request()com string literal está bloqueado ("Building and executing raw queries is prohibited"). Qualquer consulta escondida quebra na primeira vez que aquele caminho é executado. - As sinalizações do hook.php passaram a forma canónica. Marcadores como
csrf_compliantsão tratados de forma mais rígida no core; mal declarado, o plugin pode não ser reconhecido como CSRF-compliant e apanhar um 403 em POST.
Ou seja: "compatível com o 11" não é sorte, é o autor ter portado esses padrões. Quem não portou quebra - e costuma quebrar em silêncio.
Plugins que passaram a core: migre o dado, não reinstale
Boa parte dos plugins mais populares não desapareceu por incompatibilidade - desapareceu porque a função entrou no core. Aqui o trabalho não é "encontrar a versão para o 11", é levar o dado para o recurso nativo:
- FormCreator - passou a ser o módulo de Formulários nativo, um motor novo. Não há importador transparente; existe apenas uma ferramenta de transição, e os formulários não se mudam sozinhos.
- GenericObject - os objetos personalizados agora são nativos. Reavalie cada tipo e mapeie para um ativo ou dropdown do core.
- FusionInventory e dashboards de plugin - já eram substituídos desde o 10 pelo GLPI Agent e pelas dashboards nativas. No 11 não há motivo para insistir.
- Webhooks de saída - o core passou a notificar sistemas externos em eventos (abertura de ticket, mudança de estado), cobrindo parte do que se resolvia com plugin.
Matriz de compatibilidade: porque é que cada caso cai
Antes de marcar a janela, na sustentação classificamos cada plugin instalado numa destas linhas. O que decide não é o nome, é o motivo técnico:
| Plugin / caso | Motivo técnico | Ação antes de migrar |
|---|---|---|
| FormCreator | A função passou a Formulários nativo (motor novo) | Inventariar e migrar os formulários que sustentam o service desk - não migram sozinhos |
| GenericObject | Objetos personalizados agora nativos | Mapear cada tipo para um ativo ou dropdown do core |
| FusionInventory | Substituído pelo GLPI Agent (desde o 10) | Migrar a recolha para o GLPI Agent antes |
| Plugin com SQL cru / saída procedural | Usa $DB->query() ou Html::header() - removidos/partidos | Exige release portada; sem ela, desativar |
Plugin sem return type nos can*() | PHP 8.2 recusa a assinatura; o plugin não carrega | Aguardar a versão do autor ou reformar |
| Fields, DataInjection, PDF, Tag | Têm release para o 11 | Atualizar depois do core, um a um, validando entre cada |
| NexTool | Compatível com 10 e 11 (mesmo código portado) | Atualizar para a versão do 11 |
| Plugin sem release desde 2023 | Provavelmente não portado | Decisão de negócio: substituir ou reformar |
Diagnóstico: meça, não decida de memória
Não classifique de cabeça. Levante o estado real dos plugins e analise o código deles à procura dos padrões que o core 11 removeu:
# Estado real dos plugins (execute no GLPI 10 antes de migrar; apenas leitura)
# state: 0=novo 1=ativo 2=nao instalado 3=a configurar
# 4=nao ativado 5=a limpar 6=nao atualizado
mysql -u glpi -p glpi -e \
"SELECT name, directory, version, state FROM glpi_plugins ORDER BY state, name;"
# Analise o codigo dos plugins a procura dos padroes que o core 11 removeu
cd /var/www/glpi/plugins
grep -rln '$DB->query(' . --include='*.php' # controlador de SQL cru removido no 11
grep -rln 'Html::header' . --include='*.php' # saida procedural, anterior ao Twig
grep -rln 'includes.php' . --include='*.php' # include relativo fragil no encaminhamento Symfony
O erro comum é confiar só no selo do marketplace. Uma release marcada como "GLPI 11" ainda pode esconder SQL cru num caminho pouco usado - que só rebenta quando aquele relatório específico é aberto, semanas depois do go-live.
O código que reprova um plugin no 11
Se mantém um plugin próprio, ou precisa de avaliar um de terceiros com o código-fonte em mãos, estes são os três padrões que mais aparecem quando portamos código de 10 para 11:
// GLPI 10 (funcionava): SQL cru diretamente no controlador
$res = $DB->query("SELECT id FROM glpi_tickets WHERE status = 1");
// GLPI 11: $DB->query() foi REMOVIDO e request() com string crua esta bloqueado.
// O SELECT passa a query builder por criterios:
$rows = $DB->request([
'SELECT' => 'id',
'FROM' => 'glpi_tickets',
'WHERE' => ['status' => 1],
]);
// DDL / SQL literal inevitavel (ALTER, SHOW INDEX): utilize doQuery()
$DB->doQuery("ALTER TABLE glpi_plugin_x ADD COLUMN ativo TINYINT DEFAULT 0");
// PHP 8.2+: metodo herdado exige return type; sem ": bool" o plugin nem carrega
public static function canCreate(): bool
{
return Session::haveRight('plugin_x', CREATE);
}
Repare que o alias de coluna também mudou: o velho truque com plica invertida inline, que o GLPI 10 tolerava, agora tem de passar a 'name AS filho', porque o query builder do 11 faz o escape das plicas invertidas corretamente.
Como testar a compatibilidade antes da janela
Nunca descubra a incompatibilidade em produção. A rotina que aplicamos em homologação:
- Clone de produção. Suba o 11 sobre uma cópia da base de dados real, não sobre uma base de exemplo. Um plugin quebra com os seus dados, não com dados limpos.
- Instale e ative pela consola.
php bin/console glpi:plugin:install <diretorio>eglpi:plugin:activate <diretorio>, como o utilizador do servidor web. Se o plugin corre uma migração no install/init, é aqui que ela dispara. - Abra cada página
front/do plugin. Não basta ativar sem erro; o motor Twig só se queixa quando o ecrã é realmente renderizado. - Olhe para o ficheiro de log certo. A falha de carregamento não vira fatal do PHP - vira
glpi.ERROR: Error while loading plugin Xno log do GLPI. Quem só olha para o php-errors.log conclui, erradamente, que "está tudo bem". - Reponha o OPcache entre tentativas. Depois de trocar ficheiros, o php-fpm ainda serve o bytecode antigo; recarregue o processo (por exemplo,
kill -USR2no master do php-fpm), não só o Apache.
O que a sustentação nos ensinou
O incidente mais traiçoeiro que vimos não apareceu na migração em si - apareceu meses depois, num simples bump de versão de um plugin administrativo. Ele corria a migração de schema dentro do plugin_init, um padrão comum e aparentemente inofensivo: o bloco só é executado enquanto o schema_version gravado for menor do que a versão do setup.php. Um bug latente ali ficou a dormir até ao bump seguinte - e quando finalmente correu e lançou uma exceção, o GLPI 11 capturou-a no Plugin::load e desativou o plugin sozinho. O sintoma para o cliente foi aquele "ativa e desativa sem erro visível", com o plugin a oscilar para o estado 4 (não ativado, que parece normal). Desde então a regra é dura: todo o bump de um plugin com migração-no-init exige um smoke test de ativação depois do bump, e o bloco de migração vai sempre dentro de try/catch, com o schema_version gravado FORA do try - senão tenta de novo a cada pedido e entra em ciclo. É o tipo de detalhe que só quem opera GLPI de cliente todos os dias traz na memória muscular.
Devo migrar agora?
Se a sua matriz de plugins está verde (release portada para todos os essenciais) e tem homologação com clone de produção, sim - o 11 é mais moderno, seguro e rápido. Se depende de um plugin sem versão para o 11, a decisão passa a ser de negócio: substituir pela função nativa, trocar de plugin ou adiar. O que não dá é migrar às cegas e descobrir a incompatibilidade com o ambiente no ar.
Se a sua equipa não tem janela para ensaiar a migração e classificar cada plugin com calma, a NexTool conduz a atualização do seu GLPI com inventário de plugins, homologação sobre clone e rollback ensaiado. Fale connosco sobre suporte e sustentação de GLPI.
Revisto pela equipa NexTool Solutions.