PHP강좌/[라라벨]게시판만들기강좌

[라라벨+mysql]게시판 만들기 강좌 #22. 댓글 등록하기

에스크리토 2024. 8. 5. 15:07
반응형

댓글을 등록할 수 있는 화면부터 만들어 보자.

 

/resources/views/boards/view.blade.php

@extends('boards.layout')

@section('header')
    @include('boards.toptitle', ['toptitle'=>'게시판 보기', 'multi'=>$boards->multi])
@endsection

@section('content')

    <table class="table table-striped table-hover">
        <tbody>
            <tr>
                <th width="200">제목</th>
                <td>{{ $boards->subject }}</td>
            </tr>
            <tr>
                <td colspan="2">글쓴이 : {{ $boards->userid }} / 조회수 : {{ number_format($boards->cnt) }} / 등록일 : {{ $boards->regdate }}</td>
            </tr>
            <tr>
                <th width="200">내용</th>
                <td>{!! nl2br($boards->content) !!}</td>
            </tr>
            @if(count($attaches)>0)
            <tr>
                <th width="200">첨부 이미지</th>
                <td>
                    <div class="row row-cols-1 row-cols-md-6 g-4" id="attachFiles" style="margin-left:0px;">
                    @foreach ($attaches as $att)
                    <div id='af_{{ $att->id }}' class='card h-100' style='width:120px;margin-right: 10px;margin-bottom: 10px;'><a href="#" onclick="window.open('/boards/imgpop/{{ $att->filename }}','imgpop','width=600,height=400,scrollbars=yes');"><img src='/images/{{ $att->filename }}' width='100' /></a></div>
                    @endforeach
                    </div>
                </td>
            </tr>
            @endif
        </tbody>
    </table>
    <div align="right">
        @auth()
            @if($boards->userid==auth()->user()->userid)
                <a href="/boards/write/{{ $boards->multi }}/{{ $boards->bid }}"><button type="button" class="btn btn-secondary">수정</button></a>
                <a href="/boards/delete/{{ $boards->bid }}/{{ $boards->pagenumber }}" class="btn btn-secondary" onclick="return confirm('삭제하시겠습니까?');">삭제</a>
            @endif
        @endauth
        <a href="/boards/{{ $boards->multi }}/?page={{ $boards->pagenumber }}" class="btn btn-primary">목록</a>
    </div>
    <div style="padding:10px;">
    </div>
    <!-- 댓글 입력 -->
    <div class="input-group" id="firstmemo" style="margin-top:10px;margin-bottom:10px;">
        <span class="input-group-text" id="memo_image_view" style="display:none;"></span>
        <button type="button" id="attmemoimg" class="btn btn-secondary">이미지첨부</button>
        <input type="file" name="upfile" id="upfile" accept="image/*" style="display:none;">
        <textarea class="form-control" aria-label="With textarea" style="height:100px;" name="memo" id="memo" placeholder="댓글을 입력해주세요"></textarea>
        @auth()
            <button type="button" class="btn btn-secondary" style="float:right;" id="memo_submit" onclick="memoup()">입력</button>
        @else
            <button type="button" class="btn btn-secondary" style="float:right;" id="memo_submit" onclick="alert('로그인 하셔야 입력할 수 있습니다.');">입력</button>
        @endauth
    </div>
    <!-- 댓글 입력 끝-->
    <div style="padding:20px;">
    </div>
    <script>
        function memoup(){
            var memo=$("#memo").val();
            var data = {
                memo : memo,
                bid : {{ $boards->bid }}
            };
            $.ajax({
                headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
                type: 'post',
                url: '{{ route('boards.memoup') }}',
                dataType: 'json',
                data: data,
                success: function(data) {
                    location.reload();
                },
                error: function(data) {
                console.log("error" +JSON.stringify(data));
                }
            });
        }
    </script>
    @endsection    

 

댓글을 입력할 수 있는 부분을 추가했다. 로그인한 회원만 댓글을 달 수 있도록 if문을 이용해 구분해 주었다. 메모를 쓰고 등록 버튼을 누르면 memoup()함수가 작동한다. 아래에 함수를 보고 거기에 맞게 라우터와 콘트롤러를 만들어보자.

 

/routes/web.php

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\BoardController;
use App\Http\Controllers\MemberController;

Route::get('/', function () {
    return view('welcome');
});

//게시판
Route::get('/boards/{multi?}', [BoardController::class, 'index'])->name('boards.index');
Route::get('/boards/show/{id}/{page}', [BoardController::class, 'show'])->name('boards.show');

