🐘
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;
use Illuminate\Support\Facades\Auth; // ログイン情報取得に使用
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"];
// Atuh::user()でログインしているユーザーの情報を取得
$user = Auth::user();
// tasksリレーションを使用してユーザーに紐づくタスクを作成
$user->tasks()->create([
"title" => $title,
"content" => $content
]);
// タスク一覧画面にリダイレクト
return redirect()->route("task");
}
}
http://localhost:8000/task/createからタスクを追加したときにタスク一覧ページにリダイレクトすればOK
タスク一覧ページ
Controller
1 TopController.php
のindex
メソッドを編集
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class TaskController extends Controller
{
function index() {
// Atuh::user()でログインしているユーザーの情報を取得
$user = Auth::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 = Auth::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;
use Illuminate\Support\Facades\Auth;
class TaskController extends Controller
{
function index() {
$user = Auth::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 = Auth::user();
$user->tasks()->create([
"title" => $title,
"content" => $content
]);
return redirect()->route("task");
}
// ルーティングの{id}は第一引数に入る
function show($id) {
// Atuh::user()でログインしているユーザーの情報を取得
$user = Auth::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;
use Illuminate\Support\Facades\Auth;
class TaskController extends Controller
{
function index() {
$user = Auth::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 = Auth::user();
$user->tasks()->create([
"title" => $title,
"content" => $content
]);
return redirect()->route("task");
}
function show($id) {
$user = Auth::user();
$task = $user->tasks->find($id);
return view("task.show", compact("task"));
}
// editメソッドを追加
function edit($id) {
// Atuh::user()でログインしているユーザーの情報を取得
$user = Auth::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;
use Illuminate\Support\Facades\Auth;
class TaskController extends Controller
{
function index() {
$user = Auth::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 = Auth::user();
$user->tasks()->create([
"title" => $title,
"content" => $content
]);
return redirect()->route("task");
}
function show($id) {
$user = Auth::user();
$task = $user->tasks->find($id);
return view("task.show", compact("task"));
}
function edit($id) {
$user = Auth::user();
$task = $user->tasks->find($id);
return view("task.edit", compact("task"));
}
// updateメソッドを追加
function update(Request $request, $id) {
// それぞれの入力値を取得
$title = $request["title"];
$content = $request["content"];
// Auth::user()でログインしているユーザーの情報を取得
$user = Auth::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;
use Illuminate\Support\Facades\Auth;
class TaskController extends Controller
{
function index() {
$user = Auth::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 = Auth::user();
$user->tasks()->create([
"title" => $title,
"content" => $content
]);
return redirect()->route("task");
}
function show($id) {
$user = Auth::user();
$task = $user->tasks->find($id);
return view("task.show", compact("task"));
}
function edit($id) {
$user = Auth::user();
$task = $user->tasks->find($id);
return view("task.edit", compact("task"));
}
function update(Request $request, $id) {
$title = $request["title"];
$content = $request["content"];
$user = Auth::user();
$user->tasks()->find($id)->update([
"title" => $title,
"content" => $content
]);
return redirect()->route("task");
}
// destroyメソッドを追加
function destroy($id) {
// Atuh::user()でログインしているユーザーの情報を取得
$user = Auth::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