---
name: perfex-views
description: Views e templates para módulos Perfex CRM — init_head(), init_tail(), views admin e cliente, passagem de dados. Baseado apenas na documentação oficial.
---

# /perfex-views - Views Perfex CRM

Sistema de views e templates para módulos. **Zero assumptions, zero hallucinations** - apenas documentação oficial.

---

## Documentação Base

- [Module Views](https://help.perfexcrm.com/module-views/)
- [CodeIgniter Views](https://codeigniter.com/userguide3/general/views.html)

---

## Estrutura de Pastas

```
modules/meu_modulo/
└── views/
    ├── index.php           # Lista principal
    ├── form.php            # Formulário create/edit
    ├── view.php            # Detalhe
    ├── client_index.php    # Lista cliente
    ├── client_view.php     # Detalhe cliente
    ├── partials/
    │   ├── _table.php      # Partial tabela
    │   └── _filters.php    # Partial filtros
    └── widgets/
        └── dashboard.php   # Widget dashboard
```

---

## Views Admin (Área Staff)

### Template Base Admin

```php
<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
<?php init_head(); ?>

<div id="wrapper">
    <div class="content">
        <div class="row">
            <div class="col-md-12">
                <div class="panel_s">
                    <div class="panel-body">

                        <!-- CONTEÚDO AQUI -->
                        <h4><?php echo _l('meu_modulo_title'); ?></h4>

                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<?php init_tail(); ?>
</body>
</html>
```

### Funções Essenciais

| Função | Descrição |
|--------|-----------|
| `init_head()` | Inclui header, sidebar, CSS, meta tags |
| `init_tail()` | Inclui footer, JavaScript, fecha documento |

---

## Carregar Views

### No Controller

```php
// Básico
$this->load->view('form');

// Com dados
$data = [
    'item' => $item,
    'clients' => $clients,
];
$this->load->view('form', $data);

// Retornar como string (não fazer echo)
$html = $this->load->view('partial', $data, true);
```

### Fora de Controllers (Helpers, Classes)

```php
function meu_modulo_render_widget()
{
    $CI = &get_instance();
    $CI->load->view('meu_modulo/widgets/dashboard');
}

// Com dados
function meu_modulo_render_table($items)
{
    $CI = &get_instance();
    $CI->load->view('meu_modulo/partials/_table', ['items' => $items]);
}
```

---

## Views Cliente (Área Cliente)

### No Controller (ClientsController)

```php
public function index()
{
    $this->data([
        'items' => $items,
        'title' => 'Meu Módulo',
    ]);
    $this->title(_l('meu_modulo_title'));
    $this->view('client_index');
    $this->layout(); // Aplica tema do cliente
}
```

### Template Base Cliente

```php
<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>

<div class="panel_s">
    <div class="panel-body">
        <h4 class="no-margin"><?php echo _l('meu_modulo_title'); ?></h4>
        <hr class="hr-panel-heading" />

        <!-- CONTEÚDO -->
        <?php foreach ($items as $item): ?>
            <p><?php echo html_escape($item->name); ?></p>
        <?php endforeach; ?>

    </div>
</div>
```

---

## Exemplos Completos

### Lista com Tabela (Admin)

```php
<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
<?php init_head(); ?>

<div id="wrapper">
    <div class="content">
        <div class="row">
            <div class="col-md-12">
                <div class="panel_s">
                    <div class="panel-body">

                        <div class="_buttons">
                            <?php if (staff_can('create', 'meu_modulo')): ?>
                                <a href="<?php echo admin_url('meu_modulo/create'); ?>"
                                   class="btn btn-primary pull-left">
                                    <i class="fa fa-plus"></i>
                                    <?php echo _l('new_item'); ?>
                                </a>
                            <?php endif; ?>
                        </div>

                        <div class="clearfix"></div>
                        <hr class="hr-panel-heading" />

                        <table class="table table-striped dt-table">
                            <thead>
                                <tr>
                                    <th><?php echo _l('id'); ?></th>
                                    <th><?php echo _l('name'); ?></th>
                                    <th><?php echo _l('created_at'); ?></th>
                                    <th><?php echo _l('options'); ?></th>
                                </tr>
                            </thead>
                            <tbody>
                                <?php foreach ($items as $item): ?>
                                <tr>
                                    <td><?php echo $item->id; ?></td>
                                    <td><?php echo html_escape($item->name); ?></td>
                                    <td><?php echo _dt($item->created_at); ?></td>
                                    <td>
                                        <?php if (staff_can('edit', 'meu_modulo')): ?>
                                            <a href="<?php echo admin_url('meu_modulo/edit/' . $item->id); ?>"
                                               class="btn btn-default btn-icon">
                                                <i class="fa fa-pencil"></i>
                                            </a>
                                        <?php endif; ?>

                                        <?php if (staff_can('delete', 'meu_modulo')): ?>
                                            <a href="<?php echo admin_url('meu_modulo/delete/' . $item->id); ?>"
                                               class="btn btn-danger btn-icon _delete">
                                                <i class="fa fa-trash"></i>
                                            </a>
                                        <?php endif; ?>
                                    </td>
                                </tr>
                                <?php endforeach; ?>
                            </tbody>
                        </table>

                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<?php init_tail(); ?>
<script>
$(function(){
    // DataTables já inicializado via classe dt-table

    // Confirmação delete
    $('._delete').on('click', function(e){
        return confirm('<?php echo _l('confirm_delete'); ?>');
    });
});
</script>
</body>
</html>
```

### Formulário (Admin)

```php
<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
<?php init_head(); ?>

<div id="wrapper">
    <div class="content">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                <div class="panel_s">
                    <div class="panel-body">

                        <h4>
                            <?php echo isset($item) ? _l('edit') : _l('create'); ?>
                            <?php echo _l('meu_modulo_item'); ?>
                        </h4>
                        <hr class="hr-panel-heading" />

                        <?php
                        $action = isset($item)
                            ? admin_url('meu_modulo/edit/' . $item->id)
                            : admin_url('meu_modulo/create');
                        echo form_open($action);
                        ?>

                            <div class="form-group">
                                <label for="name" class="control-label">
                                    <?php echo _l('name'); ?>
                                    <span class="text-danger">*</span>
                                </label>
                                <input type="text"
                                       id="name"
                                       name="name"
                                       class="form-control"
                                       value="<?php echo isset($item) ? html_escape($item->name) : ''; ?>"
                                       required>
                            </div>

                            <div class="form-group">
                                <label for="description" class="control-label">
                                    <?php echo _l('description'); ?>
                                </label>
                                <textarea id="description"
                                          name="description"
                                          class="form-control"
                                          rows="4"><?php echo isset($item) ? html_escape($item->description) : ''; ?></textarea>
                            </div>

                            <div class="form-group">
                                <label for="client_id" class="control-label">
                                    <?php echo _l('client'); ?>
                                </label>
                                <select id="client_id" name="client_id" class="selectpicker"
                                        data-live-search="true" data-width="100%">
                                    <option value=""><?php echo _l('select'); ?></option>
                                    <?php foreach ($clients as $client): ?>
                                        <option value="<?php echo $client['userid']; ?>"
                                            <?php echo (isset($item) && $item->client_id == $client['userid']) ? 'selected' : ''; ?>>
                                            <?php echo html_escape($client['company']); ?>
                                        </option>
                                    <?php endforeach; ?>
                                </select>
                            </div>

                            <div class="btn-bottom-toolbar text-right">
                                <button type="submit" class="btn btn-primary">
                                    <?php echo _l('save'); ?>
                                </button>
                                <a href="<?php echo admin_url('meu_modulo'); ?>" class="btn btn-default">
                                    <?php echo _l('cancel'); ?>
                                </a>
                            </div>

                        <?php echo form_close(); ?>

                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<?php init_tail(); ?>
<script>
$(function(){
    // Validação formulário
    appValidateForm($('form'), {
        name: {
            required: true,
            minlength: 3
        }
    });
});
</script>
</body>
</html>
```

---

## Helpers de Output

### Escape HTML (OBRIGATÓRIO para dados user)

```php
// SEMPRE usar para dados de utilizador
echo html_escape($item->name);

// Para atributos HTML
echo html_escape($item->url, true);
```

### Formatação de Datas

```php
// Data formatada (configuração do sistema)
echo _d($item->date);           // 25-01-2026

// Data e hora
echo _dt($item->created_at);    // 25-01-2026 14:30
```

### Formatação de Valores

```php
// Moeda
echo app_format_money($item->amount, $currency);

// Número
echo app_format_number($item->quantity);
```

### Tradução

```php
// String de tradução
echo _l('meu_modulo_title');

// Com placeholder
echo _l('item_created_by', $staff_name);
```

---

## Classes CSS Disponíveis

### Painéis

```html
<div class="panel_s">
    <div class="panel-body">
        <!-- Conteúdo -->
    </div>
</div>
```

### Tabelas

```html
<!-- Tabela com DataTables -->
<table class="table table-striped dt-table">

<!-- Tabela simples -->
<table class="table table-bordered">
```

### Botões

```html
<a class="btn btn-primary">Primary</a>
<a class="btn btn-success">Success</a>
<a class="btn btn-warning">Warning</a>
<a class="btn btn-danger">Danger</a>
<a class="btn btn-default">Default</a>

<!-- Botão ícone -->
<a class="btn btn-default btn-icon"><i class="fa fa-edit"></i></a>
```

### Ícones (Font Awesome 4)

```html
<i class="fa fa-plus"></i>
<i class="fa fa-edit"></i>
<i class="fa fa-trash"></i>
<i class="fa fa-search"></i>
<i class="fa fa-check"></i>
```

---

## Anti-Patterns (NUNCA FAZER)

| Anti-Pattern | Risco | Alternativa |
|--------------|-------|-------------|
| Echo dados sem escape | XSS | `html_escape()` sempre |
| Não usar form_open() | CSRF vulnerável | Usar form_open() |
| SQL em views | Má arquitectura | Preparar no controller |
| Esquecer init_head/tail | Layout quebrado | Incluir sempre (admin) |
| Hardcode strings | Não traduzível | Usar `_l()` |

---

## Checklist View

```
1. [ ] defined('BASEPATH') no topo
2. [ ] init_head() e init_tail() (admin)
3. [ ] $this->layout() (cliente)
4. [ ] html_escape() em todos os dados user
5. [ ] form_open() para formulários
6. [ ] Permissões verificadas antes de mostrar botões
7. [ ] _l() para todas as strings
8. [ ] Classes CSS standard do Perfex
```

---

**Versão:** 1.0.0 | **Autor:** Descomplicar®
**Fonte:** help.perfexcrm.com/module-views

---

## Healing Log

Registo de erros conhecidos e como evitá-los. Lido automaticamente antes de executar.

```jsonl
{"date":"","issue":"","fix":"","source":"user|auto"}
```

*Adicionar nova linha após cada erro corrigido.*
