이번 블랙프라이데이에서 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
이렇게 저장됩니다.
데이타베이스 용량도 줄이고 검색 쿼리도 더 빨라 질 것 같습니다. ^^
# 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);
}
}
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를 했었습니다만, 여기는 그냥 해당 댓글을 감춰버리는 방식을 사용하네요.
# 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 채팅방 구현)을 들어볼 예정입니다.
In the
reply
method, the conditionreturn is_null($comment->parent_id);
ensures that only comments without a parent can be replied to. Would this logic need to be adjusted if you plan to support nested or threaded Buckshot Roulette comments where replies can have multiple levels (i.e., replies to replies)? How would you handle permission for replying to a comment in such a case?