@georgekala Your services should just be concerned with whatever business logic it is encapsulating; not anything like authentication or authorisation. That belongs in your application layer (controllers).
If you throw meaningful domain-level exceptions from your service classes, you can then get rid of your try/catch blocks in your controllers and everywhere else, and instead use Laravel’s exception handler for, well, handling exceptions and returning an appropriate response.
So instead of throwing generic Exception instances, create an exception class relevant to the domain and throw those:
class PlayerService
{
public function createForTeam(Team $team, array $data)
{
$team->assertHasCapacity();
// Logic to create player and assign them to team
}
}
The assertHasCapacity method would check if the team has capacity to add a player, and throw a meaningful exception if not:
public function assertHasCapacity(): void
{
if ($this->playersCount() < 23) {
throw TeamException::capacityReached();
}
}
You can then “convert” this exception to a more appropriate one in the exception handler:
$exceptions->map(TeamException::class, function (TeamException $e) {
return new BadRequestHttpException($e->getMessage(), previous: $e);
});
This will convert any TeamExceptions thrown to a 400 Bad Request exception.
So your controller is now just concerned with calling business logic, and not with exception handling:
public function store(StorePlayerRequest $request)
{
// Get $team from somewhere...
$this->playerService->createForTeam($team, $request->validated());
return new JsonResponse([
'message' => __('Player created successfully.'),
], JsonResponse::HTTP_CREATED);
}