ReviewController.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. <?php
  2. namespace App\Http\Controllers\Movie;
  3. use Illuminate\Http\Request;
  4. use Illuminate\Support\Str;
  5. use App\Http\Controllers\Controller;
  6. use App\Http\Traits\CommonTrait;
  7. use App\Models\Movie\Movie;
  8. use App\Models\Movie\MovieInfo;
  9. use App\Models\Movie\MovieDetail;
  10. use App\Models\Movie\MovieReview;
  11. use App\Models\Movie\MovieLike;
  12. use App\Models\Movie\MovieBlame;
  13. use App\Models\DTO\ResponseData;
  14. use App\Models\DTO\SearchData;
  15. use App\Rules\FilterSpamKeyword;
  16. use Exception;
  17. class ReviewController extends Controller
  18. {
  19. use CommonTrait;
  20. private Movie $movieModel;
  21. private MovieInfo $movieInfoModel;
  22. private MovieDetail $movieDetailModel;
  23. private MovieReview $movieReviewModel;
  24. private MovieLike $movieLikeModel;
  25. public function __construct(
  26. Movie $movieModel,
  27. MovieInfo $movieInfoModel,
  28. MovieDetail $movieDetailModel,
  29. MovieReview $movieReviewModel,
  30. MovieLike $movieLikeModel
  31. ) {
  32. $this->middleware('front');
  33. $this->movieModel = $movieModel;
  34. $this->movieInfoModel = $movieInfoModel;
  35. $this->movieDetailModel = $movieDetailModel;
  36. $this->movieReviewModel = $movieReviewModel;
  37. $this->movieLikeModel = $movieLikeModel;
  38. }
  39. /**
  40. * 영화 평점·후기 목록
  41. * @method GET
  42. * @see /movie/review
  43. */
  44. public function index(Request $request)
  45. {
  46. $params = SearchData::fromRequest($request);
  47. $params->userID = UID;
  48. $params->sort = $request->get('sort', 1);
  49. $reviews = $this->movieReviewModel->list($params);
  50. if($reviews->rows > 0) {
  51. foreach($reviews->list as &$row) {
  52. $length = strlen($row->sid);
  53. $row->owner = ($row->name . '(' . Str::mask($row->sid, '*', intval($length / 2), $length) . ')');
  54. $row->createdAt = date('Y.m.d', strtotime($row->created_at));
  55. $row->isLike = $this->movieLikeModel->isLike($row->id, UID);
  56. $row->isDisLike = $this->movieLikeModel->isDisLike($row->id, UID);
  57. $row->viewURL = route('movie.search.show', base64_encode($row->movie_cd));
  58. }
  59. }
  60. return view(layout('movie.review.index'), [
  61. 'params' => $params,
  62. 'reviews' => $reviews
  63. ]);
  64. }
  65. /**
  66. * 영화 평점·후기 보기
  67. * @method GET
  68. * @see /movie/review/{movieCd}
  69. */
  70. public function show(Request $request)
  71. {
  72. $movieCd = base64_decode($request->route('review'));
  73. $params = SearchData::fromRequest($request);
  74. $params->movieCd = $movieCd;
  75. $params->userID = UID;
  76. $params->sort = $request->get('sort', 1);
  77. // 이미 등록 했는지 확인
  78. if(!$this->movieModel->isExists($movieCd)) {
  79. return alert('잘못된 접근입니다.', DIRECTORY_SEPARATOR);
  80. }
  81. $info = $this->movieInfoModel->info($movieCd);
  82. $detail = $this->movieDetailModel->info($movieCd);
  83. $avgRate = $this->movieReviewModel->getAvgRate($movieCd);
  84. $reviews = $this->movieReviewModel->list($params);
  85. if($reviews->rows > 0) {
  86. foreach($reviews->list as &$row) {
  87. $length = strlen($row->sid);
  88. $row->owner = ($row->name . '(' . Str::mask($row->sid, '*', intval($length / 2), $length) . ')');
  89. $row->createdAt = date('Y.m.d', strtotime($row->created_at));
  90. $row->isLike = $this->movieLikeModel->isLike($row->id, UID);
  91. $row->isDisLike = $this->movieLikeModel->isDisLike($row->id, UID);
  92. }
  93. }
  94. $movieCd = base64_encode($movieCd);
  95. $movieNm = $info->movie_nm;
  96. if($info->movie_nm_en) {
  97. $movieNm .= (' (' . $info->movie_nm_en . ')');
  98. }
  99. return view(layout('movie.review.show'), [
  100. 'movieCd' => $movieCd,
  101. 'movieNm' => $movieNm,
  102. 'params' => $params,
  103. 'info' => $info,
  104. 'detail' => $detail,
  105. 'reviews' => $reviews,
  106. 'avgRate' => $avgRate
  107. ]);
  108. }
  109. /**
  110. * 영화 평점·후기 등록
  111. * @method POST
  112. * @see /movie/review
  113. */
  114. public function store(Request $request, ResponseData $response): ResponseData
  115. {
  116. try {
  117. $request->merge([
  118. 'mid' => base64_decode($request->post('mid'))
  119. ]);
  120. $rules = [
  121. 'mid' => 'required|exists:tb_movie,movie_cd',
  122. 'mode' => 'required|in:write',
  123. 'rate' => 'required|numeric|min:1|max:10',
  124. 'content' => ['required', 'string', 'min:1', 'max:1000', new FilterSpamKeyword]
  125. ];
  126. $attributes = [
  127. 'mid' => '영화 PK',
  128. 'mode' => '처리 구분',
  129. 'rate' => '평점',
  130. 'content' => '감상평'
  131. ];
  132. $messages = [
  133. 'mid.required' => '영화 PK는 필수 값 입니다.',
  134. 'mid.exists' => '영화 PK가 존재하지 않습니다.',
  135. 'mode.required' => '처리 구분을 입력해주세요.',
  136. 'mode.in' => '처리 구분 형식이 옳지 않습니다.',
  137. 'rate.required' => '평점을 선택해주세요.',
  138. 'rate.numeric' => '평점은 형식이 옳지 않습니다.',
  139. 'rate.min' => '평점은 최소 1 이상 입니다.',
  140. 'rate.max' => '평점은 최대 10 이하 입니다.',
  141. 'content.required' => '감상평을 입력해주세요.',
  142. 'content.string' => '감상평 형식이 옳지 않습니다.',
  143. 'content.min' => '감상평을 입력해주세요.',
  144. 'content.max' => '감상평은 최대 1000자 입력 가능합니다.'
  145. ];
  146. $posts = $this->validate($request, $rules, $messages, $attributes);
  147. // 이미 등록 했는지 확인
  148. if($this->movieReviewModel->isAlready($posts['mid'], UID)) {
  149. throw new Exception('이미 감상 후기를 등록하셨습니다.');
  150. }
  151. $this->movieReviewModel->insert([
  152. 'movie_cd' => $posts['mid'],
  153. 'user_id' => UID,
  154. 'content' => trim($posts['content']),
  155. 'rate' => $posts['rate'],
  156. 'like' => 0,
  157. 'dislike' => 0,
  158. 'blame' => 0,
  159. 'ip_address' => IP_ADDRESS,
  160. 'user_agent' => USER_AGENT,
  161. 'updated_at' => null,
  162. 'created_at' => now()
  163. ]);
  164. }catch(Exception $e) {
  165. $response = $response::fromException($e);
  166. }
  167. return $response;
  168. }
  169. /**
  170. * 영화 평점·후기 수정
  171. * @method PUT
  172. * @see /movie/review/{review_id}
  173. */
  174. public function update(Request $request, ResponseData $response): ResponseData
  175. {
  176. try {
  177. $request->merge([
  178. 'mid' => base64_decode($request->post('mid'))
  179. ]);
  180. $rules = [
  181. 'mid' => 'required|exists:tb_movie,movie_cd',
  182. 'rid' => 'required|exists:tb_movie_review,id',
  183. 'mode' => 'required|in:modify',
  184. 'rate' => 'required|numeric|min:1|max:10',
  185. 'content' => ['required', 'string', 'min:1', 'max:1000', new FilterSpamKeyword]
  186. ];
  187. $attributes = [
  188. 'rid' => '후기 PK',
  189. 'mid' => '영화 PK',
  190. 'mode' => '처리 구분',
  191. 'rate' => '평점',
  192. 'content' => '감상평'
  193. ];
  194. $messages = [
  195. 'mid.required' => '영화 PK는 필수 값 입니다.',
  196. 'mid.exists' => '영화 PK가 존재하지 않습니다.',
  197. 'rid.required' => '후기 PK는 필수 값 입니다.',
  198. 'rid.exists' => '후기 PK가 존재하지 않습니다.',
  199. 'mode.required' => '처리 구분을 입력해주세요.',
  200. 'mode.in' => '처리 구분 형식이 옳지 않습니다.',
  201. 'rate.required' => '평점을 선택해주세요.',
  202. 'rate.numeric' => '평점은 형식이 옳지 않습니다.',
  203. 'rate.min' => '평점은 최소 1 이상 입니다.',
  204. 'rate.max' => '평점은 최대 10 이하 입니다.',
  205. 'content.required' => '감상평을 입력해주세요.',
  206. 'content.string' => '감상평 형식이 옳지 않습니다.',
  207. 'content.min' => '감상평을 입력해주세요.',
  208. 'content.max' => '감상평은 최대 1000자 입력 가능합니다.'
  209. ];
  210. $posts = $this->validate($request, $rules, $messages, $attributes);
  211. // 내가 등록한 후기 인지 확인
  212. if(!$this->movieReviewModel->isExists($posts['rid'], UID)) {
  213. throw new Exception('내가 등록한 감상 후기가 아닙니다.');
  214. }
  215. $this->movieReviewModel->find($posts['rid'])->update([
  216. 'content' => trim($posts['content']),
  217. 'rate' => $posts['rate'],
  218. 'updated_at' => now()
  219. ]);
  220. }catch(Exception $e) {
  221. $response = $response::fromException($e);
  222. }
  223. return $response;
  224. }
  225. /**
  226. * 영화 평점·후기 삭제
  227. * @method DELETE
  228. * @see /movie/review/{review_id}
  229. */
  230. public function destroy(Request $request, ResponseData $response): ResponseData
  231. {
  232. try {
  233. $request->merge([
  234. 'mid' => base64_decode($request->post('mid'))
  235. ]);
  236. $rules = [
  237. 'mid' => 'required|exists:tb_movie,movie_cd',
  238. 'rid' => 'required|exists:tb_movie_review,id',
  239. 'mode' => 'required|in:delete'
  240. ];
  241. $attributes = [
  242. 'rid' => '후기 PK',
  243. 'mid' => '영화 PK',
  244. 'mode' => '처리 구분'
  245. ];
  246. $messages = [
  247. 'mid.required' => '영화 PK는 필수 값 입니다.',
  248. 'mid.exists' => '영화 PK가 존재하지 않습니다.',
  249. 'rid.required' => '후기 PK는 필수 값 입니다.',
  250. 'rid.exists' => '후기 PK가 존재하지 않습니다.',
  251. 'mode.required' => '처리 구분을 입력해주세요.',
  252. 'mode.in' => '처리 구분 형식이 옳지 않습니다.'
  253. ];
  254. $posts = $this->validate($request, $rules, $messages, $attributes);
  255. // 내가 등록한 후기 인지 확인
  256. if(!$this->movieReviewModel->isExists($posts['rid'], UID)) {
  257. throw new Exception('내가 등록한 감상 후기가 아닙니다.');
  258. }
  259. $this->movieReviewModel->find($posts['rid'])->delete();
  260. }catch(Exception $e) {
  261. $response = $response::fromException($e);
  262. }
  263. return $response;
  264. }
  265. /**
  266. * 평점·후기 공감하기
  267. * @method POST
  268. * @see /movie/review/like
  269. */
  270. public function like(Request $request, ResponseData $response): ResponseData
  271. {
  272. try {
  273. $request->merge([
  274. 'mid' => base64_decode($request->post('mid'))
  275. ]);
  276. $rules = [
  277. 'mid' => 'required|exists:tb_movie,movie_cd',
  278. 'rid' => 'required|exists:tb_movie_review,id'
  279. ];
  280. $attributes = [
  281. 'mid' => '영화 PK',
  282. 'rid' => '후기 PK'
  283. ];
  284. $messages = [
  285. 'mid.required' => '영화 PK는 필수 값 입니다.',
  286. 'mid.exists' => '영화 PK가 존재하지 않습니다.',
  287. 'rid.required' => '후기 PK는 필수 값 입니다.',
  288. 'rid.exists' => '후기 PK가 존재하지 않습니다.',
  289. ];
  290. $posts = $this->validate($request, $rules, $messages, $attributes);
  291. $like = $this->movieLikeModel->getType($posts['rid'], UID);
  292. if($like->exists) {
  293. throw new Exception(sprintf("이미 %s 하셨습니다.", ($like->type == 1 ? '공감' : '비공감')));
  294. }
  295. $response->like = $this->movieReviewModel->setLike($posts['mid'], $posts['rid'], UID, LIKE);
  296. }catch(Exception $e) {
  297. $response = $response::fromException($e);
  298. }
  299. return $response;
  300. }
  301. /**
  302. * 평점·후기 비공감하기
  303. * @method POST
  304. * @see /movie/review/dislike
  305. */
  306. public function dislike(Request $request, ResponseData $response): ResponseData
  307. {
  308. try {
  309. $request->merge([
  310. 'mid' => base64_decode($request->post('mid'))
  311. ]);
  312. $rules = [
  313. 'mid' => 'required|exists:tb_movie,movie_cd',
  314. 'rid' => 'required|exists:tb_movie_review,id'
  315. ];
  316. $attributes = [
  317. 'mid' => '영화 PK',
  318. 'rid' => '후기 PK',
  319. ];
  320. $messages = [
  321. 'mid.required' => '영화 PK는 필수 값 입니다.',
  322. 'mid.exists' => '영화 PK가 존재하지 않습니다.',
  323. 'rid.required' => '후기 PK는 필수 값 입니다.',
  324. 'rid.exists' => '후기 PK가 존재하지 않습니다.'
  325. ];
  326. $posts = $this->validate($request, $rules, $messages, $attributes);
  327. $like = $this->movieLikeModel->getType($posts['rid'], UID);
  328. if($like->exists) {
  329. throw new Exception(sprintf("이미 %s 하셨습니다.", ($like->type == 1 ? '공감' : '비공감')));
  330. }
  331. $response->dislike = $this->movieReviewModel->setLike($posts['mid'], $posts['rid'], UID, DISLIKE);
  332. }catch(Exception $e) {
  333. $response = $response::fromException($e);
  334. }
  335. return $response;
  336. }
  337. /**
  338. * 평점·후기 신고
  339. * @method POST
  340. * @see /movie/review/blame
  341. */
  342. public function blame(Request $request, ResponseData $response, MovieBlame $movieBlameModel): ResponseData
  343. {
  344. try {
  345. $request->merge([
  346. 'mid' => base64_decode($request->post('mid'))
  347. ]);
  348. $rules = [
  349. 'mid' => 'required|exists:tb_movie,movie_cd',
  350. 'rid' => 'required|exists:tb_movie_review,id',
  351. 'blame_type' => 'required|numeric|in:1,2,3,4,5,6,7,8,9',
  352. 'blame_reason' => 'required|string|max:1000'
  353. ];
  354. $attributes = [
  355. 'rid' => '후기 PK',
  356. 'mid' => '영화 PK',
  357. 'blame_type' => '신고 사유',
  358. 'blame_reason' => '신고 내용'
  359. ];
  360. $messages = [
  361. 'mid.required' => '영화 PK는 필수 값 입니다.',
  362. 'mid.exists' => '영화 PK가 존재하지 않습니다.',
  363. 'rid.required' => '후기 PK는 필수 값 입니다.',
  364. 'rid.exists' => '후기 PK가 존재하지 않습니다.',
  365. 'blame_type.required' => '신고 사유를 선택해주세요.',
  366. 'blame_type.numeric' => '신고 사유 형식이 옳지 않습니다.',
  367. 'blame_type.in' => '신고 사유가 잘못되었습니다.',
  368. 'blame_reason.required' => '신고 내용을 입력해주세요.',
  369. 'blame_reason.string' => '신고 내용 형식이 옳지 않습니다.',
  370. 'blame_reason.max' => '신고 내용은 최대 1000자 입력 가능합니다.'
  371. ];
  372. $posts = $this->validate($request, $rules, $messages, $attributes);
  373. if($movieBlameModel->isAlready($posts['mid'], $posts['rid'], UID)) {
  374. throw new Exception('이미 신고가 접수되었습니다.');
  375. }
  376. $this->movieReviewModel->setBlame($posts['mid'], $posts['rid'], UID, $posts['blame_type'], $posts['blame_reason']);
  377. }catch(Exception $e) {
  378. $response = $response::fromException($e);
  379. }
  380. return $response;
  381. }
  382. }