라라벨 Livewire 4, 글 수정 기능 구현

포스트 썸네일 이미지

이전 포스트는 내용이 비교적 짧았는데, 오늘의 포스트에서는 해야 할 일이 많다.

글을 보며 따라 하는 입장에서는 금방 할 수 있을지도 모르지만, 글을 쓰는 입장에서는 글을 쓰는 시간이 굉장히 많이 걸린다.

나의 글을 봐주는 사람이 분명 있기는 있을 텐데, 이런 글 하나 쓰는 데에 시간이 굉장히 많이 걸린다는 것을 알아줬으면 좋겠다.


어쨌든 이번에는 정말로 글 수정 기능을 구현해 보겠다.




이전 포스트




전체적인 코드 수정은 이 깃허브 링크를 통해서 확인할 수 있다.




Livewire 컴포넌트 pages::articles.edit 생성 (--mfc 옵션)


make bash #컨테이너 안으로 들어간다.
php artisan make:livewire pages::articles.edit --mfc

ubuntu 혹은 VSCode의 터미널에서 이 명령어들을 실행한다.

이번에도 show 컴포넌트를 만들었을 때처럼 --mfc 옵션을 넣어보았다.




--mfc 옵션에 대한 자세한 내용은 이 포스트를 참고하자.





routes/web.php에서 라우팅 설정하기


routes/web.php

Route::middleware('auth')->group(function () {
    Route::view('profile', 'profile')->name('profile');
    Route::livewire('articles/new', 'pages::articles.new')->name('articles.new');
    // 추가
    Route::livewire('articles/{article:id}/edit', 'pages::articles.edit')->name('articles.edit');
});

라우팅 설정을 했다.

다른 코드들은 원래 있던 코드고, // 추가라는 주석 바로 아래의 한 줄만 새로 추가됐다.


로그인한 사용자만 글 수정 페이지에 접근할 수 있도록 라우트 그룹 내부에 코드를 추가했다.




위의 코드와 관련된 포스트들이다.

위의 포스트들에서 이미 충분히 설명했으니, 코드에 대한 설명은 생략하겠다.





개별글 페이지에 글 수정 버튼 생성


resources/views/pages/articles/⚡show.blade.php

<div class="border rounded-md p-3">
    <!-- 생략 -->
    <hr class="my-3">
    <p>{{$article->body}}</p>
</div>

<div class="flex items-center justify-end mt-3">
    <a href="{{ route('articles.edit', $article) }}" class="inline-flex items-center px-4 py-2 bg-gray-800 dark:bg-gray-200 border border-transparent rounded-md font-semibold text-xs text-white dark:text-gray-800 uppercase tracking-widest hover:bg-gray-700 dark:hover:bg-white focus:bg-gray-700 dark:focus:bg-white active:bg-gray-900 dark:active:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150" wire:navigate>
        {{ __('Edit') }}
    </a>
</div>

글 수정 버튼을 만들었다. (정확히는 버튼처럼 생긴 링크다.)


두 div 태그 중에서 위쪽은 원래 있던 코드고, 아래쪽이 글 수정 버튼이다.

버튼을 오른쪽으로 정렬하기 위해서 <div class="flex items-center justify-end mt-3"> 태그로 감쌌다.




개별글 페이지에 글 수정 버튼이 생겼다

개별글 페이지에 글 수정 버튼이 생겼다.

이 캡처 이미지처럼 버튼을 한글화를 하기 위해서는 lang/ko.json 파일에 코드를 추가하면 된다.




그 방법은 이 포스트 혹은 상단의 깃허브 링크를 참고하자.





글 수정 기능 구현 (fill 메서드)


이제 본격적으로 글을 수정하는 기능을 만들 차례다.




resources/views/pages/articles/⚡edit/edit.php

new class extends Component
{
    public Article $article;

    #[Validate('required|exists:categories,id')]
    public int $category_id;
    #[Validate('required|string|max:60')]
    public string $title;
    #[Validate('required|string|max:21844')]
    public string $body;

    public $childCategories = [];

    public function mount(Article $article)
    {
        $this->article = $article;

        $this->fill($this->article->only(['category_id', 'title', 'body']));

        $this->childCategories = Category::whereNotNull('parent_id')
            ->pluck('name', 'id')
            ->toArray();
    }

    public function save()
    {
        $this->validate();

        $this->article->update(
            $this->only(['category_id', 'title', 'body'])
        );

        return $this->redirectRoute('articles.show', $this->article, navigate: true);
    }
};

새 글 저장 기능을 구현했을 때와 겹치는 코드들이 많다.

