Laravel 入門 ⑥(タスクの編集機能の追加)

皆さん、こんにちは。管理人です。今回はタスクのタイトルを編集できるようにしたいと思います。

タスクの編集機能を実装する

それでは、routes/web.php に二行を追加して次のようにして下さい(edit.blade.php は後ほど作成します)。

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TaskController;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

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

Route::get('/dashboard', [TaskController::class, 'show'])->middleware(['auth'])->name('dashboard');
Route::post('/store', [TaskController::class, 'store'])->middleware(['auth'])->name('store');
Route::post('/delete/{id}', [TaskController::class, 'delete'])->middleware(['auth'])->name('delete');
Route::get('/edit/{id}', [TaskController::class, 'edit'])->middleware(['auth'])->name('edit'); // 追記
Route::post('/update/{id}', [TaskController::class, 'update'])->middleware(['auth'])->name('update'); // 追記

require __DIR__.'/auth.php';

続いて、resources/views/dashboard.blade.php を編集して次のようにして下さい。

<x-app-layout>
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">
            {{ __('Dashboard') }}
        </h2>
    </x-slot>

    <div class="py-5">
        <div class="max-w-3xl mx-auto px-4">
            <form class="grid grid-cols-1 gap-3" method='POST' action="/store" enctype="multipart/form-data">
                @csrf
                <label class="block">
                    <span class="text-gray-700">新しいタスク</span>
                    <input name="title" type="text" class="mt-2 block w-full rounded-md border-gray-300 shadow-sm">
                </label>
                <button type='submit' class="w-20 bg-blue-600 hover:bg-blue-500 text-white rounded px-4 py-2">作成</button>
            </form>
            @foreach ($tasks as $task)
                <div class="flex flex-wrap justify-between p-2 my-5 bg-green-600 rounded">
                    <div class="text-white">{{ $task['title'] }}</div>
                    <div class="flex">
                        <!-- 編集ここから -->
                        <button type='submit' class="w-20 bg-blue-600 hover:bg-blue-500 text-white rounded px-4 py-2 mr-2" 
                        onclick="location.href='/edit/{{ $task['id'] }}'">編集</button>
                        <!-- 編集ここまで -->
                        <form method='POST' action="/delete/{{ $task['id'] }}" enctype="multipart/form-data">
                            @csrf
                            <button type='submit' class="w-20 bg-red-600 hover:bg-red-500 text-white rounded px-4 py-2">削除</button>
                        </form>
                    </div>
                </div>
            @endforeach
        </div>
    </div>
</x-app-layout>

ここで注目すべきなのは 24 行目の

onclick="location.href='/edit/{{ $task['id'] }}'"

という部分です。二重括弧 {{ }} で変数の中身が出力されるので、このリンクは該当するタスクの編集画面(これから作ります)へと飛ぶようになっています。

続いて、ルーティング /edit/{id} はすでに web.php の中で定義していますので、TaskControlleredit アクションを追加して次のようにして下さい。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Task;

class TaskController extends Controller
{
    public function store(Request $request)
    {
        $data = $request->all(); // フォームで送信されたデータをすべてとってきます

        Task::insertGetId([
            'user_id' => \Auth::id(), // ログイン中のユーザーの ID を格納します
            'title' => $data['title'], // 入力された文字列を格納します
        ]);

        return redirect()->route('dashboard'); // 処理が終わったらダッシュボードにリダイレクトします
    }

    public function show()
    {
        $tasks = Task::where('user_id', \Auth::id())->get(); // ログイン中のユーザーが作成したタスクをすべてとってきます
        return view('dashboard', compact('tasks')); // ここではビューに変数を渡しています
    }

    public function delete($id)
    {
        /** この if 文がないと、他のユーザーのタスクを削除できてしまう可能性があります */
        if (Task::where('id', $id)->where('user_id', \Auth::id())->exists()) {
            Task::destroy($id); // クリックされた削除ボタンに対応するタスクを削除します
            return redirect()->route('dashboard'); // ダッシュボードにリダイレクトします
        } else {
            abort(500); // サーバーエラー
        }
    }

    // 追記ここから
    public function edit($id)
    {
        $task = Task::where('id', $id)->where('user_id', \Auth::id())->first(); // ID が $id の値と同じであるタスクをとってきます
        return view('edit', compact('task')); // ビューに変数を渡しています
    } // 追記ここまで
}

続いて、resources/views 直下に次のようなファイル(edit.blade.php)を作成して下さい。

