# Routing System - Framework OfficeGest

> **Nível**: Intermédio a Avançado
> **Pré-requisitos**: Conhecimento de PHP, HTTP, MVC
> **Tempo de leitura**: ~20 minutos

---

## 📋 Índice

1. [Introdução](#introdução)
2. [CLI Commands](#cli-commands)
3. [Nomes de Rotas e "Dot Notation"](#nomes-de-rotas-e-dot-notation)
4. [Métodos HTTP e Parâmetros](#métodos-http-e-parâmetros)
5. [Route Helpers (Uso em Controllers)](#route-helpers-uso-em-controllers)
6. [Grupos e Organização](#grupos-e-organização)
7. [Cache de Rotas](#cache-de-rotas)
8. [Referência de API](#referência-de-api)

---

## Introdução

O sistema de rotas do OfficeGest é a porta de entrada da aplicação. Ele mapeia URLs amigáveis para Controllers e Actions, suportando gestão de middlewares, validação de parâmetros e agrupamento lógico.

O sistema moderno reside em `Modules/Common/Routing` e é inspirado nos frameworks mais robustos do mercado.

---

## CLI Commands

O framework fornece ferramentas de linha de comando para acelerar o desenvolvimento de rotas.

### Criar Ficheiros de Rotas
Em vez de criar ficheiros manualmente, use o comando `make:route`.

```bash
# Criar rotas API (Modules/Wmso/Routes/Api.php)
./og make:route Wmso --api

# Criar rotas Web (Modules/Wmso/Routes/Web.php)
./og make:route Wmso --web

# Criar para sub-módulo
./og make:route Workshop/Os --api
```

Este comando gera automaticamente a classe com o namespace correto e a estrutura básica (`implements RouterInterface`), prevenindo erros comuns de tipografia.

### Cache de Rotas
Para produção, é **crítico** usar o cache de rotas para performance.

```bash
# Compilar todas as rotas num ficheiro JSON otimizado
./og route:cache
```

O comando `route:cache` lê todos os ficheiros de rotas, resolve os grupos e middlewares, e guarda um mapa estático. O `RouterCollector` carrega este mapa instantaneamente, ignorando o processamento pesado de setup.

> **Nota:** Em desenvolvimento, o cache é ignorado ou reconstruído automaticamente se o ficheiro JSON não existir ou estiver desatualizado.

---

## Nomes de Rotas e "Dot Notation"

Uma das práticas mais importantes no nosso framework é o uso estrito de **"Dot Notation"** (notação por pontos) para nomear rotas.

### Por que usar `.` (ponto)?

1.  **Hierarquia Clara**: Reflete a estrutura da aplicação.
    *   Ex: `api.wmso.articles.show`
    *   [Contexto] . [Módulo] . [Recurso] . [Ação]
2.  **Matching com Wildcards**: Permite verificar grupos de rotas facilmente.
    *   `routeIs('api.wmso.*')` -> Verdadeiro para qualquer rota do WMSO.
    *   `routeIs('*.store')` -> Verdadeiro para qualquer acção de criação.
3.  **Unicidade Global**: Evita colisão de nomes entre módulos diferentes (ex: `articles.index` no WMSO vs `articles.index` no POS).

### Exemplo de Definição

```php
Route::name('api.')->group(function () {
    Route::name('wmso.')->group(function () {
        Route::name('articles.')->group(function () {
            // Nome final: api.wmso.articles.index
            Route::get('/', 'index')->name('index'); 
        });
    });
});
```

---

## Métodos HTTP e Parâmetros

### Verbos HTTP Disponíveis
O `Route` facade suporta todos os verbos padrão:

```php
Route::get($uri, $action);
Route::post($uri, $action);
Route::put($uri, $action);
Route::patch($uri, $action);
Route::delete($uri, $action);
```

### Parâmetros de Rota (`{param}`)

Parâmetros são definidos com chavetas `{}`. Eles são passados automaticamente para o método do Controller.

**Obrigatórios:**
```php
// Rota: /users/123
Route::get('/users/{id}', function ($id) {
    return "User ID: " . $id;
});
```

**Opcionais (`?`):**
```php
// Rota: /users ou /users/active
Route::get('/users/{status?}', function ($status = null) {
    return $status ? "Filtrando por $status" : "Todos os users";
});
```

> **Importante:** O nome do argumento na função/método **não precisa** coincidir com o nome na rota, mas a ordem importa se usar Closures. Em Controllers com injeção de dependência, o `RouterDispatcher` é inteligente o suficiente para mapear por nome ou tipo.

---

## Route Helpers (Uso em Controllers)

O trait `Og\Modules\Common\Http\Traits\RouteHelper` é incorporado no `Request` e disponibiliza métodos poderosos para "introspecção" da rota atual.

Se você está num Controller e injetou `Request $request`, tem acesso a estes métodos:

### 1. Verificar Nome da Rota (`routeIs`)

O método mais usado para lógica condicional (ex: marcar menu ativo no frontend ou validar permissões).

```php
public function index(Request $request) 
{
    // Verifica correspondência exata
    if ($request->routeIs('api.wmso.articles.index')) {
        // ...
    }

    // Verifica padrão (Wildcard)
    if ($request->routeIs('api.wmso.*')) {
        // Aplica lógica para todo o módulo WMSO
    }
}
```

### 2. Verificar URL (`is`)

Similar ao `routeIs`, mas verifica o caminho (path) da URL.

```php
if ($request->is('api/wmso/*')) {
    // URL começa por api/wmso/
}
```

### 3. Aceder a Parâmetros (`route`)

O método `route()` é polimórfico. Pode retornar o controller ou o valor de um parâmetro.

```php
// Obter valor de um parâmetro da URL (ex: /articles/{id})
$articleId = $request->route('id');

// Obter todos os parâmetros como array
$params = $request->routeParameters();
```

### 4. URL Helpers (`path`, `url`, `fullUrl`)

```php
// /api/articles?page=1

echo $request->path();      // "api/articles"
echo $request->url();       // "http://domain.com/api/articles"
echo $request->fullUrl();   // "http://domain.com/api/articles?page=1"
```

### 5. `segments()`

Retorna um array com os segmentos da URL.

```php
// URL: /api/wmso/articles/10
$segments = $request->segments(); 
// ['api', 'wmso', 'articles', '10']

$module = $request->segment(2); // 'wmso' (1-based index)
```

---

## Grupos e Organização

Use grupos para aplicar configurações compartilhadas (prefixo, middleware, controller, nome) a várias rotas.

### O Poder do `Route::controller()`

Agrupar por controller evita repetição e erros de importação.

```php
use Og\Modules\Wmso\Controllers\StockController;

Route::controller(StockController::class)->group(function () {
    // Não precisa repetir [StockController::class, 'method']
    Route::get('/stocks', 'index');
    Route::post('/stocks', 'store');
    Route::get('/stocks/{id}', 'show');
});
```

### Stack de Middlewares

Middlewares podem ser aplicados em cadeia.

```php
Route::middleware(['auth', 'throttle:60,1'])->group(function () {
    // Rotas protegidas e com rate limit
    Route::get('/profile', 'ProfileController@show');
});
```

---

## Referência Rápida

| Método Helper | Descrição | Exemplo |
| :--- | :--- | :--- |
| `routeIs($pattern)` | Verifica nome da rota | `$req->routeIs('*.store')` |
| `is($pattern)` | Verifica path da URL | `$req->is('api/*')` |
| `route($param)` | Obtém valor do parâmetro | `$req->route('id')` |
| `url()` | URL completa sem query | `http://site.com/foo` |
| `fullUrl()` | URL completa com query | `http://site.com/foo?q=bar` |

---

## Troubleshoot

**Erro: "Route [name] not defined"**
Verifique se definiu o `->name('...')` na rota. Lembre-se que se a rota está dentro de grupos com `name('prefix.')`, o nome final é a concatenação de todos. Use `./og route:list` (se disponível) ou faça `dd(RouterCollector::getInstance()->getRoutes())` para ver os nomes finais gerados.

**Erro: Parâmetro nulo**
Se `$request->route('id')` retornar nulo, certifique-se que definiu `{id}` na definição da rota. Parâmetros de query string (`?id=1`) não são parâmetros de rota; esses obtêm-se com `$request->input('id')`.
