BoardService.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. <?php
  2. namespace App\Services;
  3. use Illuminate\Support\Facades\Cache;
  4. use App\Http\Traits\CommonTrait;
  5. use App\Http\Traits\BoardTrait;
  6. use App\Http\Requests\BoardRequest;
  7. use App\Models\Board;
  8. use App\Models\BoardMeta;
  9. use App\Models\BoardCategory;
  10. use App\Models\BoardAdmin;
  11. use App\Models\DTO\SearchData;
  12. use stdClass;
  13. class BoardService
  14. {
  15. use CommonTrait;
  16. use BoardTrait;
  17. public Board $boardModel;
  18. public BoardMeta $boardMetaModel;
  19. public BoardCategory $boardCategoryModel;
  20. public BoardAdmin $boardAdminModel;
  21. public function __construct()
  22. {
  23. $this->boardModel = new Board();
  24. $this->boardMetaModel = new BoardMeta();
  25. $this->boardCategoryModel = new BoardCategory();
  26. $this->boardAdminModel = new BoardAdmin();
  27. }
  28. /**
  29. * 게시판 조회
  30. */
  31. public function find(string $code): Board
  32. {
  33. return $this->boardModel->findByCode($code);
  34. }
  35. /**
  36. * 게시판 설정 값 조회
  37. */
  38. public function meta(int $boardID): ?BoardMeta
  39. {
  40. return $this->boardMetaModel->getAllMeta($boardID);
  41. }
  42. /**
  43. * 게시판 분류 조회
  44. */
  45. public function categories(int $boardID): object|null
  46. {
  47. $boardMeta = $this->meta($boardID);
  48. $useCategory = $boardMeta->item('use_category', 0);
  49. $usePersonal = $boardMeta->item('use_personal', 0);
  50. if ($useCategory) {
  51. if (!$usePersonal || IS_ADMIN) {
  52. return $this->boardCategoryModel->categories($boardID);
  53. }
  54. }
  55. return null;
  56. }
  57. /**
  58. * 공지사항 조회
  59. */
  60. public function notices(BoardRequest $request): object|null
  61. {
  62. $notices = null;
  63. if($request->page == 1 && !$request->keyword && !$request->category)
  64. {
  65. $notices = $this->boardModel->getNotices(
  66. SearchData::fromRequest($request)
  67. );
  68. if ($notices->total > 0)
  69. {
  70. foreach ($notices->list as $i => $row)
  71. {
  72. $notices->list[$i] = $this->_filter($row);
  73. }
  74. $notices->list = array_filter($notices->list);
  75. }
  76. }
  77. return $notices;
  78. }
  79. /**
  80. * 일반 게시글 혹은 검색 결과
  81. */
  82. public function posts(BoardRequest $request): object
  83. {
  84. $posts = $this->boardModel->getPosts(
  85. SearchData::fromRequest($request)
  86. );
  87. if ($posts->total > 0)
  88. {
  89. $num = listNum($posts->total, $request->page, $request->perPage);
  90. foreach ($posts->list as $i => $row)
  91. {
  92. $row->num = $num--;
  93. $posts->list[$i] = $this->_filter($row);
  94. }
  95. $posts->list->filter();
  96. }
  97. return $posts;
  98. }
  99. /**
  100. * 회원 작성 게시글 조회
  101. */
  102. public function userPosts(int $userID, SearchData $params): object
  103. {
  104. $posts = $this->boardModel->getUserPosts($userID, $params);
  105. if ($posts->total > 0)
  106. {
  107. $num = listNum($posts->total, $params->page, $params->perPage);
  108. foreach ($posts->list as $i => $row)
  109. {
  110. $row->num = $num--;
  111. $posts->list[$i] = $this->_filter($row);
  112. }
  113. $posts->list->filter();
  114. }
  115. return $posts;
  116. }
  117. /**
  118. * 최신 게시글 검색 조회
  119. */
  120. public function search(SearchData $params): object
  121. {
  122. $search = $this->boardModel->getSearch($params);
  123. if ($search->total > 0)
  124. {
  125. $num = listNum($search->total, $params->page, $params->perPage);
  126. foreach ($search->list as $i => $row)
  127. {
  128. $row->num = $num--;
  129. $search->list[$i] = $this->_filter($row);
  130. }
  131. $search->list->filter();
  132. }
  133. return $search;
  134. }
  135. /**
  136. * 게시판 최근 게시글
  137. */
  138. public function latest(?string $code, int $page = 1, int $perPage = DEFAULT_LIST_PER_PAGE)
  139. {
  140. $cacheName = sprintf('latest-board-%s-%d-%d', $code, $page, $perPage);
  141. if (!$latest = Cache::get($cacheName)) {
  142. $latest = $this->boardModel->getLatest($code, $page, $perPage);
  143. if($latest->total) {
  144. $num = listNum($latest->total, $page, $perPage);
  145. foreach ($latest->list as $i => $row) {
  146. $row->num = $num--;
  147. $latest->list[$i] = $this->_filter($row);
  148. }
  149. $latest->list->filter();
  150. }
  151. Cache::tags('latest-board')->put($cacheName, $latest, CACHE_EXPIRE_TIME);
  152. }
  153. return $latest;
  154. }
  155. /**
  156. * 게시판 설정 값 조회
  157. */
  158. private function _config(string|null $code)
  159. {
  160. $boardMeta = $this->meta($code);
  161. return (object)[
  162. 'use_category' => intval($boardMeta->item('use_category', 0)),
  163. 'subject_length' => (function($boardMeta) {
  164. // 게시판 설정 값 조회
  165. if(DEVICE_TYPE_1) {
  166. return intval($boardMeta->item('subject_length', 0));
  167. }else{
  168. return intval($boardMeta->item('subject_mobile_length', 0));
  169. }
  170. })($boardMeta),
  171. 'new_icon_hour' => intval($boardMeta->item('new_icon_hour', 24)),
  172. 'hot_icon_day' => intval($boardMeta->item('hot_icon_day', 7)),
  173. 'hot_icon_hit' => intval($boardMeta->item('hot_icon_hit', 100)),
  174. 'except_notice' => intval($boardMeta->item('except_notice', 0)),
  175. 'except_speaker' => intval($boardMeta->item('except_speaker', 0)),
  176. 'use_anonymous' => intval($boardMeta->item('use_anonymous', 0)),
  177. 'use_personal' => intval($boardMeta->item('use_personal', 0)),
  178. 'blame_blind_count' => intval($boardMeta->item('blame_blind_count', 0))
  179. ];
  180. }
  181. /**
  182. * 게시글 가공
  183. */
  184. private function _filter($postInfo)
  185. {
  186. if ($postInfo)
  187. {
  188. $config = $this->_config($postInfo->board_id);
  189. // 1:1 게시판에서는 전체공지 제외
  190. if($config->use_personal && $postInfo->is_speaker) {
  191. return null;
  192. }
  193. // 공지 제외
  194. if ($config->except_notice && $postInfo->is_notice) {
  195. return null;
  196. }
  197. // 전체 공지 제외
  198. if ($config->except_speaker && $postInfo->is_speaker) {
  199. return null;
  200. }
  201. $postInfo->subject = $this->strCut($postInfo->subject, $config->subject_length);
  202. $postInfo->viewURL = route('board.post.view', [$postInfo->code, $postInfo->id]) . $this->queryString();
  203. $postInfo->listURL = route('board.list', [$postInfo->code]);
  204. $postInfo->createdAt = $this->shortDate($postInfo->created_at);
  205. $datetime = (time() - strtotime($postInfo->created_at));
  206. $postInfo->isNew = ($datetime <= ($config->new_icon_hour * 3600)); // 시간 내에 포함하면 표시
  207. // 시간 내에 포함하거나 조회 수 이상이면 표시
  208. $postInfo->isHot = ($config->hot_icon_day > 0 ? ($datetime <= ($config->hot_icon_day * 86400)) : true)
  209. && ($config->hot_icon_hit > 0 ? ($config->hot_icon_hit <= $postInfo->hit) : false);
  210. $postInfo->isBlame = ($config->blame_blind_count && $postInfo->blame >= $config->blame_blind_count);
  211. $postInfo->hit = number_format($postInfo->hit);
  212. $postInfo->like = number_format($postInfo->like);
  213. $postInfo->user = new stdClass();
  214. $postInfo->user->name = ($config->use_anonymous ? '익명' : $postInfo->username);
  215. }
  216. return $postInfo;
  217. }
  218. /**
  219. * 게시판 캐시 삭제
  220. */
  221. public function clearLatest(string $code): void
  222. {
  223. Cache::tags('latest-board-' . $code)->flush();
  224. }
  225. }