--- id: KB-PLUGIN-023 title: mcprotocol — InputValidation extraída como classe utilitária compartilhada domain: plugin-dev tags: - mcp - tools - validation - refactor - patterns status: active severity: medium created_at: 2026-05-26 updated_at: 2026-05-26 applies_to: - glpi-11 - mcprotocol-plugin related_records: - KB-PLUGIN-022 - KB-PLUGIN-019 --- # mcprotocol — InputValidation extraída como classe utilitária compartilhada ## Contexto KB-PLUGIN-022 documentou os padrões `resolveReference`, `normalizeDate`, validação agregada e response com `applied` como métodos privados em `ProjectTools`. Esse KB previu que **na introdução do segundo handler** os helpers seriam extraídos para uma classe utilitária. Esse momento chegou ao implementar `glpi_projecttask_create`. ## Decisão Extraído `src/InputValidation.php` (namespace `GlpiPlugin\Mcprotocol`) com métodos **estáticos públicos** reutilizáveis em qualquer handler de tool: | Método | Responsabilidade | |---|---| | `resolveReference($table, $value, $field, &$errors, $nameCol='name')` | Aceita int ou string e devolve ID validado. Suporta coluna de busca customizada (ex: `name` em `glpi_users`). | | `normalizeDate($value, $field, &$errors)` | Aceita `YYYY-MM-DD` ou `YYYY-MM-DD HH:MM:SS`, normaliza pro formato GLPI. | | `validateDateRange($start, $end, $startField, $endField, &$errors)` | Garante `end >= start` quando ambos informados. | | `validateIntRange($value, $field, $min, $max, &$errors)` | Valida inteiro em intervalo (ex: `percent_done` 0-100). | ## Mudanças realizadas - **Novo arquivo:** `src/InputValidation.php` - **Refatorado:** `src/ProjectTools.php` — removeu helpers privados, agora chama `InputValidation::*`. Também ganhou método `buildInputFromArgs($args, $isUpdate)` que centraliza a montagem do input para create/update (DRY). - **Estendido:** `glpi_project_update` agora aceita os mesmos campos do create (datas, estado, tipo) — antes só aceitava name/content/percent_done. - **Novo arquivo:** `src/ProjectTaskTools.php` — usa `InputValidation` desde o início, com 2 tools: `glpi_projecttask_create` e `glpi_projecttask_get`. - **Atualizado:** `src/ToolRegistry.php` — registra `ProjectTaskTools::getTools()` no merge. ## Convenções de uso 1. **Acumular erros** — qualquer handler que valida múltiplos campos deve usar a assinatura `&$errors` e lançar UMA exception ao final. Nunca múltiplas. 2. **Coluna de busca por nome** — `resolveReference` aceita `$nameCol`. Para tabelas onde o campo descritivo não se chama `name`, passar explicitamente: ```php InputValidation::resolveReference('glpi_users', $args['users_id'], 'users_id', $errors, 'name'); ``` 3. **Validação prévia ao ORM** — todos os helpers rodam ANTES de `$obj->add()` ou `$obj->update()`. Se houver erro, exception é lançada e o ORM nunca é chamado. Evita erros de SQL/ORM crípticos. 4. **Response com `applied`** — handlers devem sempre retornar o input efetivamente aplicado: ```php return ['status'=>'success', 'id'=>$newId, 'message'=>'...', 'applied'=>$input]; ``` ## Tabelas comuns para `resolveReference` | Tabela | Coluna de nome | Uso típico | |---|---|---| | `glpi_projectstates` | `name` | Estado de projeto/tarefa | | `glpi_projecttypes` | `name` | Tipo de projeto | | `glpi_projecttasktypes` | `name` | Tipo de tarefa | | `glpi_users` | `name` (login) | Responsável | | `glpi_groups` | `name` | Grupo | | `glpi_entities` | `name` | Entidade | | `glpi_itilcategories` | `name` | Categoria de chamado | | `glpi_locations` | `name` | Localização | ## Próximos handlers candidatos a usar `InputValidation` - `glpi_ticket_create` — `users_id_recipient`, `users_id_lastupdater`, `itilcategories_id`, datas - `glpi_ticket_update` — idem + estados (1=New, 2=Processing, etc. já são enums numéricos GLPI) - Futuras tools de Computer/Asset (`glpi_computer_create`, etc.) ## Validação end-to-end Padrão validado em produção criando o projeto VALGROUP (28 tarefas em hierarquia) através das tools. Erros de validação retornados claramente, datas normalizadas, estados resolvidos por nome ("New" → 1, "Processing" → 2). Aplicado conforme esperado.