В GLPI 11 «плагин сломался» почти никогда не означает баг самого плагина: под ним изменился фундамент. При сопровождении клиентских сред сценарий повторяется: клиент ставит новое ядро, два-три плагина пропадают из меню, один валит экран с ошибкой 500, а php-errors.log остаётся раздражающе пустым. Это руководство отделяет то, что стало встроенным, от того, что действительно перестало работать, показывает фрагмент кода, из-за которого плагин не проходит в 11, и даёт чек-лист, который мы проходим перед тем, как назначить окно миграции.
Что изменилось в ядре и почему это ломает плагины
11 — это не новая тема поверх 10. Это замена движка. Каждое изменение ниже отменяет паттерн, которым плагины для GLPI 10 пользовались без лишних церемоний:
- Фронтенд на Symfony + Twig. Старый процедурный поток (
Html::header(), а затемechoHTML) уступил место контроллерам и шаблонам Twig. Плагин, который собирал страницу «вручную», теряет шапку, меню, а иногда и весь экран. - Приложение отдаётся из
public/. Маршрутизацией занимается Symfony. Относительные include видаinclude("../../../inc/includes.php")зависят от рабочего каталога и перестают разрешаться. - Минимум PHP 8.2 со строгими сигнатурами. Унаследованному методу нужен совместимый return type.
canCreate()без: boolвыбрасывает «Declaration must be compatible», и плагин даже не загружается. - Драйвер БД отклоняет сырой SQL. Это самое болезненное.
$DB->query()удалён, а$DB->request()со строковым литералом блокируется («Building and executing raw queries is prohibited»). Любой спрятанный запрос ломается при первом выполнении этого пути. - Флаги в hook.php приобрели каноническую форму. Маркеры вроде
csrf_compliantобрабатываются ядром строже; если объявить их неправильно, плагин может не распознаваться как CSRF-compliant и получать 403 на POST.
Иначе говоря, «совместим с 11» — это не удача, а то, что автор портировал эти паттерны. Кто не портировал, тот ломается, и обычно ломается молча.
Плагины, ставшие частью ядра: переносите данные, а не переустанавливайте
Многие из самых популярных плагинов исчезли не из-за несовместимости, а потому что их функция вошла в ядро. Здесь задача не «найти версию для 11», а перенести данные во встроенный механизм:
- FormCreator — стал встроенным модулем форм, новым движком. Прозрачного импорта нет; есть только инструмент перехода, и формы сами не переезжают.
- GenericObject — пользовательские объекты теперь встроены. Пересмотрите каждый тип и сопоставьте его с активом или выпадающим списком ядра.
- FusionInventory и дашборды плагинов — ещё с 10 их заменили GLPI Agent и встроенные дашборды. В 11 нет причин за них держаться.
- Исходящие вебхуки — ядро теперь уведомляет внешние системы о событиях (создание заявки, смена статуса), покрывая часть того, что решалось плагином.
Матрица совместимости: почему падает каждый случай
Перед назначением окна мы в рамках сопровождения относим каждый установленный плагин к одной из этих строк. Решает не название, а техническая причина:
| Плагин / случай | Техническая причина | Действие до миграции |
|---|---|---|
| FormCreator | Функция стала встроенными формами (новый движок) | Инвентаризировать и перенести формы, на которых держится обслуживание, — сами они не переносятся |
| GenericObject | Пользовательские объекты теперь встроены | Сопоставить каждый тип с активом или выпадающим списком ядра |
| FusionInventory | Заменён GLPI Agent (с версии 10) | Заранее перевести сбор данных на GLPI Agent |
| Плагин с сырым SQL / процедурным выводом | Использует $DB->query() или Html::header() — удалены/сломаны | Нужен портированный релиз; без него — отключить |
Плагин без return type в can*() | PHP 8.2 отвергает сигнатуру; плагин не загружается | Дождаться версии от автора или вывести из эксплуатации |
| Fields, DataInjection, PDF, Tag | Есть релиз для 11 | Обновлять после ядра, по одному, проверяя после каждого |
| NexTool | Совместим с 10 и 11 (один и тот же портированный код) | Обновить до версии для 11 |
| Плагин без релизов с 2023 года | Скорее всего, не портирован | Бизнес-решение: заменить или вывести из эксплуатации |
Диагностика: измеряйте, а не решайте по памяти
Не классифицируйте на глаз. Соберите реальное состояние плагинов и просканируйте их исходники на паттерны, которые ядро 11 удалило:
# 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
Типичная ошибка — доверять только отметке в маркетплейсе. Релиз с пометкой «GLPI 11» всё ещё может содержать сырой SQL в редко используемом пути, который выстрелит только тогда, когда откроют именно этот отчёт, через несколько недель после go-live.
Код, из-за которого плагин не проходит в 11
Если вы поддерживаете собственный плагин или должны оценить сторонний, имея исходники на руках, вот три паттерна, которые чаще всего встречаются при портировании кода с 10 на 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);
}
Обратите внимание, что изменился и алиас столбца: старый трюк с inline-обратными кавычками, который GLPI 10 терпел, теперь нужно заменить на 'name AS filho', потому что query builder в 11 корректно экранирует обратные кавычки.
Как проверить совместимость до окна
Никогда не обнаруживайте несовместимость в продакшене. Сценарий, который мы применяем на тестовом стенде:
- Клон продакшена. Поднимайте 11 на копии реальной базы, а не на демонстрационной. Плагин ломается на ваших данных, а не на чистых.
- Устанавливайте и активируйте через консоль.
php bin/console glpi:plugin:install <diretorio>иglpi:plugin:activate <diretorio>от имени пользователя веб-сервера. Если плагин выполняет миграцию при install/init, она запустится именно здесь. - Откройте каждую страницу
front/плагина. Недостаточно активировать без ошибок; движок Twig жалуется только тогда, когда экран действительно рендерится. - Смотрите правильный лог. Сбой загрузки не становится фатальной ошибкой PHP — он превращается в
glpi.ERROR: Error while loading plugin Xв логе GLPI. Кто смотрит только php-errors.log, ошибочно решает, что «всё в порядке». - Сбрасывайте OPcache между попытками. После замены файлов php-fpm всё ещё отдаёт старый байткод; перезагрузите процесс (например,
kill -USR2мастер-процессу php-fpm), а не только Apache.
Чему нас научило сопровождение
Самый коварный инцидент, который мы видели, проявился не во время самой миграции, а через несколько месяцев, при простом bump версии административного плагина. Он выполнял миграцию схемы внутри plugin_init — распространённый и на вид безобидный паттерн: блок выполняется только пока записанный schema_version меньше версии в setup.php. Скрытый баг в этом месте дремал до следующего bump, а когда наконец выполнился и выбросил исключение, GLPI 11 перехватил его в Plugin::load и сам отключил плагин. Для клиента симптом выглядел как «включается и выключается без видимой ошибки», а плагин скатывался в состояние 4 (не активирован, что выглядит нормально). С тех пор правило жёсткое: каждый bump плагина с миграцией в init требует smoke-теста активации после bump, а блок миграции всегда помещается в try/catch, причём schema_version записывается ВНЕ try — иначе он пытается снова на каждом запросе и уходит в цикл. Такие детали держит в мышечной памяти только тот, кто каждый день эксплуатирует GLPI клиентов.
Стоит ли мигрировать сейчас?
Если ваша матрица плагинов зелёная (портированный релиз для всех ключевых) и у вас есть тестовый стенд с клоном продакшена — да: 11 современнее, безопаснее и быстрее. Если вы зависите от плагина без версии для 11, решение становится бизнесовым: заменить встроенной функцией, сменить плагин или отложить. Чего делать нельзя, так это мигрировать вслепую и обнаруживать несовместимость на работающей среде.
Если у вашей команды нет окна, чтобы отрепетировать миграцию и спокойно классифицировать каждый плагин, NexTool проведёт обновление вашего GLPI с инвентаризацией плагинов, тестированием на клоне и отрепетированным откатом. Свяжитесь с нами по поводу поддержки и сопровождения GLPI.
Проверено командой NexTool Solutions.