Livewire Comment System

김윤수·2024년 12월 12일
0

laravel

목록 보기
15/15

이번 블랙프라이데이에서 livewire 관련 강좌가 많은 코드코스 1년 강좌 포로그램이 50% 할인($120 > $60)이라 구매하였습니다.

가장 익숙한 내용인 댓글(comment) 강좌를 3일간 다 들고 난 뒤 내용 정리를 해둡니다.

늘 아는 내용이라고 생각했지만, 역시 강좌를 듣다가 보니 새로운 내용이 좀 있었네요.

마이그레이션

회원 탈퇴시 댓글은 남아 있게 마이그레이션
다형성(morph)도 nullable 하게

$table->foreignId('user_id')->nullable()->constrained()
    ->nullOnDelete(); # not cascadeOnDelete()
$table->nullableMorphs('commentable');

아니면 회원 탈퇴시 댓글 모두 삭제 처리하려면 모델 이벤트 처리

# User.php
public static function booted()
{
    static::deleting(static function (User $user) {
        $user->comments()->delete();
    });
}

다형성 모델 매핑

다형성 모델을 통해 댓글(comment) 모델을 저장하고 있는데 특이한 점은

commentable_type: App\Models\Article
commentable_id: 1

원래 이렇게 저장되어 있는데

# AppServiceProvider 
    public function boot(): void
    {
        Relation::enforceMorphMap([
            'article' => Article::class,
        ]);
    }
}

다형성 모델을 매핑을 이렇게 해두면

commentable_type: article
commentable_id: 1

이렇게 저장됩니다.
데이타베이스 용량도 줄이고 검색 쿼리도 더 빨라 질 것 같습니다. ^^

Policy를 권한 처리

# CommentItem.php
public function replyComment()
{
	$this->authorize('reply', $this->comment);
	....
}

# CommentPolicy.php
class CommentPolicy
{
    public function reply(User $user, Comment $comment)
    {
        return is_null($comment->parent_id);
    }
}

Apline Directive

livewire와 찰떡 궁합인 alpinjs를 이용한 directive(지침?) 처리
datetime 값을 기준으로 작성시간이 계속 변경됨
예: 몇초 전 > 1분 전 > 2분 전 ...

/** app.js */

import { Livewire, Alpine } from '../../vendor/livewire/livewire/dist/livewire.esm.js';

import humanDate from './directives/humanDate.js';

Alpine.directive('human-date', humanDate);
/** humanDate.js */
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
import utc from 'dayjs/plugin/utc'
import timezone from 'dayjs/plugin/timezone'
import ko from 'dayjs/locale/ko'

dayjs.extend(relativeTime)
dayjs.extend(utc)
dayjs.extend(timezone)
dayjs.locale(ko)

dayjs.tz.setDefault('Asia/Seoul')

export default (el) => {
    let datetime = el.getAttribute('datetime')

    if (!datetime) {
        return
    }

    const setHumanTime = () => {
        el.innerText = dayjs().tz().to(dayjs.tz(datetime))
    }

    setHumanTime()
    setInterval(setHumanTime, 30000)
}
# comment-item.blade.php
<div class="text-sm"
     x-human-date
     datetime="{{ $comment->created_at->toDateTimeString() }}">
    {{ $comment->created_at->diffForHumans() }}
</div>

댓글 삭제후 전체 목록 refresh

원래 제 스타일은 삭제가 발생하면 페이지 전체를 refresh를 했었습니다만, 여기는 그냥 해당 댓글을 감춰버리는 방식을 사용하네요.

# CommentItem
<?php

namespace App\Livewire;

use App\Livewire\Forms\CreateComment;
use App\Livewire\Forms\EditComment;
use App\Models\Comment;
use Livewire\Component;

class CommentItem extends Component
{
    public Comment $comment;
    public bool    $deleted = false;
    ....

    public function deleteComment()
    {
        ...
        $this->deleted = true;
    }
}


# comment-item.blade.php
<div>
    @if (! $deleted)
        <div ...>
    @endif
</div>

다음은 Build a Multi-room Realtime Chat with Livewire and Reverb (Reverb + livwire 채팅방 구현)을 들어볼 예정입니다.

profile
안녕하세요

0개의 댓글