# Repositórios — Diário Oficial

> _Atualizado para o **v6** (`update_diario_v5_to_v6`) em 2026-09-11. Alterações desta versão: `DIARIO_OFICIAL_ALTERACOES.md` e `plan/2026-09-11-diario-upgrade-backlog.md`._

## Estrutura

```
app/Repositories/
├── Contracts/                          # Interfaces
│   ├── IDiarioAreaRepository.php
│   ├── IDiarioSubAreaRepository.php
│   └── IDiarioConfigRepository.php
└── Eloquent/Prefecture/
    ├── DiarioOficial/
    │   ├── DiarioOficialRepository.php  # Repository principal
    │   ├── Area/
    │   │   └── AreaRepository.php       # Matérias (DiarioHasAreas)
    │   ├── DiarioArea/
    │   │   └── DiarioAreaRepository.php # Áreas (DiarioArea)
    │   └── DiarioSubArea/
    │       └── DiarioSubAreaRepository.php # Subáreas (DiarioSubArea)
    └── DiarioConfig/
        └── DiarioConfigRepository.php   # Configurações
```

## Classe Base

Todos os repositórios estendem `App\Repositories\Repository`, que fornece:

```php
abstract class Repository {
    protected $model;

    abstract protected function structureUpInsert($request): array;

    public function upInsert($request, $id = null) { ... }
    public function destroy($id) { ... }
    public function destroyAll($ids) { ... }
    protected function filter_request($request, $fields) { ... }
}
```

## 1. `DiarioOficialRepository` (Principal)

**Arquivo:** `app/Repositories/Eloquent/Prefecture/DiarioOficial/DiarioOficialRepository.php`

### Responsabilidades

- CRUD de diários (via `Repository::upInsert`)
- Geração completa de PDF com certificação digital (resiliente: timeout, progresso, escrita atômica, logs)
- Stream de PDF existente (com download opcional)
- Trilha de auditoria pública (`getPublicAuditTrail`)

### Métodos

| Método | Descrição |
|--------|-----------|
| `structureUpInsert($request)` | Prepara dados: formata data, trata has_line, status, permission_edit |
| `generatePDF($id, $forceCreate, $show, $download)` | Decide: serve o PDF existente (se `!forceCreate`) ou chama `generatePdfFile` e faz stream |
| `generatePdfFile($id)` | **Geração real** do PDF. Retorna `bool` (seguro para fluxos com polling) |
| `streamPdf($path, $download)` | Faz stream de um PDF existente |
| `saveGenerationProgress($id, $progress)` | Persiste o progresso granular em `generation_progress` (com try/catch) |
| `printAnexoMateria($pdf, $materia, $id, $columnsNumber, $inlineFlow)` | Imprime um anexo (inline rasterizado ou páginas inteiras) com fallbacks |
| `writeImagesInline(...)` | Escreve as páginas rasterizadas no fluxo de colunas (`writeHTML` + `selectColumn`) |
| `printImportedPagesInline(...)` | Fallback: importa páginas via FPDI em fluxo inline |
| `printImportedPagesFullPage(...)` | `file_in=false`: 1 página de origem = 1 página de saída |
| `printImagesFullPage(...)` | Fallback raster do full-page (`AddPage` + `Image`) |
| `printImportedPagesGrid(...)` / `printImagesGrid(...)` / `printImagesFlow(...)` / `gridBoxesForColumns(...)` | Fallbacks de grade (ex.: 2×2) e fluxo por imagens |
| `mergePdfs(...)` | **Código morto** — não é mais chamado na geração (o escopo passou a ser por área) |
| `cleanupMergedPdfs($id)` | Remove eventuais temporários `_merged_*` da pasta da edição |
| `certReturn($nomeCertCRT)` | Extrai CNPJ/nome do certificado |
| `pathImage($image)` | Ajusta caminho da imagem |
| `getPublicAuditTrail($idDiario)` | Monta a trilha de auditoria pública (LGPD) |

