@extends('layouts.docs') @section('title', 'Service Providers - OG Framework') @section('body')
Arquitetura
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.
| ❌ 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));
}
}
Todo Provider tem duas fases distintas que são executadas em momentos diferentes:
register()
✅ Fazer:
❌ Não fazer:
boot()
✅ Fazer:
❌ Não fazer:
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
}
}
Registar no Container
// Em Container.php:registerServiceProviders()
$this->providerManager->register([
// ... outros providers
MeuModuloServiceProvider::class,
]);
Usar o serviço
// Via container
$servico = app(MeuServicoInterface::class);
// Via DI no construtor
class MeuController {
public function __construct(
private MeuServicoInterface $servico
) {}
}
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 — 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']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');
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
✅ 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!
);