Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

381 lines
11KB

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