Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

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