【Laravel】掲示板を作成する(5)投稿編集機能、投稿の物理削除
Laravelによる掲示板の作成、第5回です。
今回は「投稿編集」機能と「投稿の物理削除」機能についてポストします。
(第1回)1.各種設定
(第1回)2.マイグレーションでDBを作成する
(第2回)3.Eloquent機能を使いモデルのリレーションを設定する
(第2回)4.LaravelのSeed機能とFakerを使ってDBにテストデータを登録する
(第3回)5.一覧画面の作成
(第3回)6.詳細画面の作成
(第4回)7.新規投稿機能の作成
(第4回)8.コメント投稿機能の作成
(今回)9.投稿編集機能の作成
(今回)10.投稿の物理削除機能の作成
9.投稿編集機能の作成
投稿を編集できるようにします。
ユーザー登録をし、投稿した本人が編集するといったような機能はなく、単に管理者がデータベースに登録されているデータを画面上から編集するというものです。
ルーティング追記
編集ファイル:routes/web.php
edit と update を追加します。
editが編集フォーム画面、updateが編集実行のアクションという割当です。
1 2 3 4 5 |
Route::resource('bbs', 'PostsController', ['only' => ['index', 'show', 'create', 'store']]); ↓↓↓↓↓ edit と update を追加 Route::resource('bbs', 'PostsController', ['only' => ['index', 'show', 'create', 'store', 'edit', 'update']]); |
Postsコントローラーを編集
編集ファイル:app\Http\Controllers\PostsController.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/** * 編集画面 */ public function edit($post_id) { $post = Post::findOrFail($post_id); return view('bbs.edit', ['post' => $post]); } /** * 編集実行 */ public function update(PostRequest $request) { $savedata = [ 'name' => $request->name, 'subject' => $request->subject, 'message' => $request->message, 'category_id' => $request->category_id, ]; $post = new Post; $post->fill($savedata)->save(); return redirect('/bbs')->with('poststatus', '投稿を編集しました'); } |
編集画面ビューを作成
編集画面のビューを作成します。今回は create 用のビューをコピーして改変ました(だいぶ楽)。
編集ファイル:resources\views\bbs\edit.blade.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
@extends('layout.bbslayout') @section('title', 'LaravelPjt BBS 投稿編集ページ') @section('keywords', 'キーワード1,キーワード2,キーワード3') @section('description', '投稿編集ページの説明文') @section('pageCss') <link href="/css/bbs/style.css" rel="stylesheet"> @endsection @include('layout.bbsheader') @section('content') <div class="container mt-4"> <div class="border p-4"> <h1 class="h4 mb-4 font-weight-bold"> 投稿の編集 </h1> <form method="POST" action="{{ route('bbs.update', $post->id) }}"> @csrf @method('PUT') <fieldset class="mb-4"> <div class="form-group"> <label for="subject"> 名前 </label> <input id="name" name="name" class="form-control {{ $errors->has('name') ? 'is-invalid' : '' }}" value="{{ old('name') ?: $post->name }}" type="text" > @if ($errors->has('name')) <div class="invalid-feedback"> {{ $errors->first('name') }} </div> @endif </div> <div class="form-group"> <label for="subject"> カテゴリー </label> <input id="category_id" name="category_id" class="form-control {{ $errors->has('category_id') ? 'is-invalid' : '' }}" value="{{ old('category_id') ?: $post->category_id }}" type="text" > @if ($errors->has('category_id')) <div class="invalid-feedback"> {{ $errors->first('category_id') }} </div> @endif </div> <div class="form-group"> <label for="subject"> 件名 </label> <input id="subject" name="subject" class="form-control {{ $errors->has('subject') ? 'is-invalid' : '' }}" value="{{ old('subject') ?: $post->subject }}" type="text" > @if ($errors->has('subject')) <div class="invalid-feedback"> {{ $errors->first('subject') }} </div> @endif </div> <div class="form-group"> <label for="message"> メッセージ </label> <textarea id="message" name="message" class="form-control {{ $errors->has('message') ? 'is-invalid' : '' }}" rows="4" >{{ old('message') ?: $post->message }}</textarea> @if ($errors->has('message')) <div class="invalid-feedback"> {{ $errors->first('message') }} </div> @endif </div> <div class="mt-5"> <a class="btn btn-secondary" href="{{ route('bbs.show', $post->id) }}"> キャンセル </a> <button type="submit" class="btn btn-primary"> 編集する </button> </div> </fieldset> </form> </div> </div> @endsection @include('layout.bbsfooter') |
投稿内容をフォームへ反映するには
名前やメッセージなど元の投稿内容は、三項演算で判定して value に設定しています。
該当部分を抜粋します。
1 2 3 4 5 6 7 |
<input id="name" name="name" class="form-control {{ $errors->has('name') ? 'is-invalid' : '' }}" value="{{ old('name') ?: $post->name }}" // ←★この部分 type="text" > |
「疑似フォームメソッド」について
フォームの上の方に
1 |
@method('PUT') |
という記述がありますが、これはLaravelのhttpメソッドでは GETリクエストとPOSTリクエストしか対応しておらず、PUTやPATCH、DELETEリクエストを使用する際は「擬似フォームメソッド」というものを使用ます。
擬似フォームメソッドは、フォームのパラメータとして擬似的にメソッド名を埋め込み、それに合わせてLaravel側で擬似的にputやdeleteを扱う仕組みとのことです。
『HTTPメソッドに意味をもたせて機能性を分ける』というのがRESTという概念で、Laravelの場合、ルーティングはURLとHTTPメソッドの組に対して定義されますので、使い分けないとリクエストが正しく処理されません。
LaravelのRESTコントローラでは、新規作成のstoreはPOST、更新のupdateはPATCH(PUT)が対応しています。PUTとPATCHはフレームワークとしては同等の扱いですが、HTTP メソッドの意図からすると使い分けがある、とのことです。
POST
● 新規に追加する場合
PUT(PATCH)
● 更新する場合
DELETE
● 削除する場合
今回はこれ以上詳しくは調べず(苦笑)
理解できるまでは「お約束」とか「おまじない」というレベルで覚えておきましょう(乱暴)
https://canon1ky.hatenablog.com/entry/2019/01/02/170826
https://teratail.com/questions/193410
ビューに「編集する」ボタンを追加
投稿詳細画面
詳細画面の上の方に、編集画面へのボタンを追加します。
編集ファイル:resources\views\bbs\show.blade.php
1 2 3 4 5 |
<div class="mb-4 text-right"> <a href="{{ action('PostsController@edit', $post->id) }}" class="btn btn-info"> 編集する </a> </div> |
投稿一覧画面
編集ファイル:resources\views\bbs\index.blade.php
既存のボタンへリンク先を追加します。
1 |
<p><a href="{{ action('PostsController@edit', $post->id) }}" class="btn btn-info btn-sm">編集</a></p> |
投稿の編集後画面のキャプチャ
10.投稿の物理削除機能の作成
次に投稿を削除できるようにします。
投稿用テーブルのカラムに is_deleted を用意していますが、まずは物理削除させてみます。
Postモデル、Commentモデルにてリレーション設定が行われているため、投稿に紐づくコメントがある場合は削除するメソッド内で明示的に削除実行するようすれば投稿と同時に削除してくれる(はず)です。
ルーティングの追記
例によってまずはルーティングの設定です。「destroy」メソッドを使えるようにします。
編集ファイル:routes\web.php
1 |
Route::resource('bbs', 'PostsController', ['only' => ['index', 'show', 'create', 'store', 'edit', 'update', 'destroy']]); |
削除する役割のメソッド名がdestroyと物々しいですが、今回ルーティングに指定している各メソッド名は artisan コマンドに「--resource」オプションを付けてコントローラーを作成したときに自動的に作成される標準のメソッド名となっています。
実際にやってみます。
1 2 |
# artisanコマンドの例 $ php artisan make:controller ItemsController --resource |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# 自動作成されたコントローラーファイルの内容の例 namespace App\Http\Controllers; class ItemsController extends Controller { public function index() { // } public function create() { // } public function store(Request $request) { // } public function show($id) { // } public function edit($id) { // } public function update(Request $request, $id) { // } public function destroy($id) { // } } |
ここまで楽してよいのかちょっと不安になりますね(笑)
Postsコントローラーを編集
編集ファイル:app\Http\Controllers\PostsController.php
1 2 3 4 5 6 7 8 9 10 11 12 |
/** * 物理削除 */ public function destroy($id) { $post = Post::findOrFail($id); $post->comments()->delete(); // ←★コメント削除実行 $post->delete(); // ←★投稿削除実行 return redirect('/bbs')->with('poststatus', '投稿を削除しました'); } |
ビューに「削除する」ボタンを追加
投稿詳細画面
詳細画面の上の方、編集ボタンと横並びになるように「削除する」ボタンを追加します。
編集ファイル:resources\views\bbs\show.blade.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<div class="mb-4 text-right"> <a href="{{ action('PostsController@edit', $post->id) }}" class="btn btn-info"> 編集する </a> <form style="display: inline-block;" method="POST" action="{{ action('PostsController@destroy', $post->id) }}" > @csrf @method('DELETE') <button class="btn btn-danger">削除する</button> </form> </div> |
投稿一覧画面
編集ファイル:resources\views\bbs\index.blade.php
既存のボタンへリンク先を追加します。
1 2 3 4 5 6 7 |
<p> <form method="POST" action="{{ action('PostsController@destroy', $post->id) }}"> @csrf @method('DELETE') <button class="btn btn-danger btn-sm">削除</button> </form> </p> |
削除実行
投稿ID:36を例に動作の確認を行います。
投稿ID:36には、コメントが2件(ID:71、72)登録されています。
削除前のキャプチャ
データベース確認
投稿テーブル
1 |
SELECT * FROM `posts` ORDER BY created_at DESC; |
コメントテーブル
1 |
SELECT * FROM `comments` WHERE post_id = 36 ORDER BY created_at DESC; |
詳細画面より削除を行います。
リダイレクト先を一覧画面としているので、フラッシュメッセージが表示され、先頭にあったID:36の記事がなくなっています。
データベース確認
投稿テーブル
1 |
SELECT * FROM `posts` ORDER BY created_at DESC; |
コメントテーブル
1 |
SELECT * FROM `comments` WHERE post_id = 36 ORDER BY created_at DESC; |
投稿を削除することで、リレーション設定しているコメントも削除することができました。
論理削除もそのうちに作成してみたいと思います。
とりあえず今回はここまでです。
次回は投稿画面の「カテゴリー」をプルダウン化するのと、特定カテゴリーの記事のみを表示する検索機能を実装したいと思います。