Route::middleware('auth') -> group(function (){
    Route::get('/boards/write/{multi}/{bid?}', [BoardController::class, 'write'])->name('boards.write');
    Route::post('/boards/create', [BoardController::class, 'create'])->name('boards.create');
    Route::post('/boards/saveimage', [BoardController::class, 'saveimage'])->name('boards.saveimage');
    Route::post('/boards/deletefile', [BoardController::class, 'deletefile'])->name('boards.deletefile');
    Route::get('/boards/imgpop/{imgfile}', [BoardController::class, 'imgpop'])->name('boards.imgpop');
    Route::post('/boards/update', [BoardController::class, 'update'])->name('boards.update');
    Route::get('/boards/delete/{bid}/{page}', [BoardController::class, 'delete'])->name('boards.delete');
    Route::get('/boards/summernote/{multi}/{bid?}', [BoardController::class, 'summernote'])->name('boards.summernote');
    Route::post('/boards/memoup', [BoardController::class, 'memoup'])->name('boards.memoup');
});

//회원
Route::get('/login', [MemberController::class, 'login'])->name('auth.login');
Route::get('/signup', [MemberController::class, 'signup'])->name('auth.signup');
Route::post('/signupok', [MemberController::class, 'signupok'])->name('auth.signupok');
Route::post('/emailcheck', [MemberController::class, 'emailcheck'])->name('auth.emailcheck');
Route::post('/loginok', [MemberController::class, 'loginok']) -> name('auth.loginok');
Route::post('/logout', [MemberController::class, 'logout']) -> name('auth.logout');

 

/app/Http/Controllers/BoardController.php


    public function memoup(Request $request)
    {
        $insert_data = new Memos();
        $insert_data->memo = $request->memo;
        $insert_data->bid = $request->bid;
        $insert_data->pid = $request->pid??null;
        $insert_data->userid = Auth::user()->userid;

        if(auth()->check()){
            $rs = $insert_data->save();
            if($rs){
                Board::find($request->bid)->increment('memo_cnt');//부모글의 댓글 갯수 업데이트
                Board::where('bid', $request->bid)->update([//부모글의 댓글 날짜 업데이트
                    'memo_date' => date('Y-m-d H:i:s')
                ]);
            }

            return response()->json(array('msg'=> "succ", 'num'=>$rs), 200);
        }
    }
   

 

댓글을 달면 댓글을 단 본문 글에 memo_cnt와 memo_date를 업데이트 한다. 그런데 지금 테이블엔 두 컬럼이 없으므로 추가해준다.(라라벨의 migrate를 이용해도 되고 그냥 컬럼을 추가해도 된다. 각자 알아서 추가해주자.) 그리고 모델을 수정해 준다.

 

/app/Models/Board.php

   
    protected $fillable = [
        'content', 'multi', 'subject', 'userid', 'cnt', 'status', 'attachfiles', 'memo_cnt', 'memo_date'
    ];

 

fillable에 새로 만든 두개 컬럼을 추가해 준다.

 

이렇게 하고 테스트를 해보자. memos 테이블에 값이 추가되고 memo_cnt와 memo_date에 값이 제대로 들어갔으면 성공이다.

 

아직은 작성한 댓글이 보이지 않는다. 화면에 나타나도록 하기 위해서 콘트롤러를 수정해 준다.

 

/app/Http/Controllers/BoardController.php


    public function show($bid,$page)
    {
        Board::find($bid)->increment('cnt');
        $boards = Board::findOrFail($bid);
        $boards->content = htmlspecialchars_decode($boards->content);
        $boards->pagenumber = $page??1;
        $attaches = FileTables::where('pid',$bid)->where('code','boardattach')->where('status',1)->get();

        $memos = Memos::where('bid', $bid)->where('status',1)
                        ->orderBy('id', 'asc')
                        ->get();

        return view('boards.view', ['boards' => $boards, 'attaches' => $attaches, 'memos' => $memos]);
    }

 

이렇게 메모 부분을 같이 보내준다. 그러면 화면에 나타나도록 뷰도 수정해 보자.

 

/resources/views/boards/view.blade.php

@extends('boards.layout')

@section('header')
    @include('boards.toptitle', ['toptitle'=>'게시판 보기', 'multi'=>$boards->multi])
@endsection

