# Banners — Rotas e Controllers

## 1. Rotas do CMS (`/cms`)

O módulo reutiliza as rotas genéricas de conteúdo definidas em
`v6/routes/basepro.php`.

| Método | URI (relativa) | Nome (`->name()`) | Controller@ação | Linha |
|---|---|---|---|---|
| GET | `conteudos/{slug}` | `listar-conteudo` | `Prefecture\ContentController@genericIndex` | `v6/routes/basepro.php:235` |
| GET | `conteudos/cadastrar/{slug}` | `cadastrar-conteudo` | `Prefecture\ContentController@genericCreate` | `v6/routes/basepro.php:236` |
| GET | `conteudos/editar/{slug}/{id}` | `editar-conteudo` | `Prefecture\ContentController@genericEdit` | `v6/routes/basepro.php:237` |
| POST | `conteudo` | `conteudo.store` | `Prefecture\ContentController@store` | `v6/routes/basepro.php:174` (`Route::resource`) |
| PUT/PATCH | `conteudo/{id}` | `conteudo.update` | `Prefecture\ContentController@update` | `v6/routes/basepro.php:174` |
| DELETE | `conteudo/{id}` | `conteudo.destroy` | `Prefecture\ContentController@destroy` | `v6/routes/basepro.php:174` |
| POST | `ajust-banners` | `ajust.banners` | `Prefecture\ContentController@ajustOrder` | `v6/routes/basepro.php:137` |
| POST | `update/super-banner` | `update.super.banner` | `Prefecture\ContentController@updateSuperBanner` | `v6/routes/basepro.php:249` |
| POST | `conteudo/deleteAll` | `ajax.generic.content.deleteAll` | `Prefecture\ContentController@genericDeleteAll` | `v6/routes/basepro.php:141` |
| GET | `datatable/banners` | `banners` | `Prefecture\DatatableController@get_banners` | `v6/routes/basepro.php:427` |
| GET | `datatable/super_banners` | `super_banners` | `Prefecture\DatatableController@get_super_banners` | `v6/routes/basepro.php:428` |

Com `{slug}` = `banners` ou `super-banners`.

## 2. Rotas do Portal

O módulo **não** tem rotas próprias: os banners são renderizados como parte das páginas
do portal. As rotas relevantes do portal (`v6/routes/web.php`) são:

| Método | URI | Nome | Controller@ação |
|---|---|---|---|
| GET | `/` | `home` | `Portal\PortalController@index` |
| GET | `/pagina/{slug}` | `static.show` | `Portal\PortalController@staticShow` |

O layout `default` inclui `portal.layouts.default.side-banners` nas páginas
`pages/index`, `pages/contents/*`, `pages/statics/show` e `pages/busca/index`.

## 3. Controller — métodos envolvidos

| Método | Arquivo:linha | Comportamento |
|---|---|---|
| `genericIndex` | `v6/app/Http/Controllers/Prefecture/ContentController.php:91` | Despacha por `slug`; `banners` e `super-banners` caem em `returnIndex` |
| `returnIndex` | `…/ContentController.php:121` | Monta a view de listagem da categoria |
| `genericCreate` / `genericEdit` | `…/ContentController.php:140` / `:158` | Delegam para `genericGenerate` |
| `genericGenerate` | `…/ContentController.php:163` | `banners` e `super-banners` → `returnData(..., 'banners', ...)` |
| `returnData` | `…/ContentController.php:275` | Monta o formulário (variáveis `categoryContent`, `banners`, `destaque`, `content`) |
| `store` | `…/ContentController.php:616` | Cria `Content`, `Archive` (imagem), `Link`; aplica a regra de ativação exclusiva do super banner |
| `update` | `…/ContentController.php:937` | Atualiza; mesma regra de ativação |
| `destroy` / `genericDestroy` | `…/ContentController.php:1320` / `:1369` | Remove conteúdo (soft delete) |
| `ajustOrder` | `…/ContentController.php:1498` | Persiste a ordem do drag & drop |
| `updateSuperBanner` | `…/ContentController.php:1427` | Edição rápida dos dois super banners (status, URL e imagem) |
| `setStatus` | `…/ContentController.php:1548` | Alterna o status de um conteúdo |

