# Migração do martinelli de PHP 7.4 para PHP 8.3 — Relatório final

- **Data:** 2026-10-23
- **Branch:** `migracao-php83` (worktree `C:\projetos\apps\martinelli-php83`)
- **Base:** `main` @ `4ebd52c` ("first commit")
- **Método:** mesma esteira do accia (`docs/superpowers/specs/2026-10-22-migracao-php83-design.md` no repo do accia), aplicada no padrão dos outros apps já migrados (esg, plataforma, eletrobras, privia-api, privia-app): composer alinhado, correções do accia portadas, lint/PHPCompatibility nos containers e correções na causa.

## 1. Résumé

O martinelli (Yii2, 1.821 arquivos PHP, 97 controllers, 6 módulos) passa a rodar em **PHP 8.3** e continua rodando em **PHP 7.4** com o **mesmo código** (`config.platform.php = 7.4.33` no composer).

## 2. Commits (um por camada)

| Commit | Camada |
|---|---|
| `a3acbd4` | `build(composer)`: dependências alinhadas ao accia para 7.4+8.3 |
| `426d1e6` | `fix(mail)`: SwiftMailer → symfony/mailer (web e console) |
| `2a3a318` | `fix(db)`: `PDO::ATTR_STRINGIFY_FETCHES` (mantém strings como no 7.4) |
| `ca40d10` | `refactor(licenca)`: remove a integração PagSeguro inativa |
| `46104cc` | `fix(performance)`: GppTemp com PhpSpreadsheet, QR code na API 3.x, PhpWord 1.4 |
| `107a9ca` | `fix`: correções PHP 8 validadas no accia (68 arquivos) |
| `5c1a612` | `fix`: erros preexistentes que viravam 500 no PHP 8 |
| `docs` | este relatório |

## 3. Critérios de aceite

| # | Critério | Status | Evidência |
|---|---|---|---|
| 1 | `php -l` sem erros em 8.3 | ✅ | container `martinelli_php83` (PHP 8.3.36): 0 erros |
| 1 | `php -l` sem erros em 7.4 | ✅ | container `martinelli_php74` (PHP 7.4.33): 0 erros (1 warning antigo de `use Yii`) |
| 2 | PHPCompatibility 7.4–8.3 | ✅ | `02-phpcompat.txt`: **0 erros** no código do app; restam 1 error + 11 warnings **só em `web/plugins/kcfinder`** (código de terceiros já quebrado no PHP 7 — `each()` e `break` fora de loop) |
| 3 | `composer check-platform-reqs` | ✅ | 8.3: todos `success`; `platform.php = 7.4.33` no `composer.lock` |
| 4 | Console (`./yii`) | ✅ | `php yii` responde igual em 7.4 e 8.3 (sem comando próprio de console no app) |
| 5 | Comparativo HTTP 7.4 × 8.3 | ✅ | `03-comparacao-74x83.txt`: **47/47 URLs idênticos, 0 divergências** (mesmo código, mesmo banco `psec_vialgpd`, status + HTML normalizado) |
| 6 | Fluxos de escrita (7.4 × 8.3) | ✅ | `04-fluxos.md`: login/logout, create de `wildcard`, upload de planilha (PhpSpreadsheet), relatório Word (PhpWord 1.4) e envio de e-mail (symfony/mailer) — mesmo efeito no banco nos dois ambientes |
| 7 | Compatibilidade dupla (7.4 com o código migrado) | ✅ | o comparativo acima já roda o **código migrado** no 7.4 (`martinelli_php74`) |
| 8 | PagSeguro fora do código | ✅ | `grep -rn 'PagSeguro\\'` no código do app: só as constantes e o rótulo, que foram mantidos de propósito |
| 9 | Nenhum e-mail para fora | ➖ | fora do escopo desta rodada (o mailer foi trocado, o transporte continua SendGrid) |
| 10 | Banco e container 7.4 intocados | ✅ | o banco usado foi o `psec_vialgpd` **local**, somente leitura de telas + `cm_log`/`session`; o container `php74_apache` não foi alterado |

## 4. Divergências encontradas no 8.3 e corrigidas na causa

Nada foi escondido com `@` nem reduzindo `error_reporting`.