### `generatePdfFile($id)` — Fluxo Detalhado

```
1. `@set_time_limit(0)` + log de início
2. Busca Diario, DiarioConfig e DiarioCertificado (prioriza o do diário; fallback padrão)
3. Sem certificado → retorna false (log de erro)
4. Agrupa as matérias por ÁREA: groupBy('id_area'), ordenado por position + id_area
   (a subárea NÃO define seção nem quebra)
5. Prepara dados (prefeitura, endereço, certificado) e gera o QR Code
   com rtrim(config('app.url'), '/') + '/diario-oficial/{id}' (try/catch)
6. Instancia FPdfService; define isPublished = status do diário
   e progressCallback (grava generation_progress)
7. Adiciona capa (se coverImagePath) e a primeira página
8. Para cada ÁREA:
   a. Nova área só abre página se a atual já tiver conteúdo (evita página em branco)
   b. ChapterHeader(nome da área)
   c. Para cada matéria:
      - Texto: acumula HTML
      - type=file: fecha o texto pendente; progresso `processing_attachment`;
        printAnexoMateria(...):
          * file_in=true  → convertPdfToImages (Imagick+GS) + writeImagesInline
            (fluxo de colunas contínuo); fallback import inline → grade
          * file_in=false → printImportedPagesFullPage (FPDI useTemplate);
            fallback printImagesFullPage → grade
   d. Imprime o texto acumulado via PrintChapter
9. Escrita ATÔMICA: Output('S') → Storage::put(.tmp.<uniqid>) →
   delete destino → Storage::move
10. cleanupMergedPdfs + log de sucesso; em erro fatal loga e limpa temporários
```

> A assinatura digital é aplicada **apenas** quando `isPublished` (o `status` do diário é publicado), dentro do `FPdfService::Header()`.

---

## 2. `AreaRepository`

**Arquivo:** `app/Repositories/Eloquent/Prefecture/DiarioOficial/Area/AreaRepository.php`

Gerencia **Matérias** (tabela `diario_has_areas`).

```php
class AreaRepository extends Repository {
    public function __construct() {
        $this->model = new DiarioHasAreas();
    }
}
```

---

## 3. `DiarioAreaRepository`

**Arquivo:** `app/Repositories/Eloquent/Prefecture/DiarioOficial/DiarioArea/DiarioAreaRepository.php`
**Interface:** `IDiarioAreaRepository`

Gerencia **Áreas** (tabela `diario_areas`).

```php
class DiarioAreaRepository extends Repository implements IDiarioAreaRepository {
    public function __construct() {
        $this->model = new DiarioArea();
    }
}
```

---

## 4. `DiarioSubAreaRepository`

**Arquivo:** `app/Repositories/Eloquent/Prefecture/DiarioOficial/DiarioSubArea/DiarioSubAreaRepository.php`
**Interface:** `IDiarioSubAreaRepository`

Gerencia **Subáreas** (tabela `diario_sub_areas`).

```php
class DiarioSubAreaRepository extends Repository implements IDiarioSubAreaRepository {
    public function __construct() {
        $this->model = new DiarioSubArea();
    }
}
```

---

## 5. `DiarioConfigRepository`

**Arquivo:** `app/Repositories/Eloquent/Prefecture/DiarioConfig/DiarioConfigRepository.php`
**Interface:** `IDiarioConfigRepository`

Gerencia **Configurações** (tabela `diario_configs`).

```php
class DiarioConfigRepository extends Repository implements IDiarioConfigRepository
{
    public function getModel() { return $this->model; }
}
```

---

## Service Provider Bindings

`app/Providers/RepositoryServiceProvider.php`:

```php
$this->app->bind(
    IDiarioAreaRepository::class,
    DiarioAreaRepository::class
);
$this->app->bind(
    IDiarioSubAreaRepository::class,
    DiarioSubAreaRepository::class
);
$this->app->bind(
    IDiarioConfigRepository::class,
    DiarioConfigRepository::class
);
```
