BusinessException.php 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. <?php
  2. namespace App\Exceptions;
  3. use Exception;
  4. use Illuminate\Http\JsonResponse;
  5. use Illuminate\Http\Request;
  6. /**
  7. * 需要自己的 type / title / 扩展字段的业务错误。
  8. *
  9. * 普通的 404、403、422 不要用它——直接 abort() 或让 FormRequest 抛
  10. * ValidationException,bootstrap/app.php 会统一渲染。只有当这个错误
  11. * 是一种**客户端需要分别处理的业务状态**时才定义 slug,例如:
  12. *
  13. * throw new BusinessException(
  14. * __('sentence.locked'), 409, 'sentence-locked',
  15. * ['locked_by' => $editor->nickname],
  16. * );
  17. *
  18. * Laravel 的 Handler 会先看异常有没有 render(),所以这里的实现优先级
  19. * 最高,不受 bootstrap/app.php 里那些处理器影响。
  20. */
  21. class BusinessException extends Exception
  22. {
  23. /**
  24. * @param string $detail 面向人的文案,调用方传已经过 __() 的字符串
  25. * @param string $slug 进 type 字段的问题类型标识
  26. * @param array<string, mixed> $extra 扩展成员
  27. */
  28. public function __construct(
  29. string $detail,
  30. protected int $status = 409,
  31. protected string $slug = 'business-error',
  32. protected array $extra = [],
  33. protected ?string $problemTitle = null,
  34. ) {
  35. parent::__construct($detail, $status);
  36. }
  37. public function render(Request $request): ?JsonResponse
  38. {
  39. // 只接管 v3;v2 的错误形状在 dashboard-v4 下线前不能变
  40. if (! $request->is('api/v3/*')) {
  41. return null;
  42. }
  43. return Problem::response(
  44. $request,
  45. $this->status,
  46. $this->slug,
  47. $this->problemTitle,
  48. $this->getMessage(),
  49. $this->extra,
  50. );
  51. }
  52. }