# Service Providers System - Framework OfficeGest

> **Nível**: Intermédio a Avançado  
> **Pré-requisitos**: Conhecimento de PHP, OOP e Container DI  
> **Tempo de leitura**: ~18 minutos

---

## 📋 Índice

1. [Introdução](#introdução)
2. [Quick Start](#quick-start)
3. [Arquitectura e Estrutura](#arquitectura-e-estrutura)
4. [Criar um Service Provider](#criar-um-service-provider)
5. [Ciclo de Vida](#ciclo-de-vida)
6. [Providers do Sistema](#providers-do-sistema)
7. [Tipos de Bindings](#tipos-de-bindings)
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 são Service Providers?

**Service Providers** são classes responsáveis por registar serviços no Container de Dependency Injection. São o ponto central de configuração de toda a aplicação.

```php
// Em vez de criar serviços espalhados pelo código...
$database = new Database($config);
$cache = new Cache($redis);
$logger = new Logger($path);

// Service Providers centralizam tudo num só lugar:
class MyServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton('database', fn() => new Database($config));
        $this->app->singleton('cache', fn() => new Cache($redis));
        $this->app->singleton('logger', fn() => new Logger($path));
    }
}
```

### Por que usar Service Providers?

| Sem Providers | Com Providers |
|---------------|---------------|
| Configuração espalhada | Configuração centralizada |
| Difícil de testar | Fácil mock/swap |
| Acoplamento forte | Desacoplado via interfaces |
| Ordem manual | Ordem controlada |

### Duas Fases: Register e Boot

```mermaid
sequenceDiagram
    participant C as Container
    participant PM as ProviderManager
    participant P1 as Provider 1
    participant P2 as Provider 2
    
    Note over C,P2: Fase 1: REGISTER (Registo de bindings)
    C->>PM: register([Provider1, Provider2])
    PM->>P1: register()
    P1-->>PM: ✓ bindings registados
    PM->>P2: register()
    P2-->>PM: ✓ bindings registados
    
    Note over C,P2: Fase 2: BOOT (Inicialização)
    C->>PM: boot()
    PM->>P1: boot()
    P1-->>PM: ✓ inicializado
    PM->>P2: boot()
    P2-->>PM: ✓ inicializado
```

---

## Quick Start

### 🚀 Criar um Provider em 3 Passos

**1. Criar a classe:**

```php
<?php

namespace Og\Modules\MeuModulo\Providers;

use Og\Modules\Common\Providers\ServiceProvider;
use Og\Modules\MeuModulo\Services\MeuServico;
use Og\Modules\MeuModulo\Contracts\MeuServicoInterface;

class MeuModuloServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Registar serviços
        $this->app->singleton(MeuServicoInterface::class, function($app) {
            return new MeuServico(
                $app->get('database'),
                $app->get('config')
            );
        });
    }
    
    public function boot(): void
    {
        // Inicialização após todos os serviços registados
    }
}
```

**2. Registar no Container:**

```php
// Em Container.php:registerServiceProviders()
$this->providerManager->register([
    // ... outros providers
    MeuModuloServiceProvider::class,
]);
```

**3. Usar o serviço:**

```php
// Via container
$servico = app(MeuServicoInterface::class);

// Via DI no construtor
class MeuController {
    public function __construct(
        private MeuServicoInterface $servico
    ) {}
}
```

---

## Arquitectura e Estrutura

### Estrutura de Ficheiros

```
Modules/Common/Providers/
├── ServiceProvider.php              # Classe base abstracta
├── ServiceProviderInterface.php     # Interface (extensibilidade)
└── ServiceProviderManager.php       # Gestor de providers
```

### Diagrama de Componentes

```mermaid
graph TB
    subgraph "Container DI"
        C[Container]
        PM[ServiceProviderManager]
    end
    
    subgraph "Providers Base"
        SP[ServiceProvider]
        SPI[ServiceProviderInterface]
    end
    
    subgraph "Providers do Sistema (16)"
        P1[GlobalServiceProvider]
        P2[QueueServiceProvider]
        P3[CacheServiceProvider]
        P4[RoutingServiceProvider]
        P5[...]
    end
    
    C --> PM
    PM --> P1
    PM --> P2
    PM --> P3
    PM --> P4
    PM --> P5
    P1 --> SP
    P2 --> SP
    P3 --> SP
    SP --> SPI
```

### Classes Principais

#### ServiceProvider (Classe Base)

```php
abstract class ServiceProvider implements ServiceProviderInterface
{
    protected Container $app;           // Acesso ao container
    protected array $commands = [];     // Comandos CLI registados
    
    public function __construct(Container $app);
    
    public function register(): void;   // Fase 1: Registar bindings
    public function boot(): void;       // Fase 2: Inicialização
    
    protected function registerConsoleCommand(string $commandClass): void;
    public function getRegisteredCommands(): array;
}
```

#### ServiceProviderManager

```php
class ServiceProviderManager
{
    protected Container $app;
    protected array $providers = [];            // Providers registados
    private array $registeredProviders = [];    // Prevenir duplicados
    protected array $bootedProviders = [];      // Prevenir boot duplo
    private bool $booting = false;              // Flag de boot
    
    public function register(array|ServiceProvider $providers): void;
    public function boot(): void;
    protected function bootProvider(ServiceProvider $provider): void;
}
```

---

## Criar um Service Provider

### Estrutura Básica

```php
<?php

namespace Og\Modules\Pagamentos\Providers;

use Og\Modules\Common\Providers\ServiceProvider;

class PagamentosServiceProvider extends ServiceProvider
{
    /**
     * Fase 1: Registar bindings no container
     * 
     * ✅ Fazer: registar singletons, bindings, aliases
     * ❌ Não fazer: resolver dependências, inicializar serviços
     */
    public function register(): void
    {
        $this->app->singleton(PaymentGateway::class, function($app) {
            $config = $app->get('config')->get('payments');
            return new StripeGateway($config['api_key']);
        });
        
        $this->app->singleton(PaymentService::class, function($app) {
            return new PaymentService(
                $app->make(PaymentGateway::class),
                $app->get('database')
            );
        });
        
        $this->app->alias(PaymentService::class, 'payments');
    }
    
    /**
     * Fase 2: Inicialização após todos os providers registados
     * 
     * ✅ Fazer: registar eventos, middleware, rotas
     * ❌ Não fazer: trabalho pesado (lazy loading)
     */
    public function boot(): void
    {
        // Registar middleware
        $router = $this->app->get('router');
        $router->middleware('payment-auth', PaymentAuthMiddleware::class);
        
        // Registar eventos
        $events = $this->app->get('events');
        $events->listen(PaymentCompleted::class, SendReceipt::class);
    }
}
```

### Com Comandos CLI

```php
class MeuServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Registar serviços...
        
        // Registar comandos CLI
        $this->registerConsoleCommand(ImportDataCommand::class);
        $this->registerConsoleCommand(ExportDataCommand::class);
    }
}
```

---

## Ciclo de Vida

### Ordem de Execução (16 Providers)

Os providers são registados nesta ordem específica em `Container.php`:

```php
$this->providerManager->register([
    EventServiceProvider::class,        // 1. Sistema de eventos
    HelperServiceProvider::class,       // 2. Helpers globais
    ConfigServiceProvider::class,       // 3. Configuração
    QueueServiceProvider::class,        // 4. Sistema de filas
    RedisServiceProvider::class,        // 5. Conexões Redis
    CacheServiceProvider::class,        // 6. Sistema de cache
    HttpClientServiceProvider::class,   // 7. Cliente HTTP
    SaftPtServiceProvider::class,       // 8. SAFT Portugal
    SaftAoServiceProvider::class,       // 9. SAFT Angola
    ValidationServiceProvider::class,   // 10. Validação
    GlobalServiceProvider::class,       // 11. Bridge legacy ⚠️ CRÍTICO
    ViewServiceProvider::class,         // 12. Templates
    NotificationServiceProvider::class, // 13. Notificações
    RoutingServiceProvider::class,      // 14. Routing
    GuardServiceProvider::class,        // 15. Autenticação
    QueueMasterServiceProvider::class,  // 16. Queue Master
]);
```

### Por que esta Ordem?

| Grupo | Providers | Razão |
|-------|-----------|-------|
| **Infraestrutura** | Events, Helpers, Config, Redis | Base para tudo |
| **Core** | Queue, Cache, HTTP | Serviços usados por outros |
| **Externo** | SAFT PT/AO | Independentes |
| **Validação** | Validation | Antes de quem usa |
| **Legacy** | GlobalServiceProvider | Bridge $u, $a, $s |
| **Aplicação** | View, Notification, Routing | Dependem do legacy |
| **Segurança** | Guard | Após routing |

### Fluxo Completo

```mermaid
graph TB
    A[bootstrap.php] --> B[Container::getInstance]
    B --> C[new Container]
    C --> D[registerGlobalConfig]
    D --> E[registerBindings]
    E --> F[registerServiceProviders]
    F --> G[FASE 1: register de cada provider]
    G --> H[Container pronto mas não booted]
    H --> I[container->boot]
    I --> J[FASE 2: boot de cada provider]
    J --> K[Sistema completamente funcional]
```

---

## Providers do Sistema

### GlobalServiceProvider (Crítico ⚠️)

**O provider mais importante** - bridge entre sistema moderno e legacy.

```php
// Serviços registados:
'database'       → DatabaseConnector ($GLOBALS['db'])
'app'            → Aplication ($GLOBALS['a'])
'user'           → User ($GLOBALS['u'])
'session'        → Session ($GLOBALS['s'])
'email'          → Email ($GLOBALS['mail'])
'hooks'          → Hooks ($GLOBALS['hooks'])
'auth'           → AuthManager
'language'       → Language
'support-tables' → TabelasDeApoio
'printer'        → Printer
'message-center' → CentroMensagens
'rest-client'    → RestClient
'attachments'    → Attachments
'stocks'         → Stocks
'store'          → Loja atual
```

### QueueServiceProvider

```php
// Serviços registados:
QueueConfig::class
QueueManagerInterface::class → QueueManager
Dispatcher::class
SerializerInterface::class → JsonSerializer
BatchStateManagerInterface::class
ChainStateManagerInterface::class
JobLockManagerInterface::class
DeadLetterQueueInterface::class
QueueMonitorInterface::class
```

### CacheServiceProvider

```php
// Serviços registados:
'cache.driver.redis' → RedisDriver
'cache'              → Cache
```

### RoutingServiceProvider

```php
// Serviços registados:
'router'           → RouterCollector
'router.collector' → RouterCollector::getInstance()
'url'              → URL generator
'route.cache'      → RouteCache
'middleware'       → MiddlewareManager
```

### Outros Providers

| Provider | Serviços Principais |
|----------|---------------------|
| `RedisServiceProvider` | `redis`, `redis.manager` |
| `ValidationServiceProvider` | Sistema de validação |
| `ViewServiceProvider` | `view`, template engine |
| `NotificationServiceProvider` | `notification`, multi-canal |
| `HttpClientServiceProvider` | `http-client`, Guzzle wrapper |
| `GuardServiceProvider` | `guard`, tokens, SPA auth |
| `HelperServiceProvider` | Funções auxiliares globais |

---

## Tipos de Bindings

### Singleton (Instância Única)

```php
// Mesma instância sempre
$this->app->singleton('database', function($app) {
    return new DatabaseConnection($app->get('config'));
});

// Uso:
$db1 = app('database');
$db2 = app('database');
$db1 === $db2;  // true - mesma instância
```

### Bind (Nova Instância)

```php
// Nova instância a cada resolução
$this->app->bind(RequestHandler::class, function($app) {
    return new RequestHandler();
});

// Uso:
$h1 = app(RequestHandler::class);
$h2 = app(RequestHandler::class);
$h1 === $h2;  // false - instâncias diferentes
```

### Instance (Instância Existente)

```php
// Registar instância já criada
$user = new User($id);
$this->app->instance('current-user', $user);
```

### Alias

```php
// Nome alternativo para um binding
$this->app->singleton(DatabaseConnection::class, ...);
$this->app->alias(DatabaseConnection::class, 'db');

// Ambos resolvem o mesmo:
app(DatabaseConnection::class);
app('db');
```

### Interface → Implementação

```php
// Bind interface para implementação concreta
$this->app->bind(
    PaymentGatewayInterface::class,
    StripeGateway::class
);

// Ao pedir a interface, recebe a implementação:
app(PaymentGatewayInterface::class);  // → StripeGateway
```

### Com Parâmetros

```php
$this->app->singleton('database', function($app, $parameters) {
    $name = $parameters['connection'] ?? 'default';
    return new Database($name);
});

// Uso:
app()->make('database', ['connection' => 'testing']);
```

---

## Exemplos Práticos

> Os exemplos abaixo são **código real** extraído dos Service Providers do OfficeGest.

### 🎯 Exemplo 1: CacheServiceProvider (Simples)

**Localização:** `Modules/Common/Cache/CacheServiceProvider.php`

Um provider simples que regista driver e serviço:

```php
<?php

namespace Og\Modules\Common\Cache;

use Og\Modules\Common\Cache\Drivers\RedisDriver;
use Og\Modules\Common\Providers\ServiceProvider;

class CacheServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Driver Redis - depende de redis.manager
        $this->app->singleton('cache.driver.redis', function () {
            return new RedisDriver($this->app->get('redis.manager'));
        });
        
        // Serviço principal de cache
        $this->app->singleton('cache', function ($app) {
            return new Cache();
        });
    }

    public function boot(): void
    {
        // Sem inicialização adicional necessária
    }
}
```

---

### 🎯 Exemplo 2: NotificationServiceProvider (Múltiplos Canais)

**Localização:** `Modules/Common/Notifications/Providers/NotificationServiceProvider.php`

Provider que regista serviço com múltiplos formatters e canais condicionais:

```php
<?php

namespace Og\Modules\Common\Notifications\Providers;

use Og\Modules\Common\Notifications\Channels\DatabaseChannel;
use Og\Modules\Common\Notifications\Channels\EmailChannel;
use Og\Modules\Common\Notifications\Channels\MattermostChannel;
use Og\Modules\Common\Notifications\Formatters\ContextFormatter;
use Og\Modules\Common\Notifications\Formatters\JobContextFormatter;
use Og\Modules\Common\Notifications\Formatters\StackTraceFormatter;
use Og\Modules\Common\Notifications\Services\NotificationService;
use Og\Modules\Common\Providers\ServiceProvider;

class NotificationServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(NotificationService::class, function ($app) {
            // Configuração via parâmetro da aplicação
            $debugEnabled = forceBoolean($app['app']->getParam('NOTIFICATION_DEBUG', true));
            $service = new NotificationService(isDebugEnabled: $debugEnabled);

            // Registar formatters
            $service->addFormatter('context', new ContextFormatter());
            $service->addFormatter('job_context', new JobContextFormatter());
            $service->addFormatter('exception', new StackTraceFormatter());

            // Canais sempre disponíveis
            $service->addChannel(new DatabaseChannel($app->get('message-center')));
            $service->addChannel(new EmailChannel($app->get('email')));

            // Canal condicional (Mattermost só se configurado)
            if (config('notifications.channels.mattermost.enabled', false)) {
                $service->addChannel(
                    new MattermostChannel(
                        config('notifications.channels.mattermost.api_url'),
                        config('notifications.channels.mattermost.token'),
                        config('notifications.channels.mattermost.channel_id')
                    )
                );
            }

            return $service;
        });
    }
}
```

**Pontos de interesse:**
- Usa `forceBoolean()` para converter parâmetro de config
- Adiciona formatters e canais ao serviço
- Regista canal Mattermost **condicionalmente** baseado em config

---

### 🎯 Exemplo 3: RoutingServiceProvider (Métodos Organizados)

**Localização:** `Modules/Common/Routing/RoutingServiceProvider.php`

Provider organizado em métodos separados para cada serviço:

```php
<?php

namespace Og\Modules\Common\Routing;

use Og\Modules\Common\Middleware\MiddlewareManager;
use Og\Modules\Common\Providers\ServiceProvider;
use Og\Modules\Common\Utils\URL\URL;

class RoutingServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Organização em métodos separados
        $this->registerMiddleware();
        $this->registerRouter();
        $this->registerRouterCollector();
        $this->registerUrlGenerator();
        $this->registerRouteCache();
        $this->registerResponse();
    }

    protected function registerMiddleware(): void
    {
        $this->app->singleton('middleware', function () {
            return new MiddlewareManager();
        });
    }

    protected function registerRouter(): void
    {
        $this->app->singleton('router', function ($app) {
            return new Router();
        });
    }

    protected function registerRouterCollector(): void
    {
        $this->app->singleton('router.collector', function ($app) {
            return RouterCollector::getInstance();
        });
    }

    protected function registerUrlGenerator(): void
    {
        $this->app->singleton('url', function ($app) {
            $host = $_SERVER['HTTP_HOST'] ?? null;
            $url = new URL($host);

            // Detectar HTTPS automaticamente
            if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
                $url->https();
            } else {
                $url->http();
            }

            // Gestão inteligente de portas não-padrão
            if (isset($_SERVER['SERVER_PORT'])) {
                $port = (int) $_SERVER['SERVER_PORT'];
                if (
                    ($port !== 80 && !isset($_SERVER['HTTPS'])) ||
                    ($port !== 443 && isset($_SERVER['HTTPS']))
                ) {
                    $url->port($port);
                }
            }

            return $url;
        });
    }

    protected function registerRouteCache(): void
    {
        $this->app->singleton('route.cache', function ($app) {
            return new RouteCache();
        });
    }
}
```

**Pontos de interesse:**
- `register()` delega para métodos privados (código limpo)
- URL generator detecta HTTPS e portas automaticamente
- Usa `RouterCollector::getInstance()` (singleton externo)

---

### 🎯 Exemplo 4: QueueServiceProvider (Complexo com Múltiplos Drivers)

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

Provider complexo com ~40 bindings, múltiplos drivers e binding contextual:

```php
<?php

namespace Og\Modules\Common\Queue;

use Og\Modules\Common\Providers\ServiceProvider;
use Og\Modules\Common\Queue\Contracts\BatchStateManagerInterface;
use Og\Modules\Common\Queue\Contracts\ChainStateManagerInterface;
use Og\Modules\Common\Queue\Contracts\QueueManagerInterface;
use Og\Modules\Common\Queue\Drivers\RabbitMQ\RabbitMQBatchStateManager;
use Og\Modules\Common\Queue\Drivers\Redis\RedisBatchStateManager;
use RuntimeException;

class QueueServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // 1. Configuração
        $this->app->singleton(QueueConfig::class, fn() => 
            new QueueConfig(require rootPath('Modules/Common/Config/queue.php'))
        );
        
        // 2. Serializer (bind = nova instância)
        $this->app->bind(SerializerInterface::class, JsonSerializer::class);
        
        // 3. State Managers com driver dinâmico (match expression)
        $this->app->singleton(BatchStateManagerInterface::class, function ($app) {
            $config = $app->make(QueueConfig::class);
            $driver = $config->getDefaultDriver();

            return match ($driver) {
                'redis'    => $app->make(RedisBatchStateManager::class),
                'rabbitmq' => $app->make(RabbitMQBatchStateManager::class),
                default    => throw new RuntimeException(
                    "Driver de batch state não suportado: {$driver}"
                )
            };
        });
        
        // 4. Binding contextual - RabbitMQ usa LockManager diferente
        $this->app->when(RabbitMQBatchStateManager::class)
            ->needs(LockManagerInterface::class)
            ->give(function ($app) {
                return $app->make(RabbitMQLockManager::class);
            });
        
        // 5. Queue Manager principal
        $this->app->singleton(QueueManagerInterface::class, function ($app) {
            return new QueueManager(
                $app->make(SerializerInterface::class),
                $app->make(BatchStateManagerFactory::class),
                $app->make(ChainStateManagerFactory::class),
                $app->make(QueueConfig::class)
            );
        });
        
        // 6. Worker com parâmetros opcionais
        $this->app->singleton('queue-worker', function ($app, $parameters) {
            $options = $parameters['options'] ?? [
                'sleep'   => 3,
                'tries'   => 3,
                'memory'  => 128,
                'timeout' => 60
            ];

            return new Worker(
                $app->make(QueueManagerInterface::class),
                $app->make(QueueMonitorInterface::class),
                $app->make(SerializerInterface::class),
                // ... mais dependências
                $options
            );
        });
        
        // 7. Dead Letter Queue condicional
        $this->app->singleton(DeadLetterQueueInterface::class, function ($app) {
            $config = $app->make(QueueConfig::class);
            if ($config->getFailedConfig()['driver'] === 'database') {
                return new DatabaseDeadLetterQueueService(
                    new DeadLetterQueueRepository(),
                    $app->make(QueueManagerInterface::class)
                );
            }
            throw new RuntimeException("Driver DLQ não suportado");
        });
    }

    public function boot(): void
    {
        // Carregar helpers de queue
        require_once modulePath('Common/Queue/Helpers.php');
    }
    
    // Lista de serviços fornecidos (para lazy loading)
    public function provides(): array
    {
        return [
            QueueConfig::class,
            SerializerInterface::class,
            QueueManagerInterface::class,
            BatchStateManagerInterface::class,
            // ... 30+ mais serviços
        ];
    }
}
```

**Pontos de interesse:**
- Usa `match` para selecção dinâmica de driver
- `when()->needs()->give()` para binding contextual
- Worker aceita parâmetros opcionais via `$parameters`
- Método `provides()` lista todos os serviços
- `boot()` carrega ficheiro de helpers

---

### 🎯 Exemplo 5: GlobalServiceProvider (Bridge Legacy)

**Localização:** `Modules/Common/Legacy/Providers/GlobalServiceProvider.php`

O provider mais crítico - faz a ponte entre sistema moderno e legacy:

```php
<?php

namespace Og\Modules\Common\Legacy\Providers;

use Og\_files\database\DatabaseConnector;
use Og\Modules\Common\Auth\AuthManager;
use Og\Modules\Common\Providers\ServiceProvider;

class GlobalServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Database - bridge para $GLOBALS['db']
        $this->app->singleton('database', function ($app, $parameters) {
            $app->get('redis');  // Garantir Redis inicializado
            $dbParamName = $parameters['dbParamName'] ?? 'db';
            
            // Retornar global se já existe
            if (!empty($GLOBALS[$dbParamName])) {
                return $GLOBALS[$dbParamName];
            }
            
            // Criar nova instância e guardar no global
            $databaseInstance = DatabaseConnector::getInstance();
            $GLOBALS[$dbParamName] = $databaseInstance;
            return $databaseInstance;
        });
        
        // Aplicação - bridge para $GLOBALS['a']
        $this->app->singleton('app', function ($app) {
            $app->make('database');  // Dependência
            
            if (isset($GLOBALS['a'])) {
                return $GLOBALS['a'];
            }
            
            require_once filePath('Aplication.class.php');
            $application = new Aplication();
            $GLOBALS['a'] = $application;
            return $application;
        });
        
        // User - bridge para $GLOBALS['u']
        $this->app->singleton('user', function ($app) {
            if (!empty($GLOBALS['u'])) {
                return $GLOBALS['u'];
            }
            
            $app->get('app');
            $app->get('database');
            require_once filePath('user.class.php');
            
            $user = new User();
            $GLOBALS['u'] = $user;
            return $user;
        });
        
        // Language com parâmetros dinâmicos
        $this->app->singleton('language', function ($app, array $parameters) {
            $languageVariable = $parameters['language_variable'] ?? 'l';
            
            if (isset($GLOBALS[$languageVariable])) {
                return $GLOBALS[$languageVariable];
            }
            
            require_once filePath('language.class.php');
            $languageCode = $parameters['language_code'] ?? null;
            $GLOBALS[$languageVariable] = new Language($languageCode);
            return $GLOBALS[$languageVariable];
        });
        
        // Auth Manager moderno
        $this->app->singleton('auth', function ($app) {
            return new AuthManager($app->get('user'));
        });
        
        // ... 15+ mais serviços (email, session, printer, etc.)
    }
}
```

**Pontos de interesse:**
- **Bridge pattern**: Mantém `$GLOBALS` para código legacy
- Parâmetros dinâmicos: `$parameters['dbParamName']`
- `require_once` de classes legacy quando necessário
- Dependências sequenciais: `database` → `app` → `user`
```

---

## Boas Práticas

### ✅ Register: Apenas Registar

```php
public function register(): void
{
    // ✅ BOM - apenas registar binding
    $this->app->singleton(MyService::class, fn($app) => 
        new MyService($app->get('database'))
    );
    
    // ❌ MAU - resolver antes do boot
    $service = $this->app->make(MyService::class);
    $service->setup();  // Não fazer isto aqui!
}
```

### ✅ Boot: Inicialização que Depende de Outros

```php
public function boot(): void
{
    // ✅ BOM - usar serviços já registados
    $router = $this->app->get('router');
    $router->middleware('auth', AuthMiddleware::class);
    
    // ✅ BOM - registar eventos
    $events = $this->app->get('events');
    $events->listen(UserCreated::class, SendWelcome::class);
}
```

### ✅ Interfaces em vez de Classes

```php
// ✅ BOM - depende de interface
$this->app->bind(CacheInterface::class, RedisCache::class);

// ❌ MAU - depende de implementação
$this->app->bind(RedisCache::class, RedisCache::class);
```

### ✅ Lazy Loading com Closures

```php
// ✅ BOM - só cria quando necessário
$this->app->singleton('heavy-service', function($app) {
    return new HeavyService();  // Só executa quando app('heavy-service')
});

// ❌ MAU - cria imediatamente
$this->app->instance('heavy-service', new HeavyService());
```

### ✅ Tratamento de Erros no Boot

```php
public function boot(): void
{
    try {
        $this->setupService();
    } catch (\Exception $e) {
        // Log mas não bloquear outros providers
        loggerBatch('error', 'Provider boot failed: ' . $e->getMessage());
    }
}
```

---

## Troubleshooting

### Problema: Dependência Circular

```
Circular dependency detected: ServiceA -> ServiceB -> ServiceA
```

**Solução:** Usar lazy loading ou reestruturar:

```php
// Usar Closure para quebrar ciclo
$this->app->singleton(ServiceA::class, function($app) {
    return new ServiceA(fn() => $app->make(ServiceB::class));
});
```

### Problema: Serviço não Encontrado

```php
app('meu-servico');  // BindingResolutionException
```

**Soluções:**

```php
// 1. Verificar se provider está registado
dd(app()->has('meu-servico'));

// 2. Verificar ordem dos providers (dependências primeiro)

// 3. Verificar nome do binding (case-sensitive)
```

### Problema: Boot Executado Múltiplas Vezes

**Causa:** Provider registado mais de uma vez.

**Solução:** O `ServiceProviderManager` já previne isso via `$registeredProviders`.

### Debug de Providers

```php
// Ver todos os bindings
dd(app()->get()->getBindings());

// Verificar se container fez boot
dd(app()->isBooted());

// Verificar provider específico
dd(class_exists(MyServiceProvider::class));
```

---

## Referência de API

### ServiceProvider (Classe Base)

```php
abstract class ServiceProvider implements ServiceProviderInterface
{
    protected Container $app;
    protected array $commands = [];
    
    public function __construct(Container $app);
    
    // Fase 1: Registar bindings
    public function register(): void;
    
    // Fase 2: Inicialização
    public function boot(): void;
    
    // Registar comandos CLI
    protected function registerConsoleCommand(string $commandClass): void;
    
    // Obter comandos registados
    public function getRegisteredCommands(): array;
}
```

### ServiceProviderManager

```php
class ServiceProviderManager
{
    // Registar providers (string ou instância)
    public function register(array|ServiceProvider $providers): void;
    
    // Executar boot em todos os providers
    public function boot(): void;
}
```

### Container (Métodos Relevantes)

```php
class Container
{
    // Bindings
    public function bind(string $abstract, $concrete = null, bool $shared = false): void;
    public function singleton(string $abstract, $concrete = null): void;
    public function instance(string $abstract, $instance): void;
    public function alias(string $abstract, string $alias): void;
    
    // Resolução
    public function make($abstract, array $parameters = []): mixed;
    public function get(string $abstract): mixed;
    
    // Verificação
    public function has(string $abstract): bool;
    public function bound(string $abstract): bool;
}
```

---

## Próximos Passos

- 📖 [Container System](./container-system.md) - Como o container funciona
- 📖 [Facades](./facades-system.md) - Interface estática para serviços
- 📖 [Queue System](./queue-system.md) - Sistema de filas

---

*Última atualização: Dezembro 2024*
