領収証発行サービス
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.

415 rindas
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. return $this->run($request);
  144. } catch (GeneralErrorMessageException $e) {
  145. return $this->failedResponse([], $e->getMessage());
  146. } catch (AppCommonException $e) {
  147. logs()->error(sprintf("Appエラー:%s", $e->getMessage()));
  148. return $this->failedResponse();
  149. } catch (ExclusiveException $e) {
  150. logs()->error(sprintf("排他エラー:%s", $e->getMessage()));
  151. return $this->exclusiveErrorResponse();
  152. } catch (LogicException $e) {
  153. logs()->error([
  154. sprintf("実装エラー:%s", $e->getMessage()),
  155. get_class($e),
  156. $e->getFile(),
  157. $e->getLine(),
  158. $request->all(),
  159. ]);
  160. logger(array_filter($e->getTrace(), function ($val, $key) {
  161. return $key <= 5;
  162. }, ARRAY_FILTER_USE_BOTH));
  163. return $this->failedResponse();
  164. } catch (ValidationException $e) {
  165. return $this->validateErrorResponse($e);
  166. } catch (HttpException $e) {
  167. if ($e->getStatusCode() === 401) {
  168. return $this->unAuthorizedResponse();
  169. }
  170. throw e;
  171. } catch (Exception $e) {
  172. logs()->error([
  173. sprintf("例外エラー:%s", $e->getMessage()),
  174. get_class($e),
  175. $e->getFile(),
  176. $e->getLine(),
  177. $request->all(),
  178. ]);
  179. logger(array_filter($e->getTrace(), function ($val, $key) {
  180. return $key <= 5;
  181. }, ARRAY_FILTER_USE_BOTH));
  182. return $this->failedResponse();
  183. }
  184. }
  185. protected function successResponse(array|object $data = [], array|string $messages = [])
  186. {
  187. return $this->setData($data)
  188. ->setMessages($messages)
  189. ->setResultCode(ResultCode::SECCESS)
  190. ->makeResponse();
  191. }
  192. protected function failedResponse(array|object $data = [], array|string $messages = [])
  193. {
  194. return $this->setData($data)
  195. ->setMessages($messages)
  196. ->setResultCode(ResultCode::FAILED)
  197. ->makeResponse();
  198. }
  199. protected function unAuthorizedResponse(array|object $data = [], array|string $messages = [])
  200. {
  201. return $this->setData($data)
  202. ->setMessages($messages)
  203. ->setResultCode(ResultCode::UNAUTHORIZED)
  204. ->makeResponse();
  205. }
  206. protected function exclusiveErrorResponse(array|object $data = [], array|string $messages = [])
  207. {
  208. return $this->setData($data)
  209. ->setMessages($messages)
  210. ->setResultCode(ResultCode::EXCLUSIVE_ERROR)
  211. ->makeResponse();
  212. }
  213. protected function validateErrorResponse(ValidationException|array $exception, string|null $generalMessage = null)
  214. {
  215. $errorMessages = [];
  216. $general = null;
  217. if ($exception instanceof ValidationException) {
  218. foreach ($exception->errors() as $key => $m) {
  219. $errorMessages[$key] = $m[0];
  220. }
  221. }
  222. if (is_array($exception)) {
  223. $errorMessages = $exception;
  224. }
  225. $general = $generalMessage ?? data_get($errorMessages, self::COL_NAME_GENERAL_MESSAGE);
  226. return $this->setData([])
  227. ->setMessages($errorMessages)
  228. ->setGeneralMessage($general)
  229. ->setResultCode(ResultCode::FAILED)
  230. ->makeResponse();
  231. }
  232. private function makeResponse()
  233. {
  234. if ($this->resultCode === null) {
  235. abort(403);
  236. }
  237. $ret = [];
  238. Arr::set($ret, self::COL_NAME_RESULT_CODE, $this->resultCode->value);
  239. if ($this->data !== null) {
  240. Arr::set($ret, self::COL_NAME_DATA, $this->data);
  241. }
  242. if ($this->messages !== null) {
  243. Arr::set($ret, self::COL_NAME_MESSAGES . "." . self::COL_NAME_ERRORS, $this->messages);
  244. }
  245. if ($this->generalMessage !== null) {
  246. Arr::set($ret, self::COL_NAME_MESSAGES . "." . self::COL_NAME_GENERAL_MESSAGE, $this->generalMessage);
  247. }
  248. if ($this->emailId !== null) {
  249. Arr::set($ret, self::COL_NAME_MESSAGES . "." . self::COL_NAME_EMAIL_ID, $this->emailId);
  250. }
  251. if (request()->wantsJson()) {
  252. return response()
  253. ->json($ret)
  254. ->withHeaders($this->makeHeader());
  255. } else {
  256. abort(500);
  257. }
  258. }
  259. private function makeHeader(): array
  260. {
  261. $header = [];
  262. $user = Auth::user();
  263. if ($user) {
  264. $header["App-User-Auth"] = sprintf("%d,%d", $user->id, $user->role->value);
  265. } else {
  266. $header["App-User-Auth"] = 'none';
  267. }
  268. return $header;
  269. }
  270. // 以下 認可関係
  271. protected array|null $roleAllow = null;
  272. protected array|null $roleDisallow = null;
  273. protected array|null $customAllow = null;
  274. protected function roleAllow(UserRole $role)
  275. {
  276. $this->roleAllow = [];
  277. foreach (UserRole::cases() as $ele) {
  278. if ($role->value <= $ele->value) {
  279. $this->roleAllow[] = $ele;
  280. }
  281. }
  282. }
  283. private function authorize()
  284. {
  285. if (!Auth::check()) {
  286. return;
  287. }
  288. $role = Auth::user()->role;
  289. if (!$this->canAccess($role)) {
  290. abort(401);
  291. }
  292. }
  293. public function canAccess(UserRole $role)
  294. {
  295. if (is_array($this->roleAllow) && !in_array($role, $this->roleAllow)) {
  296. return false;
  297. }
  298. if (is_array($this->roleDisallow) && in_array($role, $this->roleDisallow)) {
  299. return false;
  300. }
  301. return $this->canCustomAccess();
  302. }
  303. public function canCustomAccess(): bool
  304. {
  305. if (Auth::user()->role === UserRole::SUPER_ADMIN) {
  306. return true;
  307. }
  308. if ($this->customAllow === null) {
  309. return true;
  310. }
  311. $myCustoms = Auth::user()->contract->custom();
  312. foreach ($this->customAllow as $targetCustom) {
  313. if (in_array($targetCustom, $myCustoms, true)) {
  314. return true;
  315. }
  316. }
  317. return false;
  318. }
  319. // 返却用データの登録
  320. protected function setEmailId(int $emailId)
  321. {
  322. $this->emailId = $emailId;
  323. return $this;
  324. }
  325. protected function setMessages(array|string $messages)
  326. {
  327. if (is_array($messages)) {
  328. $this->messages = $messages;
  329. } else {
  330. $this->setGeneralMessage($messages);
  331. }
  332. return $this;
  333. }
  334. protected function setGeneralMessage(string|null $generalMessage)
  335. {
  336. $this->generalMessage = $generalMessage;
  337. return $this;
  338. }
  339. protected function setData($data)
  340. {
  341. $this->data = $data;
  342. return $this;
  343. }
  344. protected function setResultCode(ResultCode $resultCode)
  345. {
  346. $this->resultCode = $resultCode;
  347. return $this;
  348. }
  349. protected function setLogContext(Request $request)
  350. {
  351. Log::withContext([
  352. '__requestUuid__' => strval(Str::uuid()),
  353. '__userId__' => Auth::id(),
  354. '__path__' => $request->path(),
  355. ]);
  356. }
  357. }