build(); }); return response($xml, 200)->header('Content-Type', 'application/xml; charset=utf-8'); } private function build(): string { // 레이아웃의 canonical(url()->current())과 같은 방식으로 요청 기준 주소를 쓴다. // config('app.url') 은 환경파일 값에 좌우되어(로컬은 local-blog.web.or.kr) 어긋날 수 있다. $baseUrl = rtrim(url('/'), '/'); $today = date('Y-m-d'); $xml = '' . PHP_EOL; $xml .= '' . PHP_EOL; // 고정 페이지 $xml .= $this->url("{$baseUrl}/", $today, 'daily', '1.0'); $xml .= $this->url("{$baseUrl}/recently", $today, 'daily', '0.8'); $xml .= $this->url("{$baseUrl}/tag", $today, 'daily', '0.6'); // 문서 페이지. tb_document 에 노출 여부 컬럼을 확인하지 못해 현재 공개된 두 건만 둔다. $xml .= $this->url("{$baseUrl}/document/profile", $today, 'monthly', '0.5'); $xml .= $this->url("{$baseUrl}/document/proposal", $today, 'monthly', '0.5'); // 게시판 목록 $boards = DB::table('tb_board') ->where('is_display', '=', 1) ->orderBy('sort') ->pluck('code'); foreach ($boards as $code) { $xml .= $this->url("{$baseUrl}/board/{$code}", $today, 'daily', '0.8'); } // 게시글. 공지/전체공지도 실제로 열리는 페이지이므로 함께 넣는다. DB::table('tb_post') ->join('tb_board', 'tb_board.id', '=', 'tb_post.board_id') ->where('tb_board.is_display', '=', 1) ->where('tb_post.is_delete', '=', 0) ->where('tb_post.is_secret', '=', 0) ->where('tb_post.is_personal', '=', 0) ->select('tb_board.code', 'tb_post.id', 'tb_post.updated_at', 'tb_post.created_at') ->orderBy('tb_post.id') ->chunk(1000, function ($posts) use (&$xml, $baseUrl, $today) { foreach ($posts as $post) { $modified = $post->updated_at ?: $post->created_at; $lastModified = $modified ? date('Y-m-d', strtotime($modified)) : $today; $xml .= $this->url("{$baseUrl}/board/{$post->code}/{$post->id}", $lastModified, 'weekly', '0.6'); } }); $xml .= '' . PHP_EOL; return $xml; } private function url(string $location, string $lastModified, string $changeFrequency, string $priority): string { return ' ' . PHP_EOL . ' ' . htmlspecialchars($location, ENT_XML1) . '' . PHP_EOL . ' ' . $lastModified . '' . PHP_EOL . ' ' . $changeFrequency . '' . PHP_EOL . ' ' . $priority . '' . PHP_EOL . ' ' . PHP_EOL; } }