# Acesso Rápido — Arquitetura

## 1. Visão geral das camadas

O módulo é **híbrido**: o CMS reaproveita a infração genérica de CRUD de `contents`
(`Prefecture\ContentController`), enquanto o portal tem um controller dedicado
(`Portal\QuickAccessController`). Não há Repository nem Service próprios.

```
                         ┌──────────────────────────────────────────────┐
  CIDADÃO (portal)       │  routes/web.php  (middleware: web +           │
  /acesso-rapido/{slug}  │                  check.site.manutention)     │
  /acessos-rapido/{slug} │                  v6/routes/web.php:89-95      │
                         └───────────────┬──────────────────────────────┘
                                         │
                         ┌───────────────▼──────────────────────────────┐
                         │ Portal\QuickAccessController                 │
                         │ v6/app/Http/Controllers/Portal/             │
                         │   QuickAccessController.php                 │
                         │ extends App\Http\Controllers\Admin\Controller │
                         │ use NewsTrait, GetInformationsPrefectureTrait│
                         └───────┬───────────────────┬──────────────────┘
                                 │                   │
            ┌────────────────────▼──────┐   ┌────────▼─────────────────────────────┐
            │ getContentByCategory(slug)│   │ getStaticPageData(slug)            │
            │ App\Prefecture\Content    │   │ App\Prefecture\StaticPage          │
            │ whereHas(categoryContents)│   │ with('linksUnique')->first()       │
            └────────────────────┬──────┘   └────────┬─────────────────────────────┘
                                 │                   │
            ┌────────────────────▼───────────────────▼─────────────────────────────┐
            │ Views Blade: portal.layouts.{layout}.informacoes-instituicao.      │
            │              acesso-rapido.{slug}                                  │
            │ View SQL "acesso_rapido" (somente leitura do CMS)                  │
            └────────────────────────────────────────────────────────────────────┘

                         ┌──────────────────────────────────────────────┐
  OPERADOR (CMS)         │ routes/basepro.php (prefixo "cms")           │
  /cms/conteudos/        │ v6/routes/basepro.php:235-237                │
    acesso-rapido        │ (rotas `listar-conteudo`,                    │
                         │  `cadastrar-conteudo`, `editar-conteudo`)    │
  /cms/datatable/        │ v6/routes/basepro.php:395-442 (grupo         │
    acesso_rapido        │ `datatable`), rota em :430                   │
                         └───────────────┬──────────────────────────────┘
                                         │
        ┌────────────────────────────────┴────────────────────────────────┐
        │ Prefecture\ContentController (genericIndex/genericCreate/        │
        │   genericEdit/genericDestroy)  +  Prefecture\DatatableController │
        │   (get_acesso_rapido)  +  Prefecture\ContentController@ajustOrder│
        └─────────────────────────────────────────────────────────────────┘
```

## 2. Classes envolvidas