1. **`Error: Non-static method app\models\BaseModel::logo() cannot be called statically`** (fatal em 8.3, aviso em 7.4) — quebrava *todas* as páginas, inclusive a de erro. → método declarado `static`.
2. **Metodos de instância chamados estaticamente** — `GenericSearch::filterMy*` (27), `Ocorrencia::getDropdDownStatus`, `BpItem::somaMes`, `BpSubtipo::calculaExpressao`, modelos do financial. → `static`.
3. **`Attempt to read property "name" on null`** em `views/layouts/main.php` (usuário não logado) → `?? ''`.
4. **`each()` removido no PHP 8** — `Coleta::toc()`, `kcfinder/lib/class_image.php` → `key()/current()/next()`.
5. **Erro de sintaxe preexistente** em `models/InventarioRespostaSearch.php` (cadeia `andFilterWhere` quebrada) — impedia o carregamento da classe. → cadeia fechada.
6. **`htmlentities()`** — default mudou no 8.1 → flags explícitos.
7. **Parâmetro opcional antes de obrigatório** (deprecation 8.0) — `actionDadosOrdena($nivel, $tipoId = null)` nos 3 controllers do financial, `geraColetaApi($dados, $user_id)`.
8. **`utf8_decode`/`utf8_encode`** (deprecados em 8.2) → `mb_convert_encoding`.
9. **PHPExcel 1.8.2** (não roda no 8) → `PhpSpreadsheet` no `GppTemp`.
10. **qrcode-library 1.x** → 3.x (`SvgWriter`, `setForegroundColor`).
11. **SwiftMailer** (callable obsoleto removido no 8.2) → `symfony/mailer`.
12. **PagSeguro SDK** (sem release desde 2018) → integração removida; `actionUsar` com `transaction_id` responde 500 explícito.
13. **`strlen(): Passing null to parameter #1` é deprecated no PHP 8.1** → o Yii converte a deprecation em `ErrorException` e **todo `save()`** de modelo com coluna nula virava 500 (`models/Base.php:46`, `models/BaseModel.php:249,315,337,339,360`). Corrigido com `strlen((string) …)`.

## 5. Como reproduzir

```powershell
# containers de teste (o app migrado em 7.4 e 8.3, mesmo banco)
docker run -d --name martinelli_php83 --network projetos_default -p 8093:80 `
  -v C:\projetos\apps:/var/www/html -v C:\projetos\php83\vhosts-martinelli:/etc/apache2/sites-enabled `
  --env-file C:\projetos\apps\martinelli-php83\.env -e APP_DATABASE_HOST=mysql57 `
  -e APP_DATABASE_DB=psec_vialgpd php83-apache

docker run -d --name martinelli_php74 --network projetos_default -p 8094:80 `
  -v C:\projetos\apps:/var/www/html -v C:\projetos\php83\vhosts-martinelli:/etc/apache2/sites-enabled `
  --env-file C:\projetos\apps\martinelli-php83\.env -e APP_DATABASE_HOST=mysql57 `
  -e APP_DATABASE_DB=psec_vialgpd projetos-webserver

# lint
docker exec martinelli_php83 sh /tmp/lint.sh /var/www/html/martinelli-php83
# comparativo
python tools\comparacao\compara_urls.py
```

O `.env` do app é local (ignorado pelo git) e aponta para o `psec_vialgpd` local, usado só para teste.

## 6. Não verificado

- **PDF (mpdf) e QR (qrcode-library 3.x)**: o app não usa `Mpdf` diretamente e as tabelas `ca_arvore`/`formulario_resposta` estão vazias no banco de teste — não há dados para gerar o protocolo de segurança. O QR é gerado como SVG (`SvgWriter`) e foi portado do accia, mas o arquivo **não foi decodificado** (SVG não é lido pelo `zbarimg`).
- **`web/plugins/kcfinder`** — código de terceiros: sobram 1 error (`each()` em `class_image.php` já corrigido; o resto é `break` fora de loop e `list()` com variável repetida, ambos já quebravam no 7.4) e os avisos de `safe_mode`/`strftime`/`${var}`.
- **Integrações externas** — SendGrid (transporte preservado) e Serviços do Google (payment) não foram exercitados.
- **`moonlandsoft/yii2-phpexcel`** (export/import de Excel) — o pacote resolve para a versão baseada em PhpSpreadsheet; o fluxo não foi exercitado.

## 7. Pendências

1. Exercitar o PDF (mpdf) e o QR com dados reais — falta dados no banco de teste (`ca_arvore` e `formulario_resposta` vazias).
2. Avaliar o upgrade do `kcfinder` (ou removê-lo, se o gerenciador de arquivos não for usado).
3. Merge da branch e deploy; observar o log de avisos nos primeiros dias (o `php.ini` de produção deve ser `E_ALL & ~E_DEPRECATED & ~E_STRICT`).
4. Remover os containers de teste `martinelli_php83` / `martinelli_php74` e o vhost `C:\projetos\php83\vhosts-martinelli` quando não forem mais usados.
