🐘
Laravel入門7 Todoアプリ(CRUD)
記事一覧
- Laravel × Docker 最速環境構築
 - Laravel 入門1 ページ追加
 - Laravel入門2 bladeディレクティブ
 - Laravel入門3 静的ファイル
 - Laravel入門4 Request
 - Laravel入門5 Todoアプリ(データベース)
 - Laravel入門6 Todoアプリ(認証機能)
 - Laravel入門7 Todoアプリ(CRUD)
 
CRUD
CRUDとは
以下の頭文字をとったもので、基本的なwebアプリケーションの機能
- Create(作成)
 - Read(読み取り)
 - Update(更新)
 - Delete(削除)
 
リレーション設定
関係
1つのUserに対して複数のTaskが紐付いている
リレーションの追加
- 
User.phpを編集 
.
├── laravel_app
│   └── app
│       └── Models
│           └── User.php # ここ
├── mysql_data
├── docker-compose.yml
└── Dockerfile
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
    /** @use HasFactory<\Database\Factories\UserFactory> */
    use HasFactory, Notifiable;
    /**
     * The attributes that are mass assignable.
     *
     * @var list<string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];
    /**
     * The attributes that should be hidden for serialization.
     *
     * @var list<string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];
    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
        ];
    }
    // リレーションの作成 <- ここを追加
    function tasks() {
        return $this->hasMany(Task::class);
    }
}
タスク作成ページ
web.php
- 
web.phpに/task/createと/task(POST)のルーティングを追加 
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TopController;
use App\Http\Controllers\LoginController;
use App\Http\Controllers\SignUpController;
use App\Http\Controllers\TaskController;
Route::get('/', function () {
    return view('welcome');
});
Route::get('/top', [TopController::class, 'index'])->name("top");
Route::prefix('sign_up')->group(function () {
    Route::get('/', [SignUpController::class, 'index'])->name("sign_up");
    Route::post('/', [SignUpController::class, 'store'])->name("sign_up.store");
});
Route::prefix('login')->group(function () {
    Route::get('/', [LoginController::class, 'index'])->name("login");
    Route::post('/', [LoginController::class, 'store'])->name("login.store");
});
Route::middleware('auth')->group(function () {
    Route::prefix('task')->group(function () {
        Route::get('/', [TaskController::class, 'index'])->name("task");
        // タスク作成ページ
        Route::get('/create', [TaskController::class, 'create'])->name("task.create");
        // タスク作成処理
        Route::post('/', [TaskController::class, 'store'])->name("task.store");
    });
});
Controller
- 
TaskController.phpにcreateメソッド追加 
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class TaskController extends Controller
{
    function index() {
        return view("task.index");
    }
    // createメソッドを追加
    function create() {
        return view("task.create");
    }
}
View
- 
task/create.blade.phpを作成 
.
├── laravel_app
│   └── resources
│       └── views
│           └── task
│               └── create.blade.php # ここに作成
├── mysql_data
├── docker-compose.yml
└── Dockerfile
- 
task/create.blade.phpを記述 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>タスク作成ページ</h1>
    {{-- 【重要】task.storeのルーティングは後で作成する --}}
    <form action={{ route('task.store') }} method="POST">
        @csrf
        <label>タイトル</label>
        <input type="text" name="title">
        <label>内容</label>
        <textarea name="content"></textarea>
        <button type="submit">追加</button>
    </from>
    {{-- タスク一覧ページに戻るボタン --}}
    <a href="{{ route("task") }}">戻る</a>
</body>
</html>
http://localhost:8000/task/createにアクセスして以下のような画面が出ればOK

タスク作成処理
Controller
- 
TaskController.phpにstoreメソッドを追加 
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class TaskController extends Controller
{
    function index() {
        return view("task.index");
    }
    function create() {
        return view("task.create");
    }
    // storeメソッドを追加
    function store(Request $request) {
        // それぞれの入力値を取得
        $title = $request["title"];
        $content = $request["content"];
        // request()->user()でログインしているユーザーの情報を取得
        $user = request()->user();
        // tasksリレーションを使用してユーザーに紐づくタスクを作成
        $user->tasks()->create([
            "title" => $title,
            "content" => $content
        ]);
        // タスク一覧画面にリダイレクト
        return redirect()->route("task");
    }
}
http://localhost:8000/task/createからタスクを追加したときにタスク一覧ページにリダイレクトすればOK
タスク一覧ページ
Controller
1 TaskController.phpのindexメソッドを編集
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class TaskController extends Controller
{
    function index() {
        // request()->user()でログインしているユーザーの情報を取得
        $user = request()->user();
        // tasksリレーションを使用してユーザーに紐づくタスクを取得
        $tasks = $user->tasks;
        return view("task.index", compact("tasks"));
    }
    function create() {
        return view("task.create");
    }
    function store(Request $request) {
        $title = $request["title"];
        $content = $request["content"];
        $user = request()->user();
        $user->tasks()->create([
            "title" => $title,
            "content" => $content
        ]);
        return redirect()->route("task");
    }
}
View
- 
task/index.blade.phpに一覧テーブルを追加 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>タスク一覧ページ</h1>
    {{-- 一覧テーブルを作成 --}}
    <table>
        <tr>
            <th>タイトル</th>
            <th>内容</th>
            <th>作成日時</th>
            <th>更新日時</th>
        </tr>
        {{-- コントローラーから受け取った$tasksをループして表示 --}}
        @foreach ($tasks as $task)
        <tr>
            <td>{{ $task["title"] }}</td>
            <td>{{ $task["content"] }}</td>
            <td>{{ $task["created_at"] }}</td>
            <td>{{ $task["updated_at"] }}</td>
        </tr>
        @endforeach
    </table>
    {{-- タスク作成ページに遷移するボタン --}}
    <a href="{{ route("task.create") }}">タスク作成</a>
</body>
</html>
http://localhost:8000/taskにアクセスして以下のような画面が出ればOK

タスク詳細ページ
web.php
- 
web.phpに/task/{id}のルーティングを追加 
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TopController;
use App\Http\Controllers\LoginController;
use App\Http\Controllers\SignUpController;
use App\Http\Controllers\TaskController;
Route::get('/', function () {
    return view('welcome');
});
Route::get('/top', [TopController::class, 'index'])->name("top");
Route::prefix('sign_up')->group(function () {
    Route::get('/', [SignUpController::class, 'index'])->name("sign_up");
    Route::post('/', [SignUpController::class, 'store'])->name("sign_up.store");
});
Route::prefix('login')->group(function () {
    Route::get('/', [LoginController::class, 'index'])->name("login");
    Route::post('/', [LoginController::class, 'store'])->name("login.store");
});
Route::middleware('auth')->group(function () {
    Route::prefix('task')->group(function () {
        Route::get('/', [TaskController::class, 'index'])->name("task");
        Route::get('/create', [TaskController::class, 'create'])->name("task.create");
        Route::post('/', [TaskController::class, 'store'])->name("task.store");
        // タスク詳細ページ
        // 波括弧で囲んだ値は、任意の文字になる
        // 例:/task/1, /task/2 などでアクセスできる
        Route::get('/{id}', [TaskController::class, 'show'])->name("task.show");
    });
});
Controller
- 
TaskController.phpにshowメソッドを追加 
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class TaskController extends Controller
{
    function index() {
        $user = request()->user();
        $tasks = $user->tasks;
        return view("task.index", compact("tasks"));
    }
    function create() {
        return view("task.create");
    }
    function store(Request $request) {
        $title = $request["title"];
        $content = $request["content"];
        $user = request()->user();
        $user->tasks()->create([
            "title" => $title,
            "content" => $content
        ]);
        return redirect()->route("task");
    }
    // ルーティングの{id}は第一引数に入る
    function show($id) {
        // request()->user()でログインしているユーザーの情報を取得
        $user = request()->user();
        // tasksリレーションを使用してユーザーに紐づくタスクを取得
        // $idとtasksテーブルのidが一致するものを取得
        $task = $user->tasks()->find($id);
        return view("task.show", compact("task"));
    }
}
View
- 
task/show.blade.phpを作成 
.
├── laravel_app
│   └── resources
│       └── views
│           └── task
│               └── show.blade.php # ここに作成
├── mysql_data
├── docker-compose.yml
└── Dockerfile
- 
task/show.blade.phpを記述 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>タスク詳細ページ</h1>
    {{-- コントローラーから受け取った$taskを表示 --}}
    <p>タイトル: {{ $task["title"] }}</p>
    <p>内容: {{ $task["content"] }}</p>
    <p>作成日時: {{ $task["created_at"] }}</p>
    <p>更新日時: {{ $task["updated_at"] }}</p>
    {{-- タスク一覧ページに戻るボタン --}}
    <a href="{{ route("task") }}">戻る</a>
</body>
</html>
- 
task/index.blade.phpに詳細ページに飛ぶリンクを追加 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>タスク一覧ページ</h1>
    <table>
        <tr>
            <th>タイトル</th>
            <th>内容</th>
            <th>作成日時</th>
            <th>更新日時</th>
            <th></th>
        </tr>
        @foreach ($tasks as $task)
        <tr>
            <td>{{ $task["title"] }}</td>
            <td>{{ $task["content"] }}</td>
            <td>{{ $task["created_at"] }}</td>
            <td>{{ $task["updated_at"] }}</td>
            <td>
                {{-- 詳細ページに遷移するリンクを作成 --}}
                <a href={{ route("task.show", ["id" => $task["id"]]) }}>詳細</a>
            </td>
        </tr>
        @endforeach
    </table>
    <a href="{{ route("task.create") }}">タスク作成</a>
</body>
</html>
http://localhost:8000/taskから詳細ページにアクセスして以下のような画面が出ればOK

タスク編集ページ
web.php
- 
web.phpに/task/{id}/editとtask/{id}(PUT)のルーティングを追加 
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TopController;
use App\Http\Controllers\LoginController;
use App\Http\Controllers\SignUpController;
use App\Http\Controllers\TaskController;
Route::get('/', function () {
    return view('welcome');
});
Route::get('/top', [TopController::class, 'index'])->name("top");
Route::prefix('sign_up')->group(function () {
    Route::get('/', [SignUpController::class, 'index'])->name("sign_up");
    Route::post('/', [SignUpController::class, 'store'])->name("sign_up.store");
});
Route::prefix('login')->group(function () {
    Route::get('/', [LoginController::class, 'index'])->name("login");
    Route::post('/', [LoginController::class, 'store'])->name("login.store");
});
Route::middleware('auth')->group(function () {
    Route::prefix('task')->group(function () {
        Route::get('/', [TaskController::class, 'index'])->name("task");
        Route::get('/create', [TaskController::class, 'create'])->name("task.create");
        Route::post('/', [TaskController::class, 'store'])->name("task.store");
        Route::get('/{id}', [TaskController::class, 'show'])->name("task.show");
        // タスク編集ページ
        Route::get('/{id}/edit', [TaskController::class, 'edit'])->name("task.edit");
        // タスク編集処理
        Route::put('/{id}', [TaskController::class, 'update'])->name("task.update");
    });
});
Controller
- 
TaskController.phpにeditメソッドを追加 
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class TaskController extends Controller
{
    function index() {
        $user = request()->user();
        $tasks = $user->tasks;
        return view("task.index", compact("tasks"));
    }
    function create() {
        return view("task.create");
    }
    function store(Request $request) {
        $title = $request["title"];
        $content = $request["content"];
        $user = request()->user();
        $user->tasks()->create([
            "title" => $title,
            "content" => $content
        ]);
        return redirect()->route("task");
    }
    function show($id) {
        $user = request()->user();
        $task = $user->tasks()->find($id);
        return view("task.show", compact("task"));
    }
    // editメソッドを追加
    function edit($id) {
        // request()->user()でログインしているユーザーの情報を取得
        $user = request()->user();
        // tasksリレーションを使用してユーザーに紐づくタスクを取得
        // $idとtasksテーブルのidが一致するものを取得
        $task = $user->tasks()->find($id);
        return view("task.edit", compact("task"));
    }
}
View
- 
task/edit.blade.phpを作成 
.
├── laravel_app
│   └── resources
│       └── views
│           └── task
│               └── edit.blade.php # ここに作成
├── mysql_data
├── docker-compose.yml
└── Dockerfile
- 
task/edit.blade.phpを記述 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>タスク編集ページ</h1>
    {{-- 【重要】task.updateのルーティングは後で作成する --}}
    <form action={{ route('task.update', ['id' => $task["id"]]) }} method="POST">
        @csrf
        {{-- 【重要】HTTPメソッドをPUTに変更 --}}
        @method('PUT')
        <label>タイトル</label>
        {{-- value属性に$task["title"]を設定することで、編集前のタイトルが入力値に入る --}}
        <input type="text" name="title" value="{{ $task["title"] }}">
        <label>内容</label>
        {{-- textarea内に$task["content"]を設定することで、編集前の内容が入力値に入る --}}
        <textarea name="content">{{ $task["content"] }}</textarea>
        <button type="submit">更新</button>
    </form>
    {{-- タスク詳細ページに戻るボタン --}}
    <a href="{{ route("task.show", ["id" => $task["id"]]) }}">戻る</a>
</body>
</html>
- 
task/show.blade.phpに編集ページに遷移するリンクを追加 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>タスク詳細ページ</h1>
    <p>タイトル: {{ $task["title"] }}</p>
    <p>内容: {{ $task["content"] }}</p>
    <p>作成日時: {{ $task["created_at"] }}</p>
    <p>更新日時: {{ $task["updated_at"] }}</p>
    <a href="{{ route("task") }}">戻る</a>
    {{-- 編集ページに遷移するリンクを追加 --}}
    <a href="{{ route("task.edit", ["id" => $task["id"]]) }}">編集</a>
</body>
</html>
http://localhost:8000/taskから詳細ページにアクセスして編集ページを開き、以下のような画面になっていればOK

タスク編集処理
Controller
- 
TaskController.phpにupdateメソッドを追加 
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class TaskController extends Controller
{
    function index() {
        $user = request()->user();
        $tasks = $user->tasks;
        return view("task.index", compact("tasks"));
    }
    function create() {
        return view("task.create");
    }
    function store(Request $request) {
        $title = $request["title"];
        $content = $request["content"];
        $user = request()->user();
        $user->tasks()->create([
            "title" => $title,
            "content" => $content
        ]);
        return redirect()->route("task");
    }
    function show($id) {
        $user = request()->user();
        $task = $user->tasks()->find($id);
        return view("task.show", compact("task"));
    }
    function edit($id) {
        $user = request()->user();
        $task = $user->tasks()->find($id);
        return view("task.edit", compact("task"));
    }
    // updateメソッドを追加
    function update(Request $request, $id) {
        // それぞれの入力値を取得
        $title = $request["title"];
        $content = $request["content"];
        // request()->user()でログインしているユーザーの情報を取得
        $user = request()->user();
        // tasksリレーションを使用してユーザーに紐づくタスクを取得
        // $idとtasksテーブルのidが一致するものを取得
        // updateメソッドで更新
        $user->tasks()->find($id)->update([
            "title" => $title,
            "content" => $content
        ]);
        return redirect()->route("task");
    }
}
http://localhost:8000/taskから詳細ページにアクセスして編集ページを開き"更新"を押した際に更新され、一覧ページに戻ればOK

タスク削除処理
web.php
- 
web.phpに/task(DELETE)のルーティングを追加 
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TopController;
use App\Http\Controllers\LoginController;
use App\Http\Controllers\SignUpController;
use App\Http\Controllers\TaskController;
Route::get('/', function () {
    return view('welcome');
});
Route::get('/top', [TopController::class, 'index'])->name("top");
Route::prefix('sign_up')->group(function () {
    Route::get('/', [SignUpController::class, 'index'])->name("sign_up");
    Route::post('/', [SignUpController::class, 'store'])->name("sign_up.store");
});
Route::prefix('login')->group(function () {
    Route::get('/', [LoginController::class, 'index'])->name("login");
    Route::post('/', [LoginController::class, 'store'])->name("login.store");
});
Route::middleware('auth')->group(function () {
    Route::prefix('task')->group(function () {
        Route::get('/', [TaskController::class, 'index'])->name("task");
        Route::get('/create', [TaskController::class, 'create'])->name("task.create");
        Route::post('/', [TaskController::class, 'store'])->name("task.store");
        Route::get('/{id}', [TaskController::class, 'show'])->name("task.show");
        Route::get('/{id}/edit', [TaskController::class, 'edit'])->name("task.edit");
        Route::put('/{id}', [TaskController::class, 'update'])->name("task.update");
        // タスク削除処理
        Route::delete('/{id}', [TaskController::class, 'destroy'])->name("task.destroy");
    });
});
Controller
- 
TaskController.phpにdestroyメソッドを追加 
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class TaskController extends Controller
{
    function index() {
        $user = request()->user();
        $tasks = $user->tasks;
        return view("task.index", compact("tasks"));
    }
    function create() {
        return view("task.create");
    }
    function store(Request $request) {
        $title = $request["title"];
        $content = $request["content"];
        $user = request()->user();
        $user->tasks()->create([
            "title" => $title,
            "content" => $content
        ]);
        return redirect()->route("task");
    }
    function show($id) {
        $user = request()->user();
        $task = $user->tasks()->find($id);
        return view("task.show", compact("task"));
    }
    function edit($id) {
        $user = request()->user();
        $task = $user->tasks()->find($id);
        return view("task.edit", compact("task"));
    }
    function update(Request $request, $id) {
        $title = $request["title"];
        $content = $request["content"];
        $user = request()->user();
        $user->tasks()->find($id)->update([
            "title" => $title,
            "content" => $content
        ]);
        return redirect()->route("task");
    }
    // destroyメソッドを追加
    function destroy($id) {
        // request()->user()でログインしているユーザーの情報を取得
        $user = request()->user();
        // tasksリレーションを使用してユーザーに紐づくタスクを取得
        // $idとtasksテーブルのidが一致するものを取得
        // deleteメソッドで削除
        $user->tasks()->find($id)->delete();
        return redirect()->route("task");
    }
}
View
- 
task/show.blade.phpに削除処理を行うフォームを作成 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>タスク詳細ページ</h1>
    <p>タイトル: {{ $task["title"] }}</p>
    <p>内容: {{ $task["content"] }}</p>
    <p>作成日時: {{ $task["created_at"] }}</p>
    <p>更新日時: {{ $task["updated_at"] }}</p>
    <a href="{{ route("task") }}">戻る</a>
    <a href="{{ route("task.edit", ["id" => $task["id"]]) }}">編集</a>
    {{-- 削除処理を行うフォームを作成 --}}
    <form action={{ route('task.destroy', ['id' => $task["id"]]) }} method="POST">
        @csrf
        {{-- 【重要】HTTPメソッドをDELETEに変更 --}}
        @method('DELETE')
        <button type="submit">削除する</button>
    </form>
</body>
</html>
Discussion