No GLPI 11, "o plugin quebrou" quase nunca é bug do plugin: é a fundação que mudou embaixo dele. Na sustentação de ambientes de clientes o roteiro se repete - o cliente sobe o core novo, dois ou três plugins somem do menu, um derruba a tela com erro 500 e o php-errors.log fica irritantemente vazio. Este guia separa o que virou nativo do que de fato parou de funcionar, mostra o trecho de código que reprova um plugin no 11 e entrega o checklist que rodamos antes de agendar a janela de migração.
O que mudou no core - e por que isso derruba plugin
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 controllers e templates Twig. Plugin que montava a página "na unha" perde o cabeçalho, o menu, às vezes a tela inteira. - A aplicação é servida a partir de
public/. O roteamento é do Symfony. 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 sequer carrega. - O driver de banco recusa SQL cru. É a que mais dói. O
$DB->query()foi removido e o$DB->request()com string literal é bloqueado ("Building and executing raw queries is prohibited"). Qualquer consulta escondida quebra na primeira vez que aquele caminho executa. - Sinalizações do hook.php viraram forma canônica. Marcadores como
csrf_complianttêm tratamento mais rígido no core; declarado errado, o plugin pode não ser reconhecido como CSRF-compliant e apanhar 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 viraram core: migre o dado, não reinstale
Boa parte dos plugins mais populares não sumiu por incompatibilidade - sumiu porque a função entrou no core. Aqui o trabalho não é "achar a versão para o 11", é levar o dado para o recurso nativo:
- FormCreator - virou 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 - objetos personalizados agora são nativos. Reavalie cada tipo e mapeie para ativo ou dropdown do core.
- FusionInventory e dashboards de plugin - já eram substituídos desde o 10 pelo GLPI Agent e pelos dashboards nativos. No 11 não há motivo para insistir.
- Webhooks de saída - o core passou a notificar sistemas externos em eventos (abertura de chamado, mudança de status), cobrindo parte do que se resolvia com plugin.
Matriz de compatibilidade: por que cada caso cai
Antes de marcar a janela, na sustentação classificamos cada plugin instalado em uma destas linhas. O que decide não é o nome, é o motivo técnico:
| Plugin / caso | Motivo técnico | Ação antes de migrar |
|---|---|---|
| FormCreator | Função virou Formulários nativo (motor novo) | Inventariar e migrar os formulários que sustentam o atendimento - não migram sozinhos |
| GenericObject | Objetos personalizados agora nativos | Mapear cada tipo para ativo ou dropdown do core |
| FusionInventory | Substituído pelo GLPI Agent (desde o 10) | Migrar a coleta para o GLPI Agent antes |
| Plugin com SQL cru / saída procedural | Usa $DB->query() ou Html::header() - removidos/quebrados | Exige release portada; sem ela, desativar |
Plugin sem return type nos can*() | PHP 8.2 recusa a assinatura; o plugin não carrega | Aguardar versão do autor ou aposentar |
| Fields, DataInjection, PDF, Tag | Possuem 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 aposentar |
Diagnóstico: meça, não decida de memória
Não classifique de cabeça. Levante o estado real dos plugins e varra o fonte deles atrás dos padrões que o core 11 removeu:
# Estado real dos plugins (rode no GLPI 10 antes de migrar; somente 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;"
# Varra o fonte dos plugins atras dos padroes que o core 11 removeu
cd /var/www/glpi/plugins
grep -rln '$DB->query(' . --include='*.php' # driver de SQL cru removido no 11
grep -rln 'Html::header' . --include='*.php' # saida procedural pre-Twig
grep -rln 'includes.php' . --include='*.php' # include relativo fragil no roteamento Symfony
O erro comum é confiar só no selo do marketplace. Uma release marcada como "GLPI 11" ainda pode ter SQL cru num caminho pouco usado - que só estoura quando aquele relatório específico é aberto, semanas depois do go-live.
O código que reprova um plugin no 11
Se você mantém um plugin próprio ou precisa avaliar um de terceiro com o 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 direto no driver
$res = $DB->query("SELECT id FROM glpi_tickets WHERE status = 1");
// GLPI 11: $DB->query() foi REMOVIDO e request() com string crua e bloqueado.
// SELECT vira query builder por criterios:
$rows = $DB->request([
'SELECT' => 'id',
'FROM' => 'glpi_tickets',
'WHERE' => ['status' => 1],
]);
// DDL / SQL literal inevitavel (ALTER, SHOW INDEX): use 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 crase inline, que o GLPI 10 tolerava, agora precisa virar 'name AS filho' porque o query builder do 11 escapa as crases corretamente.
Como testar a compatibilidade antes da janela
Nunca descubra a incompatibilidade em produção. O roteiro que aplicamos em homologação:
- Clone de produção. Suba o 11 sobre uma cópia do banco real, não sobre uma base de exemplo. Plugin quebra com o seu dado, não com o dado limpo.
- Instale e ative pelo console.
php bin/console glpi:plugin:install <diretorio>eglpi:plugin:activate <diretorio>, como o usuário do web server. Se o plugin roda 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ó reclama quando a tela é realmente renderizada. - Olhe o log certo. A falha de carga não vira fatal do PHP - vira
glpi.ERROR: Error while loading plugin Xno log do GLPI. Quem só olha o php-errors.log conclui, errado, que "está tudo bem". - Resete o OPcache entre tentativas. Depois de trocar arquivos, 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 rodava a migração de schema dentro do plugin_init, um padrão comum e aparentemente inofensivo: o bloco só executa enquanto o schema_version gravado for menor que a versão do setup.php. Um bug latente ali ficou dormindo até o próximo bump - e quando finalmente rodou e lançou uma exceção, o GLPI 11 capturou 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 oscilando para o estado 4 (não ativado, que parece normal). Desde então a regra é dura: todo bump de 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 ele tenta de novo a cada request e entra em loop. É o tipo de detalhe que só quem opera GLPI de cliente todo dia carrega na memória muscular.
Devo migrar agora?
Se a sua matriz de plugins está verde (release portada para todos os essenciais) e você 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 vira de negócio: substituir pela função nativa, trocar de plugin ou adiar. O que não dá é migrar no escuro e descobrir a incompatibilidade com o ambiente no ar.
Se a sua equipe não tem janela para ensaiar a migração e classificar cada plugin com calma, a NexTool conduz o upgrade do seu GLPI com inventário de plugins, homologação sobre clone e rollback ensaiado. Fale com a gente sobre suporte e sustentação de GLPI.
Revisado pela equipe NexTool Solutions.