@extends('layouts.docs') @section('title', 'Service Providers - OG Framework') @section('body')
{{-- Left Sidebar: Navigation --}} @include('docs.partials.sidebar') {{-- Main Content --}}
{{-- Page Header --}}
Voltar para Documentação

Arquitetura

Service Providers

Service Providers são classes que registam serviços no Container de DI. São o ponto central de configuração de toda a aplicação — centralizando bindings, eventos, middlewares e comandos CLI.

{{-- Introduction --}}

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
// ❌ Sem Providers — configuração espalhada
$database = new Database($config);
$cache = new Cache($redis);
$logger = new Logger($path);

// ✅ Com Providers — tudo centralizado
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));
    }
}
{{-- Lifecycle --}}

Ciclo de Vida: Register & Boot

Todo Provider tem duas fases distintas que são executadas em momentos diferentes:

FASE 1: REGISTER ProviderManager.register() Provider1->register() → bindings ✓ Provider2->register() → bindings ✓ Provider3->register() → bindings ✓ FASE 2: BOOT ProviderManager.boot() Provider1->boot() → events ✓ Provider2->boot() → middleware ✓ Provider3->boot() → routes ✓

register()

✅ Fazer:

  • Registar singletons e bindings
  • Criar aliases
  • Registar comandos CLI

❌ Não fazer:

  • Resolver dependências
  • Usar outros serviços

boot()

✅ Fazer:

  • Registar eventos e listeners
  • Configurar middleware
  • Carregar rotas

❌ Não fazer:

  • Trabalho pesado (usar lazy loading)
{{-- Quick Start --}}

Criar um Provider em 3 Passos

{{-- Step 1 --}}
1

Criar a classe

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
    {
        $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
    }
}
{{-- Step 2 --}}
2

Registar no Container

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

Usar o serviço

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

// Via DI no construtor
class MeuController {
    public function __construct(
        private MeuServicoInterface $servico
    ) {}
}
{{-- 16 System Providers --}}

16 Providers do Sistema

Os providers são registados nesta ordem específica em Container.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 ⚠️
    ViewServiceProvider::class,         // 12. Templates
    NotificationServiceProvider::class, // 13. Notificações
    RoutingServiceProvider::class,      // 14. Routing
    GuardServiceProvider::class,        // 15. Autenticação
    QueueMasterServiceProvider::class,  // 16. Queue Master
]);
Grupo Providers Razão da Ordem
Infraestrutura Events, Helpers, Config, Redis Base para tudo
Core Queue, Cache, HTTP Usados por outros providers
Externos SAFT PT/AO Independentes
Legacy GlobalServiceProvider Bridge $u, $a, $s
Aplicação View, Notification, Routing Dependem do legacy
Segurança Guard Após routing
{{-- GlobalServiceProvider highlight --}}

GlobalServiceProvider — O Mais Importante

Este provider faz a ponte entre o sistema moderno e o código legacy:

'database' → $GLOBALS['db']
'user' → $GLOBALS['u']
'app' → $GLOBALS['a']
'session' → $GLOBALS['s']
'email' → $GLOBALS['mail']
'hooks' → $GLOBALS['hooks']
{{-- Binding Types --}}

Tipos de Bindings

singleton() — Instância Única

$this->app->singleton('database', fn($app) =>
    new DatabaseConnection($app->get('config'))
);

// Mesma instância sempre
$db1 = app('database');
$db2 = app('database');
$db1 === $db2;  // true

bind() — Nova Instância

$this->app->bind(RequestHandler::class, fn() =>
    new RequestHandler()
);

// Instâncias diferentes
$h1 = app(RequestHandler::class);
$h2 = app(RequestHandler::class);
$h1 === $h2;  // false

instance() — Já Criada

// Registar instância existente
$user = new User($id);
$this->app->instance('current-user', $user);

alias() — Nome Alternativo

$this->app->singleton(DatabaseConnection::class, ...);
$this->app->alias(DatabaseConnection::class, 'db');

// Ambos funcionam:
app(DatabaseConnection::class);
app('db');
{{-- Full Example --}}

Exemplo Real: NotificationServiceProvider

Modules/Common/Notifications/Providers/NotificationServiceProvider.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;
        });
    }
}

Formatters

Adiciona formatters para diferentes tipos de contexto

Canais Base

Database e Email sempre disponíveis

Canal Condicional

Mattermost só se habilitado no config

{{-- Best Practices --}}

Boas Práticas

✅ Usar Interfaces

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

✅ Lazy Loading

// BOM - só cria quando usado
$this->app->singleton('heavy', fn($app) =>
    new HeavyService()
);

❌ Resolver no Register

public function register(): void
{
    // MAU - não fazer!
    $service = $this->app->make(MyService::class);
    $service->setup();
}

❌ Instance Pesada

// MAU - cria imediatamente
$this->app->instance(
    'heavy',
    new HeavyService() // Sem lazy!
);
{{-- Navigation --}}
{{-- Right Sidebar: Table of Contents --}} @include('docs.partials.toc', ['sections' => [ 'introducao' => 'Por que usar?', 'ciclo-de-vida' => 'Register & Boot', 'criar-provider' => 'Criar Provider', 'providers-sistema' => '16 Providers', 'tipos-binding' => 'Tipos de Binding', 'exemplo-completo' => 'Exemplo Completo', 'boas-praticas' => 'Boas Práticas', ]])
@endsection