제가 나중에 활용하기 위해 또는 공부를 위해 작성한 코드입니다.
이미지 처리를 위해 "Intervention Image"를 사용하였습니다.
참고만 하시는게 정신건강에 도움이 됩니다.
<?php
if (!function_exists('admin_board_route')) {
/**
* 관리자 게시판 라우트 생성
* @param string $prefix
* @param string $controller
* @param string $boards
*/
function admin_board_route(string $prefix, string $controller, string $boards)
{
$name = str_replace('/', '.', $prefix);
// Index
Route::get("{$prefix}/{boardId}", [$controller, 'index'])
->where(["boardId" => "({$boards})"])
->name("{$name}.index");
// Create
Route::get("{$prefix}/{boardId}/create", [$controller, 'create'])
->where(["boardId" => "({$boards})"])
->name("{$name}.create");
// Store
Route::post("{$prefix}/{boardId}", [$controller, 'store'])
->where(["boardId" => "({$boards})"])
->name("{$name}.store");
// Show
Route::get("{$prefix}/{boardId}/{id}", [$controller, 'show'])
->where(["boardId" => "({$boards})", "id" => "[0-9]+"])
->name("{$name}.show");
// Edit
Route::get("{$prefix}/{boardId}/{id}/edit", [$controller, 'edit'])
->where(["boardId" => "({$boards})", "id" => "[0-9]+"])
->name("{$name}.edit");
// Update
Route::match(['PUT', 'PATCH'], "{$prefix}/{boardId}/{id}", [$controller, 'update'])
->where(["boardId" => "({$boards})", "id" => "[0-9]+"])
->name("{$name}.update");
// Delete
Route::delete("{$prefix}/{boardId}/{id}", [$controller, 'destroy'])
->where(["boardId" => "({$boards})", "id" => "[0-9]+"])
->name("{$name}.destroy");
// Editor Image Upload
Route::post("{$prefix}/{boardId}/imageUpload", [$controller, 'imageUpload'])
->where(["boardId" => "({$boards})"])
->name("{$name}.imageUpload");
// Comment Store
Route::post("{$prefix}/{boardId}/{id}", [$controller, 'commentStore'])
->where(["boardId" => "({$boards})", "id" => "[0-9]+"])
->name("{$name}.comment.store");
// Comment Update
Route::match(['PUT', 'PATCH'], "{$prefix}/{boardId}/{id}/comment/{commentId}", [$controller, 'commentUpdate'])
->where(["boardId" => "({$boards})", "id" => "[0-9]+", "commentId" => "[0-9]+"])
->name("{$name}.comment.update");
// Comment Delete
Route::delete("{$prefix}/{boardId}/{id}/comment/{commentId}", [$controller, 'commentDestroy'])
->where(["boardId" => "({$boards})", "id" => "[0-9]+", "commentId" => "[0-9]+"])
->name("{$name}.comment.destroy");
}
}
//----------------------------------------------------------------------------------------------------------------------
if (!function_exists('is_admin')) {
/**
* 관리자 레벨 확인
* @return bool
*/
function is_admin()
{
if (auth()->user()->user_level >= 1024) {
return true;
} else {
return false;
}
}
}
if (!function_exists('file_size_calc')) {
/**
* 파일 사이즈 계산 및 변환
* @param $fileByteSize
* @return string
*/
function file_size_calc($fileByteSize)
{
$sizes = [
'1073741824', // GB
'1048576', // MB
'1024', // KB
'0', // Byte
];
$units = [
'GB',
'MB',
'KB',
'Bytes'
];
$fileSize = 0;
$fileUnit = 'Byte';
foreach ($sizes as $key => $size) {
if ($fileByteSize >= $size) {
if ($size > 0) {
if ($key > 1) {
$round = 0;
} else {
$round = 2;
}
$fileSize = round($fileByteSize / $size, $round);
} else {
$fileSize = $fileByteSize;
}
$fileUnit = $units[$key];
break;
}
}
return $fileSize . ' ' . $fileUnit;
}
}
<?php
namespace App\Traits;
use App\Models\BoardComment;
use App\Models\BoardContent;
use App\Models\BoardFile;
use App\Models\BoardInfo;
use App\Models\BoardPost;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Intervention\Image\Facades\Image;
trait TraitBoard
{
protected $cookie;
protected $board;
protected $boardData = [];
protected $skin;
/**
* 게시판 정보 가져오기
* @param string $boardId
* @return mixed
*/
protected function getBoardInfo(string $boardId)
{
$this->board = BoardInfo::where('code', $boardId)->firstOrFail();
$this->skin = $this->board->skin ?? 'basic';
return $this->board;
}
/**
* 게시판 목록 가져오기
* @param string $boardId
* @param int $perPage
*/
protected function getBoardList(string $boardId, int $perPage = 15)
{
$boardInfo = $this->getBoardInfo($boardId);
$this->boardData['boardInfo'] = $boardInfo;
$this->boardData['lists'] = $boardInfo->posts()
->with('user', 'files')->withCount('comments')
// ->when() 검색 부분 추가 할 곳
->orderByDesc('notice')->latest()->paginate($perPage);
}
/**
* 게시글 쓰기 화면
* @param string $boardId
*/
protected function createPost(string $boardId)
{
$boardInfo = $this->getBoardInfo($boardId);
$this->boardData['boardInfo'] = $boardInfo;
$this->boardData['form'] = new BoardPost;
}
/**
* 게시글 저장하기
* @param Request $request
* @param string $boardId
*/
protected function storePost(Request $request, string $boardId)
{
DB::transaction(function () use ($request, $boardId) {
$boardInfo = $this->getBoardInfo($boardId);
// 1. BoardPost(게시글 저장)
$boardPost = new BoardPost;
if (auth()->guest()) {
// 비회원
$boardPost->name = $request->post('name');
$boardPost->password = Hash::make($request->post('password'));
} else {
// 회원
$boardPost->user_id = auth()->id();
$boardPost->name = auth()->user()->name;
}
$boardPost->subject = $request->post('subject');
$boardPost->notice = $request->post('notice', 'N');
// 비밀글
if ($boardInfo->force_secret === 'N') {
$boardPost->secret = $request->post('secret', 'N');
} else {
$boardPost->secret = 'Y';
}
// 조회수
$boardPost->read = 0;
// 에디터
($boardInfo->use_editor === 'Y') ? $boardPost->with_editor = 'Y' : $boardPost->with_editor = 'N';
$boardInfo->posts()->save($boardPost);
// 2. BoardContent(게시글 내용 저장)
$boardContent = new BoardContent;
$boardContent->content = $request->post('content');
$boardPost->content()->save($boardContent);
// 3. BoardFile(게시글 파일 저장)
if ($boardInfo->use_file === 'Y') {
if ($request->hasFile('upload_file') && is_array($request->file('upload_file'))) {
foreach ($request->file('upload_file') as $file) {
if ($file->isValid()) {
$uploadResult = $this->fileUpload($file, $boardId, $boardPost->id); // 여기서 실제 파일은 저장됨.
if ($uploadResult) {
$uploadFile = new BoardFile;
$uploadFile->original_file_name = $file->getClientOriginalName();
$uploadFile->file_name = $uploadResult['filename'];
$uploadFile->file_path = $uploadResult['path'];
$uploadFile->file_type = $file->getClientMimeType();
$uploadFile->file_size = $file->getSize();
$uploadFile->type = 'F';
$boardPost->files()->save($uploadFile);
}
}
}
}
}
// 4. BoardFile(썸네일 파일 저장)
if ($request->hasFile('thumbnail_file') && $request->file('thumbnail_file')->isValid()) {
$file = $request->file('thumbnail_file');
$uploadResult = $this->thumbnailUpload($file, $boardId, $boardPost->id); // 여기서 실제 파일은 저장됨.
if ($uploadResult) {
$uploadFile = new BoardFile;
$uploadFile->original_file_name = $file->getClientOriginalName();
$uploadFile->file_name = $uploadResult['filename'];
$uploadFile->file_path = $uploadResult['path'];
$uploadFile->file_type = $uploadResult['mime'];
$uploadFile->file_size = $uploadResult['size'];
$uploadFile->type = 'T';
$boardPost->files()->save($uploadFile);
}
}
});
}
/**
* 게시글 보기 화면
* @param string $boardId
* @param int $postId
*/
protected function showPost(string $boardId, int $postId)
{
$boardInfo = $this->getBoardInfo($boardId);
$this->boardData['boardInfo'] = $boardInfo;
$this->boardData['boardPost'] = $boardInfo->posts()
->with(['user', 'content', 'files', 'comments'])
->findOrFail($postId);
}
/**
* 게시글 수정 화면
* @param string $boardId
* @param int $postId
*/
protected function editPost(string $boardId, int $postId)
{
$boardInfo = $this->getBoardInfo($boardId);
$this->boardData['boardInfo'] = $boardInfo;
$this->boardData['form'] = $boardInfo->posts()
->with(['user', 'content', 'files', 'comments'])
->findOrFail($postId);
}
/**
* 게시글 수정하기
* @param Request $request
* @param string $boardId
* @param int $postId
*/
protected function updatePost(Request $request, string $boardId, int $postId)
{
DB::transaction(function () use ($request, $boardId, $postId) {
$boardInfo = $this->getBoardInfo($boardId);
// 1. BoardPost(게시글 수정)
$boardPost = $boardInfo->posts()->findOrFail($postId);
if (auth()->guest()) {
// 비회원
$boardPost->name = $request->post('name');
$boardPost->password = Hash::make($request->post('password'));
}
$boardPost->subject = $request->post('subject');
$boardPost->notice = $request->post('notice', 'N');
// 비밀글
if ($boardInfo->force_secret === 'N') {
$boardPost->secret = $request->post('secret', 'N');
} else {
$boardPost->secret = 'Y';
}
// 조회수
$boardPost->read = 0;
// 에디터
($boardInfo->use_editor === 'Y') ? $boardPost->with_editor = 'Y' : $boardPost->with_editor = 'N';
$boardPost->save();
// 2. BoardContent(게시글 내용 수정)
$boardContent = $boardPost->content;
$boardContent->content = $request->post('content');
$boardContent->save();
// 3. BoardFile(게시글 파일 저장)
if ($boardInfo->use_file === 'Y') {
if ($request->hasFile('upload_file') && is_array($request->file('upload_file'))) {
foreach ($request->file('upload_file') as $file) {
if ($file->isValid()) {
$uploadResult = $this->fileUpload($file, $boardId, $boardPost->id); // 여기서 실제 파일은 저장됨.
if ($uploadResult) {
$uploadFile = new BoardFile;
$uploadFile->original_file_name = $file->getClientOriginalName();
$uploadFile->file_name = $uploadResult['filename'];
$uploadFile->file_path = $uploadResult['path'];
$uploadFile->file_type = $file->getClientMimeType();
$uploadFile->file_size = $file->getSize();
$uploadFile->type = 'F';
$boardPost->files()->save($uploadFile);
}
}
}
}
}
// 4. BoardFile(썸네일 파일 수정)
if ($request->hasFile('thumbnail_file') && $request->file('thumbnail_file')->isValid()) {
$file = $request->file('thumbnail_file');
$uploadResult = $this->thumbnailUpload($file, $boardId, $boardPost->id); // 여기서 실제 파일은 저장됨.
if ($uploadResult) {
$uploadFile = $boardPost->files()->where('type', 'T')->first(); // 업로드 된 썸네일 있는지 확인.
if (empty($uploadFile)) {
$uploadFile = new BoardFile;
$uploadFile->original_file_name = $file->getClientOriginalName();
$uploadFile->file_name = $uploadResult['filename'];
$uploadFile->file_path = $uploadResult['path'];
$uploadFile->file_type = $uploadResult['mime'];
$uploadFile->file_size = $uploadResult['size'];
$uploadFile->type = 'T';
$boardPost->files()->save($uploadFile);
} else {
Storage::disk('public')->delete("{$uploadFile->file_path}/{$uploadFile->file_name}");
$uploadFile->original_file_name = $file->getClientOriginalName();
$uploadFile->file_name = $uploadResult['filename'];
$uploadFile->file_path = $uploadResult['path'];
$uploadFile->file_type = $uploadResult['mime'];
$uploadFile->file_size = $uploadResult['size'];
$uploadFile->type = 'T';
$uploadFile->save();
}
}
}
// 5. BoardFile(게시글 파일 삭제)
if (is_array($request->post('upload_file_delete'))) {
foreach ($request->post('upload_file_delete') as $list) {
$this->fileDelete($boardId, $boardPost->id, $list);
}
}
});
}
/**
* 첨부 파일 저장하기
* @param UploadedFile $file
* @param string $boardId
* @param int $postId
* @return string[]|null
*/
protected function fileUpload(UploadedFile $file, string $boardId, int $postId)
{
try {
$filename = 'F' . uniqid();
$folder = (int)ceil($postId / 1000);
$path = "board/upload/{$boardId}/{$folder}/{$postId}";
Storage::disk('public')->putFileAs($path, $file, $filename);
return [
'path' => $path,
'filename' => $filename,
];
} catch (\Exception $exception) {
return null;
}
}
/**
* 썸네일 파일 저장하기
* @param UploadedFile $file
* @param string $boardId
* @param int $postId
* @return array|null
*/
protected function thumbnailUpload(UploadedFile $file, string $boardId, int $postId)
{
try {
$filename = 'T' . uniqid();
$folder = (int)ceil($postId / 1000);
$path = "board/thumbnail/{$boardId}/{$folder}/{$postId}";
Storage::disk('public')->makeDirectory($path);
$thumbnailPath = storage_path("app/public/{$path}/{$filename}");
$thumbnailImage = Image::make($file->getRealPath())->orientate();
$thumbnailImage->resize(600, null, function ($constraint) {
$constraint->aspectRatio();
})->sharpen(15)->save($thumbnailPath, 85, 'jpg');
$size = $thumbnailImage->filesize();
$mime = $thumbnailImage->mime();
$thumbnailImage->destroy();
return [
'path' => $path,
'filename' => $filename,
'size' => $size,
'mime' => $mime,
];
} catch (\Exception $exception) {
return null;
}
}
/**
* 에디터 이미지 첨부 파일 저장하기
* @param Request $request
* @param string $boardId
*/
protected function editorImageUpload(Request $request, string $boardId)
{
$message = '';
$statusCode = '';
$url = '';
$boardInfo = $this->getBoardInfo($boardId);
if ($boardInfo->use_editor !== 'Y') {
$message = '에디터 사용 불가능한 게시판 입니다.';
$statusCode = '422';
}
$validatorRules = [
'upload' => 'bail|required|file|image|max:20480',
];
$validatorMessages = [
'max' => ':max KB 이하로 업로드해주세요.',
'image' => '이미지파일만 업로드 가능합니다',
];
$validator = Validator::make($request->all(), $validatorRules, $validatorMessages);
if ($validator->fails()) {
$message = $validator->errors()->first('upload');
$statusCode = '422';
} else {
try {
$filename = 'E' . uniqid();
$year = date('Y');
$month = date('n');
$day = date('j');
$file = $request->file('upload');
$path = "board/editor/{$boardId}/{$year}/{$month}/{$day}";
Storage::disk('public')->makeDirectory($path);
$editorImagePath = storage_path("app/public/{$path}/{$filename}");
$editorImage = Image::make($file->getRealPath())->orientate();
$editorImage->resize(1000, null, function ($constraint) {
$constraint->aspectRatio();
})->save($editorImagePath);
$editorImage->destroy();
$url = "/storage/{$path}/{$filename}";
$statusCode = '200';
} catch (\Exception $exception) {
$message = '업로드 중 에러가 발생했습니다.';
$statusCode = '422';
}
}
$this->boardData['returnValues'] = [
'message' => $message,
'statusCode' => $statusCode,
'url' => $url,
];
}
/**
* 첨부 파일 삭제하기
* @param string $boardId
* @param int $postId
* @param int $fileId
*/
protected function fileDelete(string $boardId, int $postId, int $fileId)
{
$boardInfo = $this->getBoardInfo($boardId);
$boardPost = $boardInfo->posts()->findOrFail($postId);
$boardFile = $boardPost->files()->findOrFail($fileId);
$filePath = "{$boardFile->file_path}/{$boardFile->file_name}";
Storage::disk('public')->delete($filePath);
$boardFile->delete();
}
/**
* 댓글 저장하기
* @param Request $request
* @param string $boardId
* @param int $postId
*/
protected function storeComment(Request $request, string $boardId, int $postId)
{
DB::transaction(function () use ($request, $boardId, $postId) {
$boardInfo = $this->getBoardInfo($boardId);
$boardPost = $boardInfo->posts()->findOrFail($postId);
$comment = new BoardComment;
if (auth()->guest()) {
// 비회원
$comment->name = $request->post('name');
$comment->password = Hash::make($request->post('password'));
} else {
// 회원
$comment->user_id = auth()->id();
$comment->name = auth()->user()->name;
}
$comment->comment = $request->post('comment');
$boardPost->comments()->save($comment);
});
}
/**
* 댓글 수정하기
* @param Request $request
* @param string $boardId
* @param int $postId
* @param int $commentId
* @return mixed
*/
protected function updateComment(Request $request, string $boardId, int $postId, int $commentId)
{
return DB::transaction(function () use ($request, $boardId, $postId, $commentId) {
$boardInfo = $this->getBoardInfo($boardId);
$boardPost = $boardInfo->posts()->findOrFail($postId);
$comment = $boardPost->comments()->findOrFail($commentId);
if ($comment->user_id === null) {
// 비회원이 남긴 댓글은 비밀번호 비교하기
if (!Hash::check($request->input('password'), $comment->password)) {
return false;
}
} elseif ($comment->user_id !== auth()->id()) {
return false;
}
$comment->comment = $request->post('comment');
$comment->save();
return true;
});
}
/**
* 댓글 삭제하기
* @param Request $request
* @param string $boardId
* @param int $postId
* @param int $commentId
* @return mixed
*/
protected function destroyComment(Request $request, string $boardId, int $postId, int $commentId)
{
return DB::transaction(function () use ($request, $boardId, $postId, $commentId) {
$boardInfo = $this->getBoardInfo($boardId);
$boardPost = $boardInfo->posts()->findOrFail($postId);
$comment = $boardPost->comments()->findOrFail($commentId);
if ($comment->user_id === null) {
// 비회원이 남긴 댓글은 비밀번호 비교하기
if (!Hash::check($request->input('password'), $comment->password)) {
return false;
}
}
$comment->delete();
return true;
});
}
}
<?php
namespace App\Http\Controllers\Admin\Board;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\BoardCommentStore;
use App\Http\Requests\Admin\BoardCommentUpdate;
use App\Http\Requests\Admin\BoardStore;
use App\Http\Requests\Admin\BoardUpdate;
use App\Traits\TraitBoard;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\View;
class BoardController extends Controller
{
use TraitBoard;
/**
* @param string $boardId
* @return \Illuminate\Contracts\View\View
*/
public function index(string $boardId)
{
$perPage = 15;
$this->getBoardList($boardId, $perPage);
// return View::first(["admin.board.skin.{$this->skin}.index", 'admin.board.skin.basic.index'], $this->boardData);
return view()->first(["admin.board.skin.{$this->skin}.index", 'admin.board.skin.basic.index'], $this->boardData);
}
/**
* @param string $boardId
* @return \Illuminate\Contracts\View\View
*/
public function create(string $boardId)
{
$this->createPost($boardId);
return View::first(["admin.board.skin.{$this->skin}.create", 'admin.board.skin.basic.create'], $this->boardData);
}
/**
* @param BoardStore $request
* @param string $boardId
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function store(BoardStore $request, string $boardId)
{
$this->storePost($request, $boardId);
return redirect(route('admin.board.boardManagement.index', ['boardId' => $boardId]))
->with('alert-primary', '등록되었습니다.');
}
/**
* @param Request $request
* @param string $boardId
* @param int $id
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
*/
public function show(Request $request, string $boardId, int $id)
{
$this->showPost($boardId, $id);
$cookie = unserialize($request->cookie('readIds'));
if (empty($cookie)) {
$cookie = [];
}
if (!in_array($id, $cookie)) {
$cookie[] = $id;
$this->boardData['boardPost']->timestamps = false;
$this->boardData['boardPost']->increment('read');
$this->boardData['boardPost']->timestamps = true;
}
$routeName = explode('.', Route::currentRouteName());
$this->boardData['route'] = implode('.', $routeName);
return response(View::first(["admin.board.skin.{$this->skin}.show", 'admin.board.skin.basic.show'], $this->boardData))
->cookie('readIds', serialize($cookie));
}
/**
* @param string $boardId
* @param int $id
* @return \Illuminate\Contracts\View\View
*/
public function edit(string $boardId, int $id)
{
$this->editPost($boardId, $id);
return View::first(["admin.board.skin.{$this->skin}.edit", 'admin.board.skin.basic.edit'], $this->boardData);
}
/**
* @param BoardUpdate $request
* @param string $boardId
* @param int $id
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function update(BoardUpdate $request, string $boardId, int $id)
{
$this->updatePost($request, $boardId, $id);
return redirect(route('admin.board.boardManagement.show', ['boardId' => $boardId, 'id' => $id]))
->with('alert-success', '수정되었습니다.');
}
public function destroy()
{
}
/**
* @param Request $request
* @param string $boardId
* @return \Illuminate\Http\JsonResponse
*/
public function imageUpload(Request $request, string $boardId)
{
$this->editorImageUpload($request, $boardId);
$returnValues = $this->boardData['returnValues'];
if ($returnValues['statusCode'] === '200') {
$data = [
'url' => $returnValues['url'],
];
} else {
$data = [
'error' => [
'message' => $returnValues['message'],
],
];
}
return response()->json($data, $returnValues['statusCode']);
}
/**
* @param BoardCommentStore $request
* @param string $boardId
* @param int $id
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function commentStore(BoardCommentStore $request, string $boardId, int $id)
{
$this->storeComment($request, $boardId, $id);
return redirect(route('admin.board.boardManagement.show', ['boardId' => $boardId, 'id' => $id]))
->with('alert-primary', '댓글이 등록되었습니다.');
}
/**
* @param BoardCommentUpdate $request
* @param string $boardId
* @param int $id
* @param int $commentId
* @return \Illuminate\Http\JsonResponse
*/
public function commentUpdate(BoardCommentUpdate $request, string $boardId, int $id, int $commentId)
{
$result = $this->updateComment($request, $boardId, $id, $commentId);
$answer = $result ? '댓글이 수정되었습니다.' : '권한이 없습니다.';
return response()->json(['msg' => $answer], 200);
}
/**
* @param Request $request
* @param string $boardId
* @param int $id
* @param int $commentId
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function commentDestroy(Request $request, string $boardId, int $id, int $commentId)
{
$result = $this->destroyComment($request, $boardId, $id, $commentId);
$answerColor = $result ? 'alert-danger' : 'alert-info';
$answerMsg = $result ? '댓글이 삭제되었습니다.' : '권한이 없습니다.';
return redirect(route('admin.board.boardManagement.show', ['boardId' => $boardId, 'id' => $id]))
->with($answerColor, $answerMsg);
}
}
이상입니다.