您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

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