# Sistema de Paginação - Framework OfficeGest

## Visão Geral do Sistema de Paginação

O sistema de paginação do OfficeGest é um componente simples e eficiente que fornece funcionalidades de paginação para resultados de queries de base de dados. O sistema é composto por uma única classe principal `Paginator` que encapsula a lógica de paginação e formatação de resultados.

Ao contrário de sistemas mais complexos que implementam múltiplos padrões de design, o sistema de paginação do OfficeGest adopta uma abordagem directa e pragmática, focada na simplicidade e performance.

## Arquitectura e Padrões de Design

### Padrões Implementados

**Data Transfer Object (DTO) Pattern**
A classe `Paginator` funciona essencialmente como um DTO que encapsula dados de paginação e fornece métodos de acesso estruturados.

**Serialization Pattern**
Implementa múltiplos formatos de serialização (Array, JSON, XML) através de métodos específicos.

**Template Method Pattern (Implícito)**
O método `links()` implementa um algoritmo fixo para geração de links de navegação.

## Estrutura e Componentes

### Classe Principal

#### `Paginator` (`Modules/Common/Pagination/Paginator.php`)

Classe principal que gere todos os aspectos da paginação de resultados.

**Propriedades:**
```php
protected array $items          // Items da página actual
protected int $total             // Total de registos
protected ?int $perPage          // Registos por página
protected ?int $currentPage      // Página actual
protected int $lastPage          // Última página (calculada)
```

**Métodos Públicos:**

- `__construct(array $items, int $total, ?int $perPage = null, ?int $currentPage = 1)`: Inicializa o paginator com dados e configuração
- `items(): array`: Retorna os items da página actual
- `total(): int`: Retorna o total de registos
- `perPage(): ?int`: Retorna o número de registos por página
- `currentPage(): ?int`: Retorna a página actual
- `lastPage(): int`: Retorna o número da última página
- `hasMorePages(): bool`: Verifica se existem mais páginas
- `links(): array`: Gera array de links de navegação
- `toArray(): array`: Serializa para array
- `toJson(): string`: Serializa para JSON
- `toXml(): string`: Serializa para XML

**Lógica de Cálculo:**
```php
$this->lastPage = (int) ceil($this->total / $this->perPage);
```

## Integração com Query Builder

### Método `paginate()` no OGDB_query_builder

O sistema integra-se com o Query Builder legacy através do método `paginate()` em `_files/database/DB_query_builder.php:1515`:

```php
public function paginate($perPage = null): array
{
    $request = Funcs::request();
    $perPage = $request->get('limit') ?? $perPage ?? config('pagination.per_page');
    $currentPage = max(1, (int) $request->get('page', 1));
    $offset = ($currentPage - 1) * $perPage;

    $total = $this->count_all_results('', false);
    $items = $this->limit($perPage, $offset)->get()->result();
    return (new Paginator($items, $total, $perPage, $currentPage))->toArray();
}
```

### Método `paginateDataTable()`

Versão especializada para DataTables que usa parâmetros específicos (`length` em vez de `limit`).

## Facades Disponíveis

**Nota:** Não existe facade específica para paginação. O sistema é utilizado directamente através da integração com o Query Builder ou instanciação directa da classe `Paginator`.

## Fluxo de Paginação

### 1. Inicialização via Query Builder
```php
// Através do Query Builder
$results = $this->db->table('users')->paginate(10);
```

### 2. Instanciação Directa
```php
// Instanciação manual
$paginator = new Paginator($items, $total, $perPage, $currentPage);
```

### 3. Processamento de Parâmetros
- Extrai `page` e `limit` do request
- Define valores por defeito via configuração
- Calcula offset automaticamente

### 4. Execução de Query
- Conta total de registos (`count_all_results()`)
- Executa query com `LIMIT` e `OFFSET`
- Encapsula resultados no `Paginator`

### 5. Geração de Output
- `toArray()`: Para APIs REST
- `toJson()`: Para respostas AJAX
- `toXml()`: Para integração com sistemas legacy
- `links()`: Para navegação web

## Configuração e Personalização

### Configurações Disponíveis

O sistema utiliza a configuração `pagination.per_page` como valor por defeito para registos por página.

### Formato dos Links

Os links gerados seguem o padrão:
```php
'?page=' . $i . '&limit=' . $this->perPage
```

### Estrutura de Resposta Padrão

```php
[
    'items' => [...],              // Dados da página actual
    'total' => 150,                // Total de registos
    'per_page' => 10,              // Registos por página
    'current_page' => 2,           // Página actual
    'last_page' => 15,             // Última página
    'has_more_pages' => true,      // Indica se há mais páginas
    'links' => [                   // Links de navegação
        ['page' => 1, 'url' => '?page=1&limit=10'],
        ['page' => 2, 'url' => '?page=2&limit=10'],
        // ...
    ]
]
```

## Exemplos de Uso Real

### Paginação Básica com Query Builder

```php
// Controllers ou Actions
$results = $this->db->select('*')
                   ->from('customers')
                   ->where('active', 1)
                   ->paginate(20);

return response()->json($results);
```

### Paginação Manual

```php
// Quando os dados já estão carregados
$allUsers = $this->userService->getAllUsers();
$total = count($allUsers);
$page = request()->get('page', 1);
$perPage = 10;

$items = array_slice($allUsers, ($page - 1) * $perPage, $perPage);
$paginator = new Paginator($items, $total, $perPage, $page);

return $paginator->toArray();
```

### Integração com DataTables

```php
// Para componentes DataTables
$results = $this->db->table('orders')
                   ->paginateDataTable(25);
```

## Considerações de Performance

### Optimizações Implementadas

1. **Lazy Calculation**: `lastPage` é calculada apenas no constructor
2. **Single Query Pattern**: Uma query para count, uma para dados
3. **Memory Efficient**: Não carrega todos os registos em memória
4. **Caching Ready**: Estrutura compatível com sistemas de cache

### Limitações Actuais

1. **Links Estáticos**: URLs geradas assumem estrutura query string simples
2. **No Advanced Navigation**: Não implementa navegação "Previous/Next"
3. **Fixed Link Generation**: Todos os links são gerados mesmo para grandes datasets

## Extensibilidade

### Como Estender o Sistema

Para personalizar o comportamento de paginação:

1. **Herdar da classe Paginator**:
```php
class CustomPaginator extends Paginator
{
    public function links(): array
    {
        // Implementação personalizada
    }
}
```

2. **Integração com Query Builder personalizado**:
```php
public function paginateCustom($perPage = null): array
{
    // Lógica personalizada
    return (new CustomPaginator($items, $total, $perPage, $currentPage))->toArray();
}
```

O sistema de paginação do OfficeGest demonstra a filosofia do framework: simplicidade, performance e integração harmoniosa entre componentes modernos e legacy.