<x-app-layout>
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">
            タスクの編集
        </h2>
    </x-slot>

    <div class="py-5">
        <div class="max-w-3xl mx-auto px-4">
            <form class="grid grid-cols-1 gap-3" method='POST' action="/update/{{ $task['id'] }}" enctype="multipart/form-data">
                @csrf
                <label class="block">
                    <span class="text-gray-700">タスクの編集</span>
                    <input name="title" type="text" class="mt-2 block w-full rounded-md border-gray-300 shadow-sm" value="{{ $task['title'] }}">
                </label>
                <button type='submit' class="w-20 bg-blue-600 hover:bg-blue-500 text-white rounded px-4 py-2">更新</button>
            </form>
        </div>
    </div>
</x-app-layout>

(この段階でビューを確認しても良いです。)ここで、10行目に

action="/update/{{ $task['id'] }}"

という記述が出てきました。これによって、更新ボタンをクリックするとルーティング /update/{id} に飛ぶわけです。また、14 行目の input タグに

value="{{ $task['title'] }}"

という記述がありますが、これによってページを開いたときにテキスト入力欄にタスクのタイトルが入った状態となります。

続いて、ルーティング /update/{id} はすでに web.php の中で定義していますので、次のようにして、TaskControllerupdate アクションを追加しましょう。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Task;

class TaskController extends Controller
{
    public function store(Request $request)
    {
        $data = $request->all(); // フォームで送信されたデータをすべてとってきます

        Task::insertGetId([
            'user_id' => \Auth::id(), // ログイン中のユーザーの ID を格納します
            'title' => $data['title'], // 入力された文字列を格納します
        ]);

        return redirect()->route('dashboard'); // 処理が終わったらダッシュボードにリダイレクトします
    }

    public function show()
    {
        $tasks = Task::where('user_id', \Auth::id())->get(); // ログイン中のユーザーが作成したタスクをすべてとってきます
        return view('dashboard', compact('tasks')); // ここではビューに変数を渡しています
    }

    public function delete($id)
    {
        /** この if 文がないと、他のユーザーのタスクを削除できてしまう可能性があります */
        if (Task::where('id', $id)->where('user_id', \Auth::id())->exists()) {
            Task::destroy($id); // クリックされた削除ボタンに対応するタスクを削除します
            return redirect()->route('dashboard'); // ダッシュボードにリダイレクトします
        } else {
            abort(500); // サーバーエラー
        }
    }

    public function edit($id)
    {
        $task = Task::where('id', $id)->where('user_id', \Auth::id())->first(); // ID が $id の値と同じであるタスクをとってきます
        return view('edit', compact('task')); // ビューに変数を渡しています
    }

    // 追記ここから
    public function update(Request $request, $id)
    {
        $query = Task::where('id', $id)->where('user_id', \Auth::id());

        /** この if 文がないと、他のユーザーのタスクを更新できてしまう可能性があります */
        if ($query->exists()) {
            $query->update(['title' => $request->title]); // タスクのタイトルを更新しています
            return redirect()->route('dashboard'); // ダッシュボードにリダイレクトします
        } else {
            abort(500); // サーバーエラー
        }
    } // 追記ここまで
}
さて、ダッシュボードにアクセスして、どれでも良いので編集ボタンをクリックして下さい(ここでは、赤枠で囲った「あいうえお」の編集ボタンをクリックします)。
するとタスクの編集画面になります。value="{{ $task['title'] }}" とした効果で、テキストボックスにはすでにタスクのタイトルが入っています。
タイトルを編集して、更新ボタンをクリックしてみましょう。
狙い通り、タイトルが「あいうえお、追記」となりました。
念のため、ログイン中のユーザーが他のユーザーのタスクを更新できないことを確認してみましょう。ここではログイン中のユーザーの ID は 1 ですので、赤枠で囲ったユーザー ID が 2 のタスク(ID は 11)をターゲットにしてみましょう。(お手元の環境で試す場合は、数字を適宜読み替えて試して下さい。)
(ダッシュボードにおいて)どれでも良いので編集ボタンをクリックして、タスクを編集する画面にアクセスして下さい。(今回の場合は「さしすせそ」という文字列が入っていました。)そうしましたら、Ctrl + Shift + I キーで開発者ツールを開き、form タグの「action=”/update/X”」のところ(赤枠で囲った部分。X は数字)をダブルクリックします。そうしましたら、数字 X の部分をターゲットの ID である 11 に変更して、
action="/update/11"

として下さい。そして更新ボタンをクリックすると、

狙い通り SERVER ERROR となりました。
そして ターゲットのタスク(赤枠で囲ったタスク)のタイトルは「さしすせそ」になっていないことが確認できるかと思います。

最後に

いかがでしたでしょうか。これでタスクの作成(Create)、閲覧(Read)、編集(Update)、削除(Delete)の機能が実装されました。この 4 つの機能をまとめて CRUD と言ったりしますので、覚えておきましょう。次回の内容は考え中です。お疲れ様でした。

コメント

タイトルとURLをコピーしました