領収証発行サービス
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

394 行
11KB

  1. <?php
  2. namespace App\Http\Controllers\Web;
  3. use App\Codes\HTTPResultCode as ResultCode;
  4. use App\Codes\UserRole;
  5. use App\Exceptions\AppCommonException;
  6. use App\Exceptions\GeneralErrorMessageException;
  7. use Exception;
  8. use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
  9. use Illuminate\Foundation\Bus\DispatchesJobs;
  10. use Illuminate\Foundation\Validation\ValidatesRequests;
  11. use Illuminate\Http\JsonResponse;
  12. use Illuminate\Http\Request;
  13. use Illuminate\Http\Response;
  14. use Illuminate\Routing\Controller as BaseController;
  15. use Illuminate\Support\Arr;
  16. use Illuminate\Support\Facades\Auth;
  17. use Illuminate\Support\Facades\Log;
  18. use Illuminate\Support\Facades\Validator;
  19. use Illuminate\Support\Str;
  20. use Illuminate\Validation\ValidationException;
  21. use LogicException;
  22. use Symfony\Component\HttpFoundation\BinaryFileResponse;
  23. use Symfony\Component\HttpKernel\Exception\HttpException;
  24. abstract class WebController extends BaseController
  25. {
  26. use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
  27. const COL_NAME_CREATED_AT = 'created_at';
  28. const COL_NAME_UPDATED_AT = 'updated_at';
  29. const COL_NAME_RESULT_CODE = 'result';
  30. const COL_NAME_DATA = 'data';
  31. const COL_NAME_MESSAGES = 'messages';
  32. const COL_NAME_GENERAL_MESSAGE = 'general';
  33. const COL_NAME_EMAIL_ID = 'email_id';
  34. const COL_NAME_ERRORS = 'errors';
  35. /**
  36. * バリデートした結果を格納
  37. *
  38. * @var array
  39. */
  40. protected $validated = [];
  41. /**
  42. * 画面へ返却するメールID
  43. *
  44. * @var integer|null
  45. */
  46. private int|null $emailId = null;
  47. /**
  48. * 返却するメッセージ
  49. *
  50. * @var array|null
  51. */
  52. private array|null $messages = null;
  53. /**
  54. * 返却するメッセージ
  55. *
  56. * @var string|null
  57. */
  58. private string|null $generalMessage = null;
  59. /**
  60. * 返却するデータ
  61. *
  62. * @var mixed|null
  63. */
  64. private $data = null;
  65. /**
  66. * 返却する結果コード
  67. *
  68. * @var ResultCode|null
  69. */
  70. private ResultCode|null $resultCode = ResultCode::SECCESS;
  71. /**
  72. * パラメータオブジェクト
  73. */
  74. protected function getParam(): IParam
  75. {
  76. return $this->param;
  77. }
  78. /**
  79. * コントローラーの名前
  80. * オーバーライドされることを想定
  81. * 主に、Routeのドキュメント作成用
  82. *
  83. * @return string
  84. */
  85. public function name(): string
  86. {
  87. return "---未設定---";
  88. }
  89. /**
  90. * コントローラーの説明
  91. * オーバーライドされることを想定
  92. * 主に、Routeのドキュメント作成用
  93. *
  94. * @return string
  95. */
  96. public function description(): string
  97. {
  98. return "---未設定---";
  99. }
  100. /**
  101. * オーバーライド必要
  102. * メインロジック
  103. *
  104. * @param Request $request
  105. * @return Response|JsonResponse|string
  106. */
  107. protected function run(Request $request): Response|JsonResponse|BinaryFileResponse|string
  108. {
  109. return $this->successResponse();
  110. }
  111. private function getRules()
  112. {
  113. return $this->getParam()->rules();
  114. }
  115. public function entry(Request $request)
  116. {
  117. $this->setLogContext($request);
  118. try {
  119. $validator = Validator::make($request->all(), $this->getRules());
  120. $validator->validate();
  121. } catch (ValidationException $e) {
  122. logger("validate error", ['errors' => $e->errors(), 'request' => $request->all(), 'path' => $request->path()]);
  123. return $this->validateErrorResponse($e);
  124. }
  125. try {
  126. $this->validated = $validator->validated();
  127. $this->getParam()->setData($this->validated);
  128. $this->authorize();
  129. return $this->run($request);
  130. } catch (GeneralErrorMessageException $e) {
  131. return $this->failedResponse([], $e->getMessage());
  132. } catch (AppCommonException $e) {
  133. logs()->error(sprintf("Appエラー:%s", $e->getMessage()));
  134. return $this->failedResponse();
  135. } catch (LogicException $e) {
  136. logs()->error([
  137. sprintf("実装エラー:%s", $e->getMessage()),
  138. get_class($e),
  139. $e->getFile(),
  140. $e->getLine(),
  141. $request->all(),
  142. ]);
  143. logger(array_filter($e->getTrace(), function ($val, $key) {
  144. return $key <= 5;
  145. }, ARRAY_FILTER_USE_BOTH));
  146. return $this->failedResponse();
  147. } catch (ValidationException $e) {
  148. return $this->validateErrorResponse($e);
  149. } catch (HttpException $e) {
  150. if ($e->getStatusCode() === 401) {
  151. return $this->unAuthorizedResponse();
  152. }
  153. throw e;
  154. } catch (Exception $e) {
  155. logs()->error([
  156. sprintf("例外エラー:%s", $e->getMessage()),
  157. get_class($e),
  158. $e->getFile(),
  159. $e->getLine(),
  160. $request->all(),
  161. ]);
  162. logger(array_filter($e->getTrace(), function ($val, $key) {
  163. return $key <= 5;
  164. }, ARRAY_FILTER_USE_BOTH));
  165. return $this->failedResponse();
  166. }
  167. }
  168. protected function successResponse(array|object $data = [], array|string $messages = [])
  169. {
  170. return $this->setData($data)
  171. ->setMessages($messages)
  172. ->setResultCode(ResultCode::SECCESS)
  173. ->makeResponse();
  174. }
  175. protected function failedResponse(array|object $data = [], array|string $messages = [])
  176. {
  177. return $this->setData($data)
  178. ->setMessages($messages)
  179. ->setResultCode(ResultCode::FAILED)
  180. ->makeResponse();
  181. }
  182. protected function unAuthorizedResponse(array|object $data = [], array|string $messages = [])
  183. {
  184. return $this->setData($data)
  185. ->setMessages($messages)
  186. ->setResultCode(ResultCode::UNAUTHORIZED)
  187. ->makeResponse();
  188. }
  189. protected function exclusiveErrorResponse(array|object $data = [], array|string $messages = [])
  190. {
  191. return $this->setData($data)
  192. ->setMessages($messages)
  193. ->setResultCode(ResultCode::EXCLUSIVE_ERROR)
  194. ->makeResponse();
  195. }
  196. protected function validateErrorResponse(ValidationException|array $exception, string|null $generalMessage = null)
  197. {
  198. $errorMessages = [];
  199. $general = null;
  200. if ($exception instanceof ValidationException) {
  201. foreach ($exception->errors() as $key => $m) {
  202. $errorMessages[$key] = $m[0];
  203. }
  204. }
  205. if (is_array($exception)) {
  206. $errorMessages = $exception;
  207. }
  208. $general = $generalMessage ?? data_get($errorMessages, self::COL_NAME_GENERAL_MESSAGE);
  209. return $this->setData([])
  210. ->setMessages($errorMessages)
  211. ->setGeneralMessage($general)
  212. ->setResultCode(ResultCode::FAILED)
  213. ->makeResponse();
  214. }
  215. private function makeResponse()
  216. {
  217. if ($this->resultCode === null) {
  218. abort(403);
  219. }
  220. $ret = [];
  221. Arr::set($ret, self::COL_NAME_RESULT_CODE, $this->resultCode->value);
  222. if ($this->data !== null) {
  223. Arr::set($ret, self::COL_NAME_DATA, $this->data);
  224. }
  225. if ($this->messages !== null) {
  226. Arr::set($ret, self::COL_NAME_MESSAGES . "." . self::COL_NAME_ERRORS, $this->messages);
  227. }
  228. if ($this->generalMessage !== null) {
  229. Arr::set($ret, self::COL_NAME_MESSAGES . "." . self::COL_NAME_GENERAL_MESSAGE, $this->generalMessage);
  230. }
  231. if ($this->emailId !== null) {
  232. Arr::set($ret, self::COL_NAME_MESSAGES . "." . self::COL_NAME_EMAIL_ID, $this->emailId);
  233. }
  234. return response()
  235. ->json($ret)
  236. ->withHeaders($this->makeHeader());
  237. }
  238. private function makeHeader(): array
  239. {
  240. $header = [];
  241. $user = Auth::user();
  242. if ($user) {
  243. $header["App-User-Auth"] = sprintf("%d,%d", $user->id, $user->role->value);
  244. } else {
  245. $header["App-User-Auth"] = 'none';
  246. }
  247. return $header;
  248. }
  249. // 以下 認可関係
  250. protected array|null $roleAllow = null;
  251. protected array|null $roleDisallow = null;
  252. protected array|null $customAllow = null;
  253. protected function roleAllow(UserRole $role)
  254. {
  255. $this->roleAllow = [];
  256. foreach (UserRole::cases() as $ele) {
  257. if ($role->value <= $ele->value) {
  258. $this->roleAllow[] = $ele;
  259. }
  260. }
  261. }
  262. private function authorize()
  263. {
  264. if (!Auth::check()) {
  265. return;
  266. }
  267. $role = Auth::user()->role;
  268. if (!$this->canAccess($role)) {
  269. abort(401);
  270. }
  271. }
  272. public function canAccess(UserRole $role)
  273. {
  274. if (is_array($this->roleAllow) && !in_array($role, $this->roleAllow)) {
  275. return false;
  276. }
  277. if (is_array($this->roleDisallow) && in_array($role, $this->roleDisallow)) {
  278. return false;
  279. }
  280. return $this->canCustomAccess();
  281. }
  282. public function canCustomAccess(): bool
  283. {
  284. if (Auth::user()->role === UserRole::SUPER_ADMIN) {
  285. return true;
  286. }
  287. if ($this->customAllow === null) {
  288. return true;
  289. }
  290. $myCustoms = Auth::user()->contract->custom();
  291. foreach ($this->customAllow as $targetCustom) {
  292. logger(['myCustoms' => $myCustoms, 'target' => $targetCustom]);
  293. if (in_array($targetCustom, $myCustoms, true)) {
  294. return true;
  295. }
  296. }
  297. return false;
  298. }
  299. // 返却用データの登録
  300. protected function setEmailId(int $emailId)
  301. {
  302. $this->emailId = $emailId;
  303. return $this;
  304. }
  305. protected function setMessages(array|string $messages)
  306. {
  307. if (is_array($messages)) {
  308. $this->messages = $messages;
  309. } else {
  310. $this->setGeneralMessage($messages);
  311. }
  312. return $this;
  313. }
  314. protected function setGeneralMessage(string|null $generalMessage)
  315. {
  316. $this->generalMessage = $generalMessage;
  317. return $this;
  318. }
  319. protected function setData($data)
  320. {
  321. $this->data = $data;
  322. return $this;
  323. }
  324. protected function setResultCode(ResultCode $resultCode)
  325. {
  326. $this->resultCode = $resultCode;
  327. return $this;
  328. }
  329. protected function setLogContext(Request $request)
  330. {
  331. Log::withContext([
  332. '__requestUuid__' => strval(Str::uuid()),
  333. '__userId__' => Auth::id(),
  334. '__path__' => $request->path(),
  335. ]);
  336. }
  337. }