# Facades System - Framework OfficeGest

> **Nível**: Básico a Avançado  
> **Pré-requisitos**: Conhecimento de PHP, OOP e Container DI  
> **Tempo de leitura**: ~15 minutos

---

## 📋 Índice

1. [Introdução](#introdução)
2. [Quick Start](#quick-start)
3. [Arquitectura e Estrutura](#arquitectura-e-estrutura)
4. [Todas as Facades](#todas-as-facades)
5. [Classe Base Facade](#classe-base-facade)
6. [Criar uma Facade](#criar-uma-facade)
7. [Testing com Facades](#testing-com-facades)
8. [Exemplos Práticos](#exemplos-práticos)
9. [Boas Práticas](#boas-práticas)
10. [Troubleshooting](#troubleshooting)
11. [Referência de API](#referência-de-api)

---

## Introdução

### O que é uma Facade?

Uma **Facade** é um padrão de design que fornece uma interface estática simples para serviços complexos do container de DI. Em vez de:

```php
// Sem Facade - verboso
$container = Container::getInstance();
$cache = $container->get('cache');
$value = $cache->get('key');
```

Usamos:

```php
// Com Facade - limpo e elegante
$value = Cache::get('key');
```

### Vantagens das Facades

| Aspecto | Sem Facade | Com Facade |
|---------|------------|------------|
| **Sintaxe** | Verbosa | Concisa |
| **Testabilidade** | Manual mocking | `spy()`, `mock()` built-in |
| **IDE Support** | Limitado | PHPDoc completo |
| **Flexibilidade** | Acoplado | Serviço trocável via container |

### Como Funcionam?

```mermaid
sequenceDiagram
    participant Code as Código
    participant Facade as Cache Facade
    participant Container as Container DI
    participant Service as CacheManager
    
    Code->>Facade: Cache::get('key')
    Facade->>Facade: __callStatic('get', ['key'])
    Facade->>Facade: getFacadeAccessor() → 'cache'
    Facade->>Container: get('cache')
    Container-->>Facade: CacheManager instance
    Facade->>Service: get('key')
    Service-->>Code: valor
```

---

## Quick Start

### 🚀 Usar Facades em 1 Minuto

```php
use Og\Modules\Common\Facades\Cache;
use Og\Modules\Common\Facades\Auth;
use Og\Modules\Common\Facades\Queue;
use Og\Modules\Common\Facades\Http;

// CACHE - armazenar e recuperar dados
Cache::put('user:1', $userData, 60);
$user = Cache::get('user:1');

// AUTH - verificar utilizador
if (Auth::check()) {
    $userId = Auth::id();
    $canEdit = Auth::can('posts:edit');
}

// QUEUE - enviar jobs para background
Queue::dispatch(new SendEmailJob($user));

// HTTP - fazer requests externos
$response = Http::get('https://api.example.com/users');
```

### Import Múltiplo

```php
use Og\Modules\Common\Facades\{
    Auth,
    Cache,
    Queue,
    Http,
    Route,
    View,
    File,
    Notification,
    Request,
    Response
};
```

---

## Arquitectura e Estrutura

### Estrutura de Ficheiros

```
Modules/Common/
├── Utils/
│   └── Facade.php              # Classe base abstrata
└── Facades/
    ├── Auth.php                # Autenticação básica
    ├── Cache.php               # Sistema de cache
    ├── File.php                # Sistema de ficheiros
    ├── Http.php                # Cliente HTTP (Guzzle)
    ├── Notification.php        # Notificações multi-canal
    ├── Queue.php               # Sistema de filas
    ├── QueueJobLock.php        # Gestão de locks de jobs
    ├── Request.php             # Request HTTP actual
    ├── Response.php            # Response HTTP
    ├── Route.php               # Definição de rotas
    └── View.php                # Engine de templates

Modules/Common/Guard/
    └── GuardFacade.php         # Autenticação avançada (tokens)
```

### Diagrama de Componentes

```mermaid
graph TB
    subgraph "Facades (Interface Estática)"
        F1[Auth]
        F2[Cache]
        F3[Queue]
        F4[Http]
        F5[Route]
        F6[...]
    end
    
    subgraph "Classe Base"
        FB[Facade.php]
    end
    
    subgraph "Container DI"
        C[Container::getInstance]
    end
    
    subgraph "Serviços Reais"
        S1[AuthManager]
        S2[CacheManager]
        S3[QueueManager]
        S4[HttpClient]
        S5[RouterCollector]
    end
    
    F1 --> FB
    F2 --> FB
    F3 --> FB
    F4 --> FB
    F5 --> FB
    FB --> C
    C --> S1
    C --> S2
    C --> S3
    C --> S4
    C --> S5
```

---

## Todas as Facades

### 📋 Tabela Completa (11 Facades)

| Facade | Accessor | Serviço | Uso Principal |
|--------|----------|---------|---------------|
| `Auth` | `'auth'` | AuthManager | Verificar utilizador e permissões |
| `Cache` | `'cache'` | CacheManager | Cache distribuído |
| `File` | `Filesystem::class` | Filesystem | Operações de ficheiros |
| `Http` | `'http-client'` | HttpClient | Requests HTTP externos |
| `Notification` | `NotificationService::class` | NotificationService | Email, SMS, Push |
| `Queue` | `QueueManagerInterface::class` | QueueManager | Jobs em background |
| `QueueJobLock` | `JobLockManagerInterface::class` | JobLockManager | Locks de jobs |
| `Request` | `'request'` | Request | Dados do request actual |
| `Response` | `'response'` | Response | Construir responses |
| `Route` | `RouterClass::class` | RouterCollector | Definir rotas |
| `View` | `'view'` | ViewFactory | Renderizar templates |
| `GuardFacade` | `'guard'` | GuardManager | Tokens e SPA auth |

---

### Auth

**Accessor:** `'auth'`

```php
use Og\Modules\Common\Facades\Auth;

// Verificar se está logado
if (Auth::check()) {
    $user = Auth::user();     // Obter utilizador
    $id = Auth::id();         // Obter ID
}

// Verificar permissões
if (Auth::can('invoices:create')) {
    // Tem permissão
}
```

---

### Cache

**Accessor:** `'cache'`

```php
use Og\Modules\Common\Facades\Cache;

// Operações básicas
Cache::put('key', $value, 60);        // Guardar por 60s
$value = Cache::get('key');            // Recuperar
Cache::forget('key');                  // Remover
Cache::clearAll();                     // Limpar tudo

// Remember pattern (cache inteligente)
$data = Cache::remember('expensive', 300, function() {
    return $this->heavyQuery();
});

// Verificação
if (Cache::has('key')) { ... }

// Gestão de prefixos (multi-tenant)
Cache::replacePrefix('tenant:123:');
$keys = Cache::keys('user:*');
```

---

### Http

**Accessor:** `'http-client'`

```php
use Og\Modules\Common\Facades\Http;

// GET request
$response = Http::get('https://api.example.com/users');

// POST com dados
$response = Http::post('https://api.example.com/users', [
    'name' => 'João',
    'email' => 'joao@email.com',
]);

// Com headers
$response = Http::withHeaders([
    'Authorization' => 'Bearer ' . $token,
])->get('https://api.example.com/protected');

// Basic Auth
$response = Http::withBasicAuth('user', 'pass')
    ->get('https://api.example.com/data');

// Base URL
$response = Http::baseUrl('https://api.example.com')
    ->get('/users');

// Sem verificar SSL (desenvolvimento)
$response = Http::withoutVerifying()
    ->get('https://localhost:8443/api');
```

---

### Queue

**Accessor:** `QueueManagerInterface::class`

```php
use Og\Modules\Common\Facades\Queue;

// Dispatch simples
Queue::dispatch(new SendEmailJob($user));

// Com delay
Queue::later(now()->addMinutes(5), new ReminderJob());

// Batch de jobs
Queue::batch([
    new ProcessJob($item1),
    new ProcessJob($item2),
    new ProcessJob($item3),
]);

// Chain de jobs (sequencial)
Queue::chain([
    new ImportDataJob(),
    new ValidateDataJob(),
    new GenerateReportJob(),
]);

// Gestão de queue
$count = Queue::size('emails');   // Jobs pendentes
Queue::clear('failed');           // Limpar queue

// Controlo de worker
Queue::stop();                    // Parar worker
if (Queue::shouldStop()) { ... }
```

---

### QueueJobLock

**Accessor:** `JobLockManagerInterface::class`

```php
use Og\Modules\Common\Facades\QueueJobLock;

// Verificar se job já está a correr
if (QueueJobLock::hasJobLock(MyJob::class, 'user:1', $companyId)) {
    return; // Já está a processar
}

// Adquirir lock
$locked = QueueJobLock::acquireJobLock(
    MyJob::class, 
    'user:1', 
    $companyId, 
    ttl: 60
);

// Libertar lock
QueueJobLock::releaseJobLock(MyJob::class, 'user:1', $companyId);

// Info do lock
$info = QueueJobLock::getJobLockInfo(MyJob::class, 'key', $companyId);
```

---

### File

**Accessor:** `Filesystem::class`

```php
use Og\Modules\Common\Facades\File;

// Ler/Escrever ficheiros
$content = File::get('/path/to/file.txt');
File::put('/path/to/file.txt', $content);

// Verificar existência
if (File::fileExists('/path/to/file.txt')) { ... }

// Eliminar
File::delete('/path/to/file.txt');

// Directórios
File::makeDirectory('/path/to/dir', 0755, true);
File::ensureDirectoryExists('/path/to/dir');
```

---

### Route

**Accessor:** `RouterClass::class`

```php
use Og\Modules\Common\Facades\Route;

// Rotas básicas
Route::get('/users', [UserController::class, 'index']);
Route::post('/users', [UserController::class, 'store']);
Route::put('/users/{id}', [UserController::class, 'update']);
Route::delete('/users/{id}', [UserController::class, 'destroy']);

// Com nome
Route::get('/dashboard', [DashboardController::class, 'index'])
    ->name('dashboard');

// Controller group
Route::controller(InvoiceController::class)->group(function() {
    Route::get('/invoices', 'index');
    Route::post('/invoices', 'store');
});
```

---

### Notification

**Accessor:** `NotificationService::class`

```php
use Og\Modules\Common\Facades\Notification;

// Enviar notificação
Notification::send([
    'to' => $user->email,
    'subject' => 'Bem-vindo!',
    'template' => 'welcome',
    'data' => ['user' => $user],
]);

// Usar canal específico
Notification::using('sms')->send([
    'to' => $user->phone,
    'message' => 'Código: 123456',
]);
```

---

### GuardFacade

**Accessor:** `'guard'`

```php
use Og\Modules\Common\Guard\GuardFacade as Guard;

// Autenticação
$user = Guard::user();
$token = Guard::token();

// Criar tokens
$token = Guard::createToken($userId, 'api-token');
$spaToken = Guard::createSpaToken($userId);

// Login
$token = Guard::loginForSpa($credentials);
Guard::logout();

// Gestão de tokens
$tokens = Guard::tokens();
Guard::revokeCurrentToken();
Guard::revokeAllTokens();
Guard::pruneExpiredTokens();

// Verificar abilities
if (Guard::tokenCan('read:users')) { ... }
```

---

## Classe Base Facade

### Localização

`Modules/Common/Utils/Facade.php`

### Estrutura

```php
abstract class Facade
{
    protected static array $resolvedInstances = [];  // Cache de instâncias
    protected static array $spyInstances = [];       // Mocks para testes
    
    // Método mágico que redireciona chamadas
    public static function __callStatic($method, $args)
    {
        $instance = static::getFacadeRoot();
        return $instance->$method(...$args);
    }
    
    // Cada facade implementa este método
    protected static function getFacadeAccessor()
    {
        throw new RuntimeException('Implement getFacadeAccessor()');
    }
}
```

### Métodos Importantes

| Método | Descrição |
|--------|-----------|
| `getFacadeRoot()` | Obtém a instância real do serviço |
| `getFacadeAccessor()` | Retorna o nome do binding no container |
| `swap($instance)` | Substituir instância (testes) |
| `spy()` | Criar spy (Mockery) |
| `mock()` | Criar mock (Mockery) |
| `partialMock()` | Criar partial mock |
| `shouldReceive()` | Setup de expectation |
| `clearResolvedInstances()` | Limpar cache |

---

## Criar uma Facade

> Os exemplos abaixo são **código real** extraído das Facades do OfficeGest.

### 🎯 Exemplo Real 1: Auth Facade (Simples)

**Localização:** `Modules/Common/Facades/Auth.php`

```php
<?php

namespace Og\Modules\Common\Facades;

use Og\Modules\Common\Utils\Facade;

/**
 * @method static user()
 * @method static id()
 * @method static check()
 * @method static can(string $permission)
 * @method static isImpersonating()
 */
class Auth extends Facade
{
    public static function getFacadeAccessor(): string
    {
        return 'auth';  // String - resolvido do container
    }
}
```

**Pontos de interesse:**
- PHPDoc documenta métodos disponíveis para IDE
- Accessor é string `'auth'` → resolve para `AuthManager`

---

### 🎯 Exemplo Real 2: Queue Facade (Com Interface)

**Localização:** `Modules/Common/Facades/Queue.php`

```php
<?php

namespace Og\Modules\Common\Facades;

use Og\Modules\Common\Queue\Contracts\JobInterface;
use Og\Modules\Common\Queue\Contracts\QueueManagerInterface;
use Og\Modules\Common\Queue\PendingChain;
use Og\Modules\Common\Queue\PendingDispatch;
use Og\Modules\Common\Queue\QueueManager;
use Og\Modules\Common\Utils\Facade;

/**
 * @method static PendingDispatch dispatch(JobInterface $job)
 * @method static PendingDispatch batch(array $jobs)
 * @method static string pushOn(string $queue, JobInterface $job)
 * @method static string later(\DateTime $delay, JobInterface $job)
 * @method static string pushRaw(string $payload, string $queue = null, array $options = [])
 * @method static void bulk(array $jobs)
 * @method static int size(string $queue = null)
 * @method static bool clear(string $queue = null)
 * @method static QueueManager driver(string $driver = null)
 * @method static void stop(bool $status = true)
 * @method static bool shouldStop()
 * @method static bool isDownForMaintenance()
 * @method static PendingChain chain(array $jobs)
 */
class Queue extends Facade
{
    protected static function getFacadeAccessor(): string
    {
        return QueueManagerInterface::class;  // Interface - auto-resolved
    }
}
```

**Pontos de interesse:**
- PHPDoc completo com tipos de retorno (`PendingDispatch`, `PendingChain`)
- Accessor é **interface** `QueueManagerInterface::class`
- Imports das classes usadas no PHPDoc

---

### 🎯 Exemplo Real 3: Http Facade (Com Métodos Estáticos Personalizados)

**Localização:** `Modules/Common/Facades/Http.php`

```php
<?php

namespace Og\Modules\Common\Facades;

use Og\Modules\Common\Utils\Facade;

/**
 * @method static withBasicAuth(string $username, string $password)
 * @method static withHeaders(array $headers)
 * @method static get(string $url, array $query = [])
 * @method static post(string $url, array $data = [])
 * @method static put(string $url, array $data = [])
 * @method static patch(string $url, array $data = [])
 * @method static delete(string $url, array $data = [])
 * @method static withoutVerifying()
 * @method static baseUrl(string $resolveHttpBaseUrl)
 */
class Http extends Facade
{
    public static function getFacadeAccessor(): string
    {
        return 'http-client';
    }

    // Método estático personalizado para testes
    public static function fake($callback = null)
    {
        return tap(static::getFacadeRoot(), function ($fake) use ($callback) {
            static::swap($fake->fake($callback));
        });
    }

    public static function fakeSequence(string $urlPattern = '*')
    {
        $fake = tap(static::getFacadeRoot(), function ($fake) {
            static::swap($fake);
        });
        return $fake->fakeSequence($urlPattern);
    }

    public static function preventStrayRequests($prevent = true)
    {
        return tap(static::getFacadeRoot(), function ($fake) use ($prevent) {
            static::swap($fake->preventStrayRequests($prevent));
        });
    }
}
```

**Pontos de interesse:**
- Métodos estáticos personalizados (`fake()`, `fakeSequence()`)
- Usa `static::swap()` para substituir a instância em testes
- `tap()` helper para fluent interface

---

### 🎯 Exemplo Real 4: GuardFacade (Autenticação Avançada)

**Localização:** `Modules/Common/Guard/GuardFacade.php`

```php
<?php

namespace Og\Modules\Common\Guard;

use Og\Modules\Common\Utils\Facade;

/**
 * Guard Facade - Autenticação com Tokens SPA/API
 *
 * @method static array|null user()
 * @method static PersonalAccessToken|null token()
 * @method static bool check()
 * @method static bool guest()
 * @method static int|null id()
 * @method static PersonalAccessToken createToken(int $userId, string $name, array $abilities = ['*'], int $expiresIn = null)
 * @method static PersonalAccessToken createSpaToken(int $userId, string $name = 'spa-token')
 * @method static bool revokeCurrentToken()
 * @method static bool revokeAllTokens()
 * @method static array tokens()
 * @method static bool tokenCan(string $ability)
 * @method static bool tokenCanAny(array $abilities)
 * @method static PersonalAccessToken|null loginForSpa(array $credentials)
 * @method static bool logout()
 * @method static int pruneExpiredTokens()
 * @method static attemptLogin(array $credentials)
 * @method static authenticate()
 * @method static can(string $permission)
 * @method static getTokenManager()
 */
class GuardFacade extends Facade
{
    protected static function getFacadeAccessor(): string
    {
        return 'guard';
    }
}
```

**Pontos de interesse:**
- PHPDoc extensivo (15+ métodos)
- Tipos de retorno específicos (`PersonalAccessToken`)
- Localização diferente (`Guard/` em vez de `Facades/`)

---

### Tipos de Accessor

```php
// String - serviço registado com nome
protected static function getFacadeAccessor(): string
{
    return 'cache';  // Container::get('cache')
}

// Classe - auto-resolved via reflection
protected static function getFacadeAccessor(): string
{
    return MyService::class;  // Container::make(MyService::class)
}
```

---

## Testing com Facades

### Spying

```php
use Og\Modules\Common\Facades\Cache;

test('cache is called', function() {
    Cache::spy();
    
    // Executar código que usa cache
    $service->process();
    
    // Verificar
    Cache::shouldHaveReceived('put')->once();
    Cache::shouldHaveReceived('get')->with('expected-key');
});
```

### Mocking

```php
test('mocked cache', function() {
    $mock = Cache::mock();
    $mock->shouldReceive('get')
        ->with('key')
        ->andReturn('mocked-value');
    
    $result = Cache::get('key');
    expect($result)->toBe('mocked-value');
});
```

### Partial Mock

```php
test('partial mock', function() {
    Cache::partialMock()
        ->shouldReceive('get')
        ->andReturn('partial-value');
    
    // get() está mockado, put() funciona normalmente
});
```

### Swap (Substituição Completa)

```php
test('with fake service', function() {
    Cache::swap(new FakeCacheManager());
    
    // Agora Cache usa FakeCacheManager
});
```

### Http Faking

```php
use Og\Modules\Common\Facades\Http;

test('api call', function() {
    Http::fake([
        'api.example.com/*' => Http::response(['data' => 'mocked'], 200),
    ]);
    
    $response = Http::get('https://api.example.com/users');
    expect($response->json()['data'])->toBe('mocked');
});
```

### Cleanup

```php
afterEach(function() {
    Facade::clearResolvedInstances();
});
```

---

## Exemplos Práticos de Uso

> Exemplos de uso real das Facades no código do OfficeGest.

### 🎯 Exemplo 1: Auth + Cache em Controller

```php
use Og\Modules\Common\Facades\Auth;
use Og\Modules\Common\Facades\Cache;

class ClienteController
{
    public function show(int $id)
    {
        // Verificar permissão usando Auth facade
        if (!Auth::can('entidades:clientes')) {
            return response()->json(['error' => 'Sem permissão'], 403);
        }
        
        // Verificar impersonation
        if (Auth::isImpersonating()) {
            loggerBatch('audit', "Admin está a ver cliente {$id} via impersonation");
        }
        
        // Cache com prefixo por tenant
        $cacheKey = "cliente:{$id}";
        
        $cliente = Cache::remember($cacheKey, 300, function() use ($id) {
            return Cliente::find($id);
        });
        
        if (!$cliente) {
            return response()->json(['error' => 'Cliente não encontrado'], 404);
        }
        
        return response()->json($cliente);
    }
    
    public function update(int $id, array $data)
    {
        // Atualizar cliente
        Cliente::update($id, $data);
        
        // Invalidar cache
        Cache::forget("cliente:{$id}");
        
        return response()->json(['success' => true]);
    }
}
```

---

### 🎯 Exemplo 2: Queue com Batch e Chain

```php
use Og\Modules\Common\Facades\Queue;

class FacturacaoService
{
    public function processarFacturasMensais(array $clientes): void
    {
        // Dispatch simples
        foreach ($clientes as $cliente) {
            Queue::dispatch(new GerarFacturaJob($cliente));
        }
    }
    
    public function enviarFacturasComAtraso(): void
    {
        // Batch - processar em lote
        $jobs = [];
        foreach (Factura::comAtraso()->get() as $factura) {
            $jobs[] = new EnviarReminderJob($factura);
        }
        
        Queue::batch($jobs);
    }
    
    public function processamentoCompleto(Factura $factura): void
    {
        // Chain - jobs em sequência
        Queue::chain([
            new ValidarFacturaJob($factura),
            new GerarPdfJob($factura),
            new EnviarEmailJob($factura),
            new NotificarClienteJob($factura),
        ]);
    }
    
    public function verificarEstadoQueue(): array
    {
        return [
            'pendentes' => Queue::size('facturas'),
            'emails'    => Queue::size('emails'),
            'default'   => Queue::size(),
        ];
    }
}
```

---

### 🎯 Exemplo 3: Http para APIs Externas

```php
use Og\Modules\Common\Facades\Http;

class SaftService
{
    public function enviarParaAT(Factura $factura): array
    {
        // Request com headers
        $response = Http::withHeaders([
            'Authorization' => 'Bearer ' . $this->getToken(),
            'Content-Type'  => 'application/json',
        ])->post('https://api.at.gov.pt/faturas', $factura->toSaftArray());
        
        return $response->json();
    }
    
    public function verificarCertificado(): bool
    {
        // Request com Basic Auth
        $response = Http::withBasicAuth(
            config('saft.username'),
            config('saft.password')
        )->get('https://api.at.gov.pt/status');
        
        return $response->successful();
    }
    
    public function consultarNif(string $nif): ?array
    {
        // Base URL para múltiplos requests
        $client = Http::baseUrl('https://api.nif.pt/v2');
        
        $response = $client->get("/nif/{$nif}");
        
        if ($response->failed()) {
            return null;
        }
        
        return $response->json();
    }
}
```

---

### 🎯 Exemplo 4: GuardFacade para Autenticação SPA

```php
use Og\Modules\Common\Guard\GuardFacade as Guard;

class AuthController
{
    public function login(array $credentials)
    {
        // Login para SPA - retorna token
        $token = Guard::loginForSpa($credentials);
        
        if (!$token) {
            return response()->json(['error' => 'Credenciais inválidas'], 401);
        }
        
        return response()->json([
            'token' => $token->plainTextToken,
            'user'  => Guard::user(),
        ]);
    }
    
    public function logout()
    {
        Guard::revokeCurrentToken();
        
        return response()->json(['success' => true]);
    }
    
    public function profile()
    {
        // Verificar se está autenticado
        if (Guard::guest()) {
            return response()->json(['error' => 'Não autenticado'], 401);
        }
        
        return response()->json([
            'user'   => Guard::user(),
            'token'  => Guard::token(),
            'tokens' => Guard::tokens(),
        ]);
    }
    
    public function verificarPermissao(string $ability)
    {
        // Verificar ability do token
        if (!Guard::tokenCan($ability)) {
            return response()->json(['error' => 'Token sem permissão'], 403);
        }
        
        return response()->json(['allowed' => true]);
    }
    
    public function limparTokensExpirados()
    {
        // Manutenção - remover tokens expirados
        $removidos = Guard::pruneExpiredTokens();
        
        return response()->json(['removidos' => $removidos]);
    }
}

---

## Boas Práticas

### ✅ Use PHPDoc para IDE Support

```php
/**
 * @method static string process(array $data)
 * @method static bool validate(int $id)
 */
class MyFacade extends Facade
```

### ✅ Facades para Código de Aplicação

```php
// BOM - em controllers, commands, etc.
class MyController {
    public function index() {
        return Cache::get('data');
    }
}

// EVITAR - em classes de domínio (use DI)
class UserService {
    public function __construct(
        private CacheInterface $cache  // ✅ DI
    ) {}
}
```

### ✅ Limpar Instâncias em Testes

```php
afterEach(function() {
    Facade::clearResolvedInstances();
});
```

### ✅ Nomes de Accessor Consistentes

```php
// String para serviços core
return 'cache';
return 'auth';
return 'request';

// Classe para serviços específicos
return MyService::class;
return PaymentGateway::class;
```

---

## Troubleshooting

### Problema: "A facade root has not been set"

**Causa:** Serviço não está registado no container.

**Solução:**
```php
// Verificar se está registado
dd(app()->has('meu-servico'));

// Registar no Service Provider
$this->app->singleton('meu-servico', MyService::class);
```

### Problema: Método não encontrado

**Causa:** Método não existe no serviço real.

**Solução:**
```php
// Verificar serviço real
$service = app('cache');
dd(get_class_methods($service));
```

### Problema: Testes afetados por outros testes

**Causa:** Instâncias em cache.

**Solução:**
```php
afterEach(function() {
    Facade::clearResolvedInstances();
});
```

---

## Referência de API

### Facade (Classe Base)

```php
abstract class Facade
{
    // Chamada mágica
    public static function __callStatic($method, $args);
    
    // Resolução
    public static function getFacadeRoot();
    abstract protected static function getFacadeAccessor(): string;
    protected static function resolveFacadeInstance($name);
    public static function getFacadeApplication(): Container;
    
    // Testing
    public static function spy(): MockInterface;
    public static function mock(): MockInterface;
    public static function partialMock(): MockInterface;
    public static function shouldReceive(...$args): MockInterface;
    public static function swap($instance): void;
    
    // Lifecycle
    public static function clearResolvedInstances(): void;
    public static function clearResolvedInstance(string $name): void;
}
```

---

## Próximos Passos

- 📖 [Container System](./container-system.md) - Como o container resolve facades
- 📖 [Service Providers](./service-providers-system.md) - Registar serviços
- 📖 [Cache System](./cache-system.md) - Cache Facade em detalhe

---

*Última atualização: Dezembro 2024*
