AbstractService
v1.1.0O AbstractService representa a camada de negócio do Laravel Domain Generator.
Os Controllers nunca devem conter regras de negócio. Toda operação é delegada ao Service, que coordena DTOs, Repositories, transações e regras do domínio.
Todo Service gerado pelo comando php artisan make:domain estende automaticamente essa classe.
Visão Geral
Os Services gerados oferecem um local consistente para concentrar a lógica de negócio, mantendo os Controllers extremamente enxutos.
Responsabilidades:
- regras de negócio
- orquestração do Repository
- processamento de DTOs
- transações
- suporte a identificadores públicos
- paginação
- carregamento de relacionamentos
- operações reutilizáveis do domínio
Exemplo mínimo:
class UserService extends AbstractService
{
public function __construct(UserRepository $repository)
{
parent::__construct($repository);
}
}Ciclo de Execução
Toda operação segue sempre o mesmo fluxo.
O Service funciona como a camada de orquestração entre HTTP e persistência.
Propriedades protegidas
$repository
protected AbstractRepository $repository;Armazena a instância do Repository injetada no construtor.
Toda operação CRUD chega ao Repository através dessa propriedade.
Exemplo:
public function __construct(UserRepository $repository)
{
parent::__construct($repository);
}Isso garante tipagem consistente em todos os Services gerados.
Construtor
public function __construct(AbstractRepository $repository)O construtor registra automaticamente o Repository utilizado pelo Service.
Fluxo:
- Repository é injetado.
- O construtor da classe pai o armazena.
- Os métodos CRUD ficam disponíveis imediatamente.
Métodos CRUD
create()
Cria um novo registro utilizando um DTO.
Exemplo:
$user = $service->create($dto);Fluxo:
DTO
↓
Service
↓
Repository
↓
Model::create()Responsabilidades típicas:
- validar regras de negócio;
- executar transações;
- delegar persistência.
O Service nunca deve receber Requests diretamente.
update()
Atualiza um registro existente.
Exemplo:
$service->update($publicId, $dto);Fluxo:
- Resolve o identificador público.
- Aplica regras de negócio.
- Persiste as alterações.
delete()
Remove um registro.
Quando o Model utiliza:
use SoftDeletes;o comportamento é preservado automaticamente.
find()
Recupera uma entidade.
Exemplo:
$user = $service->find($publicId);Sempre que possível, trabalha com identificadores públicos.
findOrFail()
Equivalente ao findOrFail() do Laravel, mas mantendo a responsabilidade centralizada no Repository.
Se o registro não existir, uma exceção padronizada é lançada.
paginate()
Retorna uma coleção paginada.
Exemplo:
return $service->paginate();O Controller permanece desacoplado da implementação do Repository.
A resposta já contém:
datalinksmeta
Suporte a Identificadores Públicos
Os Services utilizam identificadores públicos em vez de expor IDs internos.
Suporta:
- ULID
- UUID
- UUID32
- identificadores hash personalizados
Exemplo:
GET /api/users/01JXYZABCDEF123456A resolução é delegada ao Repository.
Transações
Uma das principais responsabilidades do Service é controlar transações.
Exemplo:
DB::transaction(function () use ($dto) {
$this->repository->create($dto->toArray());
});Benefícios:
- operações atômicas;
- rollback automático;
- maior segurança para regras complexas.
Sempre que houver múltiplas gravações relacionadas, elas devem ficar aqui.
Regras de Negócio
O Service é o lugar correto para implementar regras do domínio.
Exemplo:
if (! $user->ativo) {
throw new DomainException();
}Evite colocar essas regras em:
- Controllers;
- Repositories;
- Resources.
Assim o domínio permanece reutilizável.
Delegação para o Repository
O Service nunca acessa o banco diretamente.
Fluxo:
Controller
↓
Service
↓
Repository
↓
Banco de DadosExemplo:
$this->repository->create($dto->toArray());Isso torna a persistência substituível.
Carregamento de Relacionamentos
O Service pode solicitar eager loading através do Repository.
Exemplo:
$this->repository->with([
'municipio'
]);Vantagens:
- menos consultas;
- respostas previsíveis.
Fluxo da Paginação
A paginação sempre segue o mesmo pipeline.
Controller
↓
Service
↓
Repository::paginate()
↓
Paginator
↓
Resource CollectionO Controller nunca precisa montar a paginação manualmente.
Tratamento de Erros
As exceções de negócio permanecem dentro da camada Service.
Exemplo:
throw new DomainException(
'Usuários inativos não podem executar esta operação.'
);Posteriormente, o Controller converte essa exceção para o formato JSON padronizado.
Boas Práticas
Recomendado:
- receber DTOs;
- chamar Repositories;
- executar transações;
- validar regras do domínio.
Evite:
- receber Requests;
- retornar Responses HTTP;
- consultar Models diretamente.
O Service gerado mantém a lógica de negócio isolada da camada HTTP e da persistência, tornando o domínio mais testável e muito mais fácil de manter.