| Classe | Caminho | Papel |
|---|---|---|
| `App\Http\Controllers\Portal\QuickAccessController` | `v6/app/Http/Controllers/Portal/QuickAccessController.php` | Controller público do portal; monta o prefixo de view e decide entre conteúdo de categoria e página estática. |
| `App\Http\Controllers\Admin\Controller` | `v6/app/Http/Controllers/Admin/Controller.php` | Classe-base do controller do portal; fornece `getTemplateActived()`. |
| `App\Http\Controllers\Prefecture\ContentController` | `v6/app/Http/Controllers/Prefecture/ContentController.php` | CRUD genérico de `contents` usado pelo CMS para o módulo; `genericIndex` (linha 91), `genericCreate` (140), `genericEdit` (158), `genericGenerate` (163), `ajustOrder` (1498), `setStatus` (1548), `genericDestroy` (1369). |
| `App\Http\Controllers\Prefecture\DatatableController` | `v6/app/Http/Controllers/Prefecture/DatatableController.php` | `get_acesso_rapido()` (linha 234) monta o JSON do DataTable a partir da view SQL `acesso_rapido`. |
| `App\Http\Traits\GetInformationsPrefectureTrait` | `v6/app/Http/Traits/GetInformationsPrefectureTrait.php` | `getContentByCategory()` (28), `getStaticPageData()` (60), `getTemplateActived()` (92), `updateClickStaticPage()` (110). |
| `App\Http\Traits\NewsTrait` | `v6/app/Http/Traits/NewsTrait.php` | `getContentNews()` (28) — categorias de notícia exibidas no menu lateral das páginas. |
| `App\Prefecture\Content` | `v6/app/Http/Model/Prefecture/Content.php` | Eloquent de `contents`; `categoryContents()` (belongsTo), `linksUnique()` (hasOne). |
| `App\Prefecture\CategoryContent` | `v6/app/Http/Model/Prefecture/CategoryContent.php` | Eloquent de `category_contents`. |
| `App\Prefecture\StaticPage` | `v6/app/Http/Model/Prefecture/StaticPage.php` | Eloquent de `static_pages`; `linksUnique()` (hasOne). |
| `App\Prefecture\Archive` | `v6/app/Http/Model/Prefecture/Archive.php` | Eloquent de `archives` (arquivos anexados à página estática). |
| `App\Prefecture\Link` | `v6/app/Http/Model/Prefecture/Link.php` | Eloquent de `links` (URL de destino do atalho). |
| `App\Admin\State` / `App\Admin\City` | `v6/app/Http/Model/Admin/State.php`, `v6/app/Http/Model/Admin/City.php` | Listas de estado/cidade usadas pelo formulário de solicitação de informação. |
| `App\Providers\ConfigHeaderServiceProvider` | `v6/app/Providers/ConfigHeaderServiceProvider.php:86-101` | View composer que injeta `$acessos` (contents da categoria `acesso-rapido` com `status = true`) nas views da home. |
| `App\Providers\ModulosServiceProvider` | `v6/app/Providers/ModulosServiceProvider.php` | View composer que injeta `$modulos` (status por slug, cache `Cache::rememberForever('modulos')`). |
| `App\Library\Helper\appHelpers` | `v6/app/Library/Helper/appHelpers.php:22` | Helper `has_access()` usado no CMS. |
| `App\Http\Middleware\CheckRoutePermission` | `v6/app/Http/Middleware/CheckRoutePermission.php` | Autorização das rotas do CMS. |

## 3. Fluxo detalhado — portal

### 3.1 `GET /acesso-rapido/{slug}` (rota `acesso-rapido.index`)

1. Middleware `web` (sessão + CSRF) e `check.site.manutention`
   (`v6/routes/web.php:7`).
2. `QuickAccessController::__construct` injeta `Content` e `CategoryContent` e calcula
   `$this->view = "portal.layouts." . $this->getTemplateActived() . ".informacoes-instituicao.acesso-rapido."`.
   `getTemplateActived()` lê `configurations.key = 'layout'`; se a view
   `portal.layouts.{layout}.home.index` não existir, marca
   `configurations.pagina_em_manutencao = 1` e faz `abort(404)`.
3. `index($slug1)`:
   - se `$slug1 === 'ouvidoria'` -> `redirect()->to(url('/acessos-rapido/solicitar-informacao'))`;
   - `$contentCategoriesNews = $this->getContentNews()`;
   - `$contents = $this->getContentByCategory($slug1)` — `Content::whereHas('categoryContents', fn($q) => $q->where('slug', $param))->get()`;
   - se `!count($contents)` -> delega a `getIndexStatic($slug1)`;
   - senão `view($this->view . $slug1, compact('contentCategoriesNews','contents'))`.

### 3.2 `GET /acessos-rapido/{slug}` (rota `acessos-rapido.index`)

1. `getIndexStatic($slug1)`:
   - `$contents = $this->getStaticPageData($slug1)` — `StaticPage::with('linksUnique')->where('slug', $param)->first(['id','title','text','layout'])`;
   - `$this->updateClickStaticPage($contents->id)` — `static_pages.clicks + 1`;
   - `$archives = Archive::where('static_pages_id', $contents->id)->where('highlight', null)->get()`;
   - `$view_pdf = Archive::where('static_pages_id', $contents->id)->where('view_pdf', true)->first()`;
   - `$states = State::pluck('name','id')`, `$cities = City::pluck('name','id')`;
   - se `$slug1 === "solicitar-informacao"` -> renderiza
     `portal.layouts.newsbit.informacoes-instituicao.acesso-rapido.solicitar-informacao`
     com `content`, `states`, `cities`, `modelo`, `archives`, `view_pdf`;
   - senão -> `view($this->view . $slug1, compact('contentCategoriesNews','contents','states','cities','archives','view_pdf'))`.

### 3.3 Renderização do bloco na home

`ConfigHeaderServiceProvider` monta `$acessos` **uma vez por requisição** e o injeta por
view composer em seis views:

| View injetada | Layout |
|---|---|
| `portal.layouts.modelo1.home.acesso-rapido` | modelo1 |
| `portal.layouts.modelo2.home.acesso-rapido` | modelo2 |
| `portal.layouts.modelo3.home.links-rapidos` | modelo3 |
| `portal.layouts.modelo4.home.links-rapidos` | modelo4 |
| `portal.layouts.modelo5.home.news.sidebar.acesso-rapido` | modelo5 |
| `portal.layouts.modelo6.layout.sidebar.acesso-rapido` | modelo6 |

A consulta é:

```php
// v6/app/Providers/ConfigHeaderServiceProvider.php:86-89
$acessos = Content::with('categoryContents', 'linksUnique')->whereHas('categoryContents', function ($query) {
    $query->where('slug', '=', 'acesso-rapido');
})->where('status', true)->orderBy('order', 'asc')->get();
```

## 4. Fluxo detalhado — CMS

1. `GET /cms/conteudos/acesso-rapido` (rota `listar-conteudo`,
   `v6/routes/basepro.php:234`) -> `ContentController@genericIndex` ->
   `if ($slug === 'acesso-rapido') return $this->returnIndex('Acesso Rápido', $slug);`
   -> view `prefecture.contents.acesso-rapido.index`.
2. A view carrega `assets/js/custom/contents/acesso-rapido/datatable.js`, que chama
   `runDatatables('acesso_rapido', collums, true, 'ASC', null)`.
3. `runDatatables` faz `GET /cms/datatable/acesso_rapido`
   (`v6/public/assets/js/custom/utilities/table.js:181-185`) ->
   `DatatableController@get_acesso_rapido` -> `DB::table('acesso_rapido')->get()` ->
   `struct_views($links, 'acesso-rapido', true, false)` (linha 504) ->
   `DataTables::of($this->struct_views($links, 'acesso-rapido', true, false))->make(true)`.
4. Ordenação: o `sortable` do jQuery UI faz `POST /cms/ajax/ajust-banners`
   (rota `ajust.banners`, `v6/routes/basepro.php:137`) ->
   `ContentController@ajustOrder` -> `reorder(new Content(), $request->sortable_data)`.
5. Ativar/desativar: botão com `target_url = '/cms/set-status'`
   (`v6/routes/basepro.php:347`, rota `set.status`) -> `ContentController@setStatus`.
6. Editar: link relativo `editar/acesso-rapido/{id}` (montado em
   `v6/public/assets/js/custom/contents/acesso-rapido/datatable.js`) que, relativo a
   `/cms/conteudos/acesso-rapido`, resolve para `/cms/conteudos/editar/acesso-rapido/{id}`
   (rota `editar-conteudo`).
7. Excluir: `DELETE /cms/conteudo/delete/{id}` (rota `generic.conteudo.delete`).

## 5. Dependências externas (composer)

| Pacote | Uso no módulo |
|---|---|
| `laravel/framework` 5.5 | rotas, views, Eloquent, `DataTables` (yajra) e formulários `laravelcollective/html`. |
| `yajra/laravel-datatables-oracle` | `DataTables::of($this->struct_views($links, 'acesso-rapido', true, false))->make(true)` no `DatatableController`. |
| `laravelcollective/html` | `Form::open`, `Form::model`, `Form::text` nos Blades do CMS e do portal. |
| `google/recaptcha` | `Recaptcha::render()` no formulário de solicitação de informação. |
| `cartalyst/sentinel` | `Sentinel::check()` / `has_access()` no controle de permissão do CMS. |
| `graham-campbell/markdown` (indireto) | renderização de `contents.text` com `{!! !!}` (HTML cru) — o texto vem do Summernote do CMS. |

## 6. Pontos de atenção arquitetural

| Ponto | Impacto |
|---|---|
| Controller do portal estende `Admin\Controller` | Herda dependências do CMS (ex.: `getTemplateActived()`) numa classe pública. |
| Sem Repository/Service no portal | Lógica de apresentação e consulta misturadas no controller. |
| View composer global | `$acessos` é calculado para **todas** as requisições do portal, mesmo quando o bloco não é exibido. |
| `Cache::rememberForever('modulos')` | O cache é invalidado explicitamente por `Cache::pull('modulos')` em `ModulosController@update` (`v6/app/Http/Controllers/Admin/ModulosController.php:50`). |
| Dependência de views por layout | 6 layouts × 7 telas = replicação manual obrigatória. |