@section('content')

    <table class="table table-striped table-hover">
        <tbody>
            <tr>
                <th width="200">제목</th>
                <td>{{ $boards->subject }}</td>
            </tr>
            <tr>
                <td colspan="2">글쓴이 : {{ $boards->userid }} / 조회수 : {{ number_format($boards->cnt) }} / 등록일 : {{ $boards->regdate }}</td>
            </tr>
            <tr>
                <th width="200">내용</th>
                <td>{!! nl2br($boards->content) !!}</td>
            </tr>
            @if(count($attaches)>0)
            <tr>
                <th width="200">첨부 이미지</th>
                <td>
                    <div class="row row-cols-1 row-cols-md-6 g-4" id="attachFiles" style="margin-left:0px;">
                    @foreach ($attaches as $att)
                    <div id='af_{{ $att->id }}' class='card h-100' style='width:120px;margin-right: 10px;margin-bottom: 10px;'><a href="#" onclick="window.open('/boards/imgpop/{{ $att->filename }}','imgpop','width=600,height=400,scrollbars=yes');"><img src='/images/{{ $att->filename }}' width='100' /></a></div>
                    @endforeach
                    </div>
                </td>
            </tr>
            @endif
        </tbody>
    </table>
    <div align="right">
        @auth()
            @if($boards->userid==auth()->user()->userid)
                <a href="/boards/write/{{ $boards->multi }}/{{ $boards->bid }}"><button type="button" class="btn btn-secondary">수정</button></a>
                <a href="/boards/delete/{{ $boards->bid }}/{{ $boards->pagenumber }}" class="btn btn-secondary" onclick="return confirm('삭제하시겠습니까?');">삭제</a>
            @endif
        @endauth
        <a href="/boards/{{ $boards->multi }}/?page={{ $boards->pagenumber }}" class="btn btn-primary">목록</a>
    </div>
    <div style="padding:10px;">
    </div>

    <!--댓글 리스트 시작 -->
    <div id="reply">
        @foreach ($memos as $m)
        <div class="card mt-2" id="{{ 'memolist_'.$m->id }}">
            <div class="card-header p-2">
                <table>
                    <tbody>
                        <tr class="align-middle">
                            <td rowspan="2" class="pr-2">
                                <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" fill="currentColor" class="bi bi-chat-square-dots" viewBox="0 0 16 16">
                                    <path d="M14 1a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1h-2.5a2 2 0 0 0-1.6.8L8 14.333 6.1 11.8a2 2 0 0 0-1.6-.8H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1zM2 0a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2.5a1 1 0 0 1 .8.4l1.9 2.533a1 1 0 0 0 1.6 0l1.9-2.533a1 1 0 0 1 .8-.4H14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/>
                                    <path d="M5 6a1 1 0 1 1-2 0 1 1 0 0 1 2 0m4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0m4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0"/>
                                </svg>
                            </td>
                            <td class="ml">{{ $m->userid }}</td>
                        </tr>
                        <tr>
                            <td>
                                {{ disptime($m->created_at) }}
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
            <div class="card-body">
                <p class="card-text">{!! nl2br($m->memo) !!}</p>
            </div>
        </div>
        @endforeach
    </div>
    <!-- 댓글 리스트 끝 -->

    <!-- 댓글 입력 -->
    <div class="input-group" id="firstmemo" style="margin-top:10px;margin-bottom:10px;">
        <span class="input-group-text" id="memo_image_view" style="display:none;"></span>
        <button type="button" id="attmemoimg" class="btn btn-secondary">이미지첨부</button>
        <input type="file" name="upfile" id="upfile" accept="image/*" style="display:none;">
        <textarea class="form-control" aria-label="With textarea" style="height:100px;" name="memo" id="memo" placeholder="댓글을 입력해주세요"></textarea>
        @auth()
            <button type="button" class="btn btn-secondary" style="float:right;" id="memo_submit" onclick="memoup()">입력</button>
        @else
            <button type="button" class="btn btn-secondary" style="float:right;" id="memo_submit" onclick="alert('로그인 하셔야 입력할 수 있습니다.');">입력</button>
        @endauth
    </div>
    <!-- 댓글 입력 끝-->
    <div style="padding:20px;">
    </div>
    <script>
        function memoup(){
            var memo=$("#memo").val();
            var data = {
                memo : memo,
                bid : {{ $boards->bid }}
            };
            $.ajax({
                headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
                type: 'post',
                url: '{{ route('boards.memoup') }}',
                dataType: 'json',
                data: data,
                success: function(data) {
                    location.reload();
                },
                error: function(data) {
                console.log("error" +JSON.stringify(data));
                }
            });
        }
    </script>
    @endsection    

 

memos를 받아서 화면에 뿌려주도록 수정했다.

 

이렇게 나타나게 된다. 다음 시간엔 이미지 첨부하는걸 해보자.

반응형