이미 설명했던 코드들은 생략하고, 설명한 적이 없는 코드들에 대해서만 설명하겠다.


  • public int $category_id;: 각 프로퍼티 선언문 앞에 데이터 타입(int, string 등)을 명시했다.
  • $this->article = $article;: 라우트 모델 바인딩으로 받아온 $article 데이터를 클래스의 프로퍼티로 저장한다.
  • $this->fill($this->article->only(['category_id', 'title', 'body']));: 라라벨 Livewire에서 $this->fill() 메서드는 여러 개의 컴포넌트 프로퍼티(클래스 변수)에 한 번에 값을 대입해 주는 헬퍼 메서드다. 기존 $article 객체에서 수정에 필요한 3개 데이터만 추출하여 동일한 이름을 가진 컴포넌트의 프로퍼티($this->category_id 등)에 한 번에 값을 채워넣는 역할을 한다. 즉, category_id, title, body 등의 필드에 기존 데이터를 미리 입력해준다.
  • $this->article->update( ... );: update() 메서드는 데이터베이스에서 해당 글의 데이터를 수정한다. 그 안의 $this->only([ ... ])는 아래에 링크한 포스트인 '라라벨 Livewire를 이용해서 새 글 저장 기능 구현'에서 설명했었다.
  • return $this->redirectRoute('articles.show', $this->article, navigate: true);: 글의 수정이 끝나면 해당 글의 개별글 페이지로 리다이렉트 된다. $this->article은 상세 페이지 URL을 생성하는 데 필요한 라우트 파라미터Route Parameter 역할을 한다.




위에서 한번 링크했었던 포스트지만 다시 가져왔다.

public Article $article;에 대한 설명은 여기서 이미 했었다.




그 아래의 #[Validate] 어트리뷰트를 사용해서 유효성 검사를 하는 부분은 이 포스트에서 정리했었다.




그 아래의 코드들은 대부분 이 포스트에서 설명했었다.





resources/views/pages/articles/⚡edit/edit.blade.php

<div>
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
            {{ __('Edit') }}
        </h2>
    </x-slot>

    <div class="py-12">
        <div class="max-w-7xl mx-auto sm:px-3 lg:px-4">
            <div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
                <div class="p-6 text-gray-900 dark:text-gray-100">
                    <form wire:submit="save" class="space-y-4">
                        <!-- Category -->
                        <div>
                            <x-input-label for="category_id" :value="__('Category')" />
                            <x-select wire:model="category_id" id="category_id" class="block mt-1 w-full" name="category_id" required>
                                @foreach ($childCategories as $id => $name)
                                    <option value="{{ $id }}">
                                        {{ $name }}
                                    </option>
                                @endforeach
                            </x-select>
                            <x-input-error :messages="$errors->get('category_id')" class="mt-2" />
                        </div>

                        <!-- Title -->
                        <div>
                            <x-input-label for="title" :value="__('Title')" />
                            <x-text-input wire:model="title" id="title" class="block mt-1 w-full" type="text" name="title" required autofocus autocomplete="off" />
                            <x-input-error :messages="$errors->get('title')" class="mt-2" />
                        </div>

                        <!-- Body -->
                        <div>
                            <x-input-label for="body" :value="__('Body')" />
                            <x-textarea wire:model="body" id="body" rows="4" class="block mt-1 w-full" name="body" required autocomplete="off"></x-textarea>
                            <x-input-error :messages="$errors->get('body')" class="mt-2" />
                        </div>

                        <div class="flex items-center justify-end">
                            <x-primary-button>
                                {{ __('Save') }}
                            </x-primary-button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

새 글을 저장할 때의 ⚡new.blade.php코드와 거의 동일하다.

<form wire:submit="save">와 wire:model="..."에 대한 설명도 위에 링크한 포스트인 '라라벨 Livewire를 이용해서 새 글 저장 기능 구현'에서 이미 했었다.




글 수정 페이지

이젠 글을 수정할 수 있게 됐다.




하지만 아직은 완벽하지 않다.

현재는 남의 글도 수정할 수 있다는 치명적인 문제가 남아있다.


이 문제는 글을 삭제하는 기능까지 구현한 후에 해결하도록 하겠다.




다음 포스트

이 글이 도움이 됐거나 유익했다면 스크롤을 조금만 더 내려서 댓글을 남겨주세요. (비로그인도 가능합니다!)
응원이나 피드백이 담긴 댓글은 제가 계속 블로그를 해나갈 수 있는 원동력이 됩니다. 😊

지인에게 보여주고 싶은 글이었다면 URL을 복사해서 메신저나 소셜 미디어에 공유해 주세요.
이전 포스트 다음 포스트

댓글 쓰기

0 Comments

문의하기 양식