### 3.1 Despacho por slug

```php
// v6/app/Http/Controllers/Prefecture/ContentController.php:102-104
if ($slug === 'rede-social') return $this->returnIndex('Redes Sociais', $slug);
if ($slug === 'banners') return $this->returnIndex('Banners', $slug);
if ($slug === 'super-banners') return $this->returnIndex('Super Banners', $slug, 'banners');
```

E, para o formulário:

```php
// v6/app/Http/Controllers/Prefecture/ContentController.php:174-175
if ($slug === 'banners') return $this->returnData('Banners', $slug, 'banners', [], $id);
if ($slug === 'super-banners') return $this->returnData('Super Banners', $slug, 'banners', [], $id);
```

> Em `super-banners`, a variável `$banners` recebida pelo formulário é preenchida com os
> conteúdos da categoria **`banners`** (não `super-banners`), por causa do argumento
> `'banners'` em `$self`. A view do super banner não usa `$banners`, então o efeito é
> inofensivo hoje — mas é uma fonte de confusão.

### 3.2 Ativação exclusiva por posição (super banner)

```php
// v6/app/Http/Controllers/Prefecture/ContentController.php:675-677 (store)
// v6/app/Http/Controllers/Prefecture/ContentController.php:997-999 (update)
if ($slug === 'super-banners' && $request->get('status') == 1) {
    Content::where('category_contents_id', $category_contents_id)
        ->where('order', $request->get('order'))
        ->where('status', true)
        ->update(['status' => false]);
}
```

Ou seja: **ativar um super banner desativa o outro da mesma posição** (`order` 1 ou 2).
O mesmo vale para `setStatus` (`…/ContentController.php:1568-1570`).

### 3.3 Reordenação

```php
// v6/app/Http/Controllers/Prefecture/ContentController.php:1498-1502
public function ajustOrder(Request $request): JsonResponse
{
    $this->reorder((new Content()), $request->sortable_data);
    return response()->json(true);
}
```

`reorder()` está em `v6/app/Http/Traits/AppTrait.php:741` e grava a nova sequência na
coluna `order` da tabela `contents`.

### 3.4 `updateSuperBanner`

```php
// v6/app/Http/Controllers/Prefecture/ContentController.php:1427-1452 (trecho)
$banner1 = $this->table->whereHas('categoryContents', function($q){ $q->where('slug', 'super-banners'); })->where('order', 1)->first();
$linkBanner1 = Link::where('contents_id', $banner1->id)->first();
$archive1 = $this->archive->where('contents_id', $banner1->id)->first();

$banner2 = $this->table->whereHas('categoryContents', function($q){ $q->where('slug', 'super-banners'); })->where('order', 2)->first();
// trecho omitido do código original
$banner1->status = $request->check_super_banner_1;
if (!isset($request->check_super_banner_1)) $banner1->status = 0;
// trecho omitido do código original
$linkBanner1->link = $this->sanitizeLink($request->get('url_super_banner_1'));
```

Pontos:

- Assume **exatamente dois** super banners (posições 1 e 2) — se faltar um, `$banner1` ou
  `$banner2` é `null` e o acesso a `->id` gera erro fatal.
- O nome dos campos esperados (`check_super_banner_1`, `url_super_banner_1`,
  `super_banner_1`) coincide com o que o formulário `super.blade.php` envia
  (`check_<slug>`, `url_<slug>`, `<slug>`) **apenas** porque os slugs semeados dos
  dois super banners são `super_banner_1` e `super_banner_2` (ver `04-VIEWS-E-UX.md`).
  A tela, porém, é órfã: nenhum controller a renderiza, logo a rota fica sem uso.
- O caminho do arquivo é reescrito para `storage/content/super-banner/` (singular),
  enquanto a view do formulário aponta para `storage/content/super-banners/` (plural).

## 4. Form Request / validação

`v6/app/Http/Requests/ContentRequest.php` — as regras dependem do `slug`:

```php
case 'banners':
    $rules = [
        "title" => "required|max:120",
        "category_contents_id" => "required|numeric",
        "link" => "required|max:2999",
        "order" => "required",
    ];

    if (Route::getCurrentRoute()->getName() == "conteudo.store") {
        $rules += [
            "archive_highlight" => "required|max:20000|mimes:jpg,jpeg,png,gif,webp",
        ];
    }
    break;

case 'super-banners':
    $rules = [
        "title" => "required|max:120",
        "category_contents_id" => "required|numeric",
        "order" => "required",
    ];

    if (Route::getCurrentRoute()->getName() == "conteudo.store") {
        $rules += [
            "archive_highlight" => "required|max:20000|mimes:jpg,jpeg,png,gif,webp",
        ];
    }
    break;
```

Observações:

| Campo | `banners` | `super-banners` |
|---|---|---|
| `title` | obrigatório, máx. 120 | obrigatório, máx. 120 |
| `category_contents_id` | obrigatório, numérico | obrigatório, numérico |
| `link` | **obrigatório**, máx. 2999 | **não validado** (presente no formulário) |
| `order` | obrigatório | obrigatório |
| `archive_highlight` | obrigatório **apenas no create** | obrigatório **apenas no create** |

- A validação condicional usa `Route::getCurrentRoute()->getName()` — acoplamento
  direto com o nome da rota dentro do Form Request.
- `status` e `isBlank` **não** têm regra para banners/super-banners (existe para outras
  categorias, como `transmissoes`).
- `authorize()` retorna `true`.

## 5. Datatables

```php
// v6/app/Http/Controllers/Prefecture/DatatableController.php:204-214
public function get_banners()
{
    $banners = DB::table('banners')->get();
    return DataTables::of($this->struct_views($banners, 'banners'))->make(true);
}

public function get_super_banners()
{
    $superbanners = DB::table('super_banners')->get();
    return DataTables::of($this->struct_views($superbanners, 'super-banners'))->make(true);
}
```

`struct_views` (`:504`) injeta por linha: `edit`, `delete`, `active`, `inactivate` —
todos derivados de `has_access("<slug>.<ação>")`.

| Grid | Slug de permissão | Colunas |
|---|---|---|
| `banners` | `banners` | `titulo`, `status_name`, ações |
| `super_banners` | `super-banners` | `titulo`, `posicao`, `status_name`, ações |

## 6. Permissões

| Recurso | Slug | Tabela |
|---|---|---|
| Módulo | `banners` | `modulos` (id 22, `status = 1`) |
| Item de menu | `banners` | `menu_orders` (id 15) |
| Recurso "Banners" | `banners` | `resources` (id 25) |
| Recurso "Super Banners" | `super-banners` | `resources` (id 26) |

Uso no código:

- `has_access(['banners.create'])`, `has_access(['banners.delete'])` — botões da lista
  (`v6/resources/views/prefecture/contents/banners/index.blade.php`).
- `has_access(['super-banners.create'])`, `has_access(['super-banners.delete'])` — lista
  de super banners.
- `has_access('super-banners.index')` — decide se o submenu "Super Banners" aparece
  (`v6/app/Providers/MenuServiceProvider.php:258`).
- No portal, `isset($modulos['banners']) && $modulos['banners']` controla a exibição
  dos banners laterais.

## 7. Menu do CMS

```php
// v6/app/Providers/MenuServiceProvider.php:253-263
case 'banners':
    $sub_ban = [
        '',
        ['text' => 'Banners Laterais', 'url' => '/cms/conteudos/banners',  'icon' => 'list-ul'],
    ];
    if (has_access('super-banners.index')) {
        array_push($sub_ban, ['text' => 'Super Banners', 'url' => '/cms/conteudos/super-banners',  'icon' => 'list-ul']);
    }
    $event->menu->add([
        'text' => 'Banners', 'icon' => 'map-signs',
        // trecho omitido do código original
```

## 8. Recursos de API

Não há `ApiResource` nem endpoint JSON para banners. A resposta de `ajustOrder` é
`response()->json(true)`.
