3.7 KiB
| id | title | domain | tags | status | severity | created_at | updated_at | applies_to | related_records | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| KB-PLUGIN-005 | ITILCategoryFieldStrategy LAST_VALID_ANSWER ignora subclasses de QuestionTypeItemDropdown | plugin-dev |
|
active | critical | 2026-05-02 | 2026-05-02 |
|
|
Contexto
Ao criar um QuestionType de plugin que retorna uma ITILCategory como resposta, o GLPI não aplica automaticamente essa categoria ao ticket criado pelo formulário.
Sintoma observável
- O usuário seleciona uma categoria no formulário.
- O ticket é criado sem
itilcategories_id(campo vazio/zero). - Nenhum erro é exibido — a categoria simplesmente é ignorada.
Causa raiz
ITILCategoryFieldStrategy::LAST_VALID_ANSWER filtra respostas por tipo assim:
$valid_answers = $answers_set->getAnswersByType(QuestionTypeItemDropdown::class);
AnswersSet::getAnswersByType() usa comparação exata (==), não is_a():
fn(Answer $answer) => $answer->getRawType() == $type
O raw_question_type de um QuestionTypeSplititil é armazenado como
'GlpiPlugin\Splititil\QuestionTypeSplititil', que não é igual a
'Glpi\Form\QuestionType\QuestionTypeItemDropdown'.
Resultado: a resposta é invisível para a estratégia padrão.
Solução — AbstractConfigField silencioso
Registrar um campo de destino de plugin que roda após ITILCategoryField e
sobrescreve itilcategories_id quando encontra uma resposta da nossa classe:
// Em setup.php (dentro de plugin_init_*)
FormDestinationManager::getInstance()->registerPluginCommonITILConfigField(
AbstractCommonITILFormDestination::class, // aplica a Ticket, Change e Problem
new \GlpiPlugin\Splititil\SplititilITILCategoryApplicator()
);
O SplititilITILCategoryApplicator estende AbstractConfigField com:
renderConfigForm()retorna''→ invisível na UI de configuraçãoapplyConfiguratedValueToInputUsingAnswers()varre as respostas buscando pelo tipo exato da nossa classe e setaitilcategories_idno input do ticket
Por que esse campo roda após ITILCategoryField
Em createDestinationItems(), os campos Entity, Template e ITILCategoryField
são aplicados antecipadamente e adicionados a $already_applied_fields.
Os campos de plugin são aplicados no foreach subsequente e não são filtrados
(porque têm uma classe diferente de ITILCategoryField), sobrescrevendo o valor anterior.
Mínimo para implementar AbstractConfigField de plugin
Além dos defaults de AbstractConfigField, implementar obrigatoriamente:
getLabel(), renderConfigForm(), getConfigClass(), getDefaultConfig(),
getWeight(), getCategory()
- uma classe config mínima implementando
JsonFieldInterface(jsonDeserialize()+jsonSerialize()).
Validação padrão
- Submeter formulário com questão de categoria preenchida.
- Abrir o ticket criado e verificar que
itilcategories_idestá preenchido. - Confirmar no banco:
SELECT itilcategories_id FROM glpi_tickets ORDER BY id DESC LIMIT 1;
Regra para agentes
Qualquer QuestionType de plugin que retorne ITILCategory DEVE implementar um
AbstractConfigField silencioso registrado via registerPluginCommonITILConfigField().
Não existe forma nativa de fazer o LAST_VALID_ANSWER reconhecer subclasses
sem modificar o core do GLPI.
Classificação
- Tipo: Limitação arquitetural do GLPI 11 + solução via ponto de extensão oficial.
- Reutilização: obrigatória em qualquer plugin de categoria ITIL no form builder.