Laravel8でTodoアプリを作成するパート④です。
前回までで、タスク追加まで終わりました。
この記事では、タスク編集と削除を実装していきます。
環境構築の手順やdockerの基本コマンドについては、【簡単】Laravel8・php8・mysql8のDocker環境構築で詳しく解説しています。
PHPコンテナの入り方
laravel_todo % docker-compose start
または、docker Desktopからコンテナを起動させる。
コンテナが起動したら、laravel_todo % docker psでコンテナの情報を確認する。
laravel_todo % docker exec -it コンテナIDまたはNAMES bash
で、PHPのコンテナに入る。
例)
laravel_todo % docker exec -it laravel_todo_php_1 bash
/var/www#
とかになればOK
【動作環境】
Mac intel
PHP8
Laravel8
apache2.4
Mysql8
phpmyadmin
Composer 2.2.6
node 12系
休日で空いた時間の暇つぶしを探せるアプリを公開しています。
タスク編集画面を実装する
タスク編集画面を新規作成します。
<h1>タスク編集画面</h1>
ルーティングを追加します。
参考記事:Laravel8ルーティングの書き方
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TasksController;
/*
|--------------------------------------------------------------------------
| 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('/', [TasksController::class, 'index'])->name('tasks.index');
// 詳細ページ
Route::get('/{id}', [TasksController::class, 'show'])->name('tasks.show');
// タスク追加
Route::get('/tasks/add', [TasksController::class, 'add'])->name('tasks.add');
// タスク追加-DBに値を入れる処理
Route::post('/tasks/add', [TasksController::class, 'store'])->name('tasks.store');
----------追加--------------------
// タスク編集画面
Route::get('/tasks/edit/{id}', [TasksController::class, 'edit'])->name('tasks.edit');
----------追加終わり--------------------
コントローラーにeditアクションを追加します。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Task;
use App\Http\Requests\TaskRequest;
class TasksController extends Controller
{
/**
* 一覧画面
*/
public function index()
{
// 更新日時が最新順に並び替えて、タスク一覧を取得
$tasks = Task::orderBy('updated_at', 'desc')->get();
return view('tasks.index', compact('tasks'));
}
/**
* 詳細画面
*/
public function show($id)
{
$task = Task::find($id);
return view('tasks.show', compact('task'));
}
/**
* タスク追加
*/
public function add()
{
return view('tasks.add');
}
/**
* タスク追加-DBに値を入れる処理
*/
public function store(TaskRequest $request)
{
// tasksテーブルにフォームで入力した値を挿入する
$result = Task::create([
'name' => $request->name,
'content' => $request->content,
]);
// タスク一覧画面にリダイレクト
return redirect()->route('tasks.index');
}
----------追加------------------------
/**
* タスク編集画面
*/
public function edit($id)
{
return view('tasks.edit');
}
----------追加終わり--------------------
}
一覧画面や詳細画面から編集画面に遷移するようにします。
一覧画面
<style>
h1 {
text-align: center;
padding: 30px;
}
.container {
width: 80%;
margin: 0 auto;
}
.task__add {
text-align: right;
padding-bottom: 10px;
}
table {
border-spacing: 0;
border-collapse: collapse;
border-bottom: 1px solid #aaa;
color: #555;
width: 100%;
}
th {
border-top: 1px solid #aaa;
background-color: #f5f5f5;
padding: 10px 0 10px 6px;
text-align: center;
}
td {
border-top: 1px solid #aaa;
padding: 10px 0 10px 6px;
text-align: center;
}
a {
margin-right: 20px;
}
</style>
<h1>タスク一覧</h1>
<div class="container">
<div class="task__add">
<a href="{{ route('tasks.add') }}">+タスクを追加する</a>
</div>
<table>
<tr>
<th>タスク</th>
<th>アクション</th>
</tr>
@foreach ($tasks as $task)
<tr>
<td>{{ $task->name }}</td>
<td>
<a href="{{ route('tasks.show', ['id' => $task->id]) }}">詳細</a>
---------------------修正前---------------------------
<a href="">編集</a>
---------------------修正後---------------------------
<a href="{{ route('tasks.edit', ['id' => $task->id]) }}">編集</a>
<a href="">削除</a>
</td>
</tr>
@endforeach
</table>
</div>
詳細画面
<style>
h1 {
text-align: center;
padding: 30px;
}
.container {
width: 80%;
margin: 0 auto;
}
.task__add {
text-align: right;
padding-bottom: 10px;
}
table {
border-spacing: 0;
border-collapse: collapse;
border-bottom: 1px solid #aaa;
color: #555;
width: 100%;
}
th {
border-top: 1px solid #aaa;
background-color: #f5f5f5;
padding: 10px 0 10px 6px;
text-align: center;
}
td {
border-top: 1px solid #aaa;
padding: 10px 0 10px 6px;
text-align: center;
}
a {
margin-right: 20px;
}
</style>
<h1>タスク一覧</h1>
<div class="container">
<div class="task__add">
<a href="{{ route('tasks.add') }}">+タスクを追加する</a>
</div>
<table>
<tr>
<th>タスク</th>
<th>アクション</th>
</tr>
@foreach ($tasks as $task)
<tr>
<td>{{ $task->name }}</td>
<td>
<a href="{{ route('tasks.show', ['id' => $task->id]) }}">詳細</a>
---------------------修正前---------------------------
<a href="">編集</a>
---------------------修正後---------------------------
<a href="{{ route('tasks.edit', ['id' => $task->id]) }}">編集</a>
<a href="">削除</a>
</td>
</tr>
@endforeach
</table>
</div>
編集押すと、タスク編集画面に遷移します。
例)/tasks/edit/11に遷移し、タスク編集画面とタイトルが表示されていればOKです。
こちらも、編集押すとタスク編集画面に遷移します。
編集画面に遷移できることが確認できたので、タスク追加画面のようにしましょう。
※add.blade.phpをコピペしてきて、一部修正するぐらいでOKです。
<style>
h1 {
text-align: center;
padding: 30px;
}
.error {
text-align: center;
}
.error__message {
color: red;
}
.form {
width: 80%;
margin: 0 auto;
text-align: center;
}
.form-group {
padding-bottom: 50px;
}
span {
color: red;
}
input {
width: 60%;
height: 30px;
}
textarea {
width: 60%;
}
</style>
<h1>タスク編集</h1>
<div class="error">
@foreach ($errors->all() as $error)
<p class="error__message">{{$error}}</p>
@endforeach
</div>
<form action="" method="POST" class="form">
@csrf
<div class="form-group">
<label for="name">タスク<span>(必須)</span></label><br>
<input type="text" name="name" maxlength="30" placeholder="タスクは30文字で書きましょう。">
</div>
<div class="form-group">
<label for="content">タスク内容<span>(必須)</span></label><br>
<textarea rows="5" name="content" placeholder="タスク内容を具体的に書きましょう"></textarea>
</div>
<button type="submit">更新する</button>
</form>
form action=””は空にします。理由は、add.blade.phpの時はstoreアクションを実行するようにしましたが、今度は更新処理になるのでアクションが異なるからです。※後でここはform action=”{{ route(‘tasks.update’)” }}と書きます。
ここまでで、編集画面もタスク追加画面と同じようにできましたが、追加画面と違い、フォームにはDBに登録したデータが表示されていることが好ましいです。こんな感じで。
コントローラーを修正します。
showアクションと同じで、IDを条件にtasksテーブルからレコードを一つに絞り込み。
/**
* タスク編集画面
*/
public function edit($id)
{
$task = Task::find($id);
return view('tasks.edit', compact('task'));
}
edit.blade.phpを以下のように修正します。
参考記事:Laravelのビューでold関数を使い、フォームに値を残す方法
<form action="" method="POST" class="form">
@csrf
<div class="form-group">
<label for="name">タスク<span>(必須)</span></label><br>
--------------修正前----------------
<input type="text" name="name" maxlength="30" placeholder="タスクは30文字で書きましょう。">
--------------修正後----------------
<input type="text" name="name" maxlength="30" placeholder="タスクは30文字で書きましょう。" value="{{ old('name', $task->name) }}">
</div>
<div class="form-group">
<label for="content">タスク内容<span>(必須)</span></label><br>
--------------修正前----------------
<textarea rows="5" name="content" placeholder="タスク内容を具体的に書きましょう"></textarea>
--------------修正後----------------
<textarea rows="5" name="content" placeholder="タスク内容を具体的に書きましょう">{{ old('content', $task->content) }}</textarea>
</div>
<button type="submit">追加する</button>
</form>
これで、DBの値が最初表示されるようにできました。
タスク更新処理を実装する
ルーティングを追加します。
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TasksController;
/*
|--------------------------------------------------------------------------
| 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('/', [TasksController::class, 'index'])->name('tasks.index');
// 詳細ページ
Route::get('/{id}', [TasksController::class, 'show'])->name('tasks.show');
// タスク追加
Route::get('/tasks/add', [TasksController::class, 'add'])->name('tasks.add');
// タスク追加-DBに値を入れる処理
Route::post('/tasks/add', [TasksController::class, 'store'])->name('tasks.store');
// タスク編集画面
Route::get('/tasks/edit/{id}', [TasksController::class, 'edit'])->name('tasks.edit');
---------追加-------------------------
// タスク更新処理
Route::post('tasks/edit/{id}', [TasksController::class, 'update'])->name('tasks.update');
---------追加終わり-------------------------
コントローラーにupdateアクションを追加します。
/**
* タスク更新処理
*/
public function update(TaskRequest $request, $id)
{
// idを条件にtasksテーブルからレコードを取得
$task = Task::find($id);
// 更新処理
$task->fill([
'name' => $request->name,
'content' => $request->content,
])
->save();
// タスク一覧画面にリダイレクト
return redirect()->route('tasks.index');
}
edit.blade.phpのformアクションを修正します。
<form action="{{ route('tasks.update', ['id' => $task->id]) }}" method="POST" class="form">
これで、タスク編集画面でフォームの値を編集し、更新するボタンを押すと正常に更新できればタスク一覧画面にリダイレクトされて、タスクが更新されています。
もし、フォームの値が未入力などエラーがあれば、タスク追加同様にエラーメッセージが表示されます。
タスク削除処理を実装する
削除処理のためのルーティングを追加します。
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TasksController;
/*
|--------------------------------------------------------------------------
| 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('/', [TasksController::class, 'index'])->name('tasks.index');
// 詳細ページ
Route::get('/{id}', [TasksController::class, 'show'])->name('tasks.show');
// タスク追加
Route::get('/tasks/add', [TasksController::class, 'add'])->name('tasks.add');
// タスク追加-DBに値を入れる処理
Route::post('/tasks/add', [TasksController::class, 'store'])->name('tasks.store');
// タスク編集画面
Route::get('/tasks/edit/{id}', [TasksController::class, 'edit'])->name('tasks.edit');
// タスク更新処理
Route::post('tasks/edit/{id}', [TasksController::class, 'update'])->name('tasks.update');
-----------------追加---------------------------
// タスクを削除する
Route::post('tasks/delete/{id}', [TasksController::class, 'delete'])->name('tasks.delete');
-----------------追加終わり---------------------------
コントローラーに削除処理のdeleteアクションを追加します。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Task;
use App\Http\Requests\TaskRequest;
class TasksController extends Controller
{
/**
* 一覧画面
*/
public function index()
{
// 更新日時が最新順に並び替えて、タスク一覧を取得
$tasks = Task::orderBy('updated_at', 'desc')->get();
return view('tasks.index', compact('tasks'));
}
/**
* 詳細画面
*/
public function show($id)
{
$task = Task::find($id);
return view('tasks.show', compact('task'));
}
/**
* タスク追加
*/
public function add()
{
return view('tasks.add');
}
/**
* タスク追加-DBに値を入れる処理
*/
public function store(TaskRequest $request)
{
// tasksテーブルにフォームで入力した値を挿入する
$result = Task::create([
'name' => $request->name,
'content' => $request->content,
]);
// タスク一覧画面にリダイレクト
return redirect()->route('tasks.index');
}
/**
* タスク編集画面
*/
public function edit($id)
{
$task = Task::find($id);
return view('tasks.edit', compact('task'));
}
/**
* タスク更新処理
*/
public function update(TaskRequest $request, $id)
{
// idを条件にtasksテーブルからレコードを取得
$task = Task::find($id);
// 更新処理
$task->fill([
'name' => $request->name,
'content' => $request->content,
])
->save();
// タスク一覧画面にリダイレクト
return redirect()->route('tasks.index');
}
/**
* タスク削除処理
*/
public function delete($id)
{
// idを条件にtasksテーブルから該当レコードを削除
$task = Task::destroy($id);
// タスク一覧画面にリダイレクト
return redirect()->route('tasks.index');
}
}
タスク一覧画面に削除リンクがあるので、こちらを押したときにデータが削除されるようにindex.blade.phpを修正します。
レイアウトが少々崩れてしまう関係で、cssなども調整しています。
<style>
h1 {
text-align: center;
padding: 30px;
}
.container {
width: 80%;
margin: 0 auto;
}
.task__add {
text-align: right;
padding-bottom: 10px;
}
table {
border-spacing: 0;
border-collapse: collapse;
border-bottom: 1px solid #aaa;
color: #555;
width: 100%;
}
th {
border-top: 1px solid #aaa;
background-color: #f5f5f5;
padding: 10px 0 10px 6px;
text-align: center;
}
-------------追加--------------
.td1 {
border-top: 1px solid #aaa;
padding: 10px 0 10px 6px;
text-align: center;
}
.td2 {
border-top: 1px solid #aaa;
padding: 10px 0 10px 6px;
display: flex;
justify-content: center;
}
-------------追加終わり--------------
a {
margin-right: 20px;
}
</style>
<h1>タスク一覧</h1>
<div class="container">
<div class="task__add">
<a href="{{ route('tasks.add') }}">+タスクを追加する</a>
</div>
<table>
<tr>
<th>タスク</th>
<th>アクション</th>
</tr>
@foreach ($tasks as $task)
<tr>
<td class="td1">{{ $task->name }}</td>// ←classを追加
<td class="td2">// ←classを追加
<a href="{{ route('tasks.show', ['id' => $task->id]) }}">詳細</a>
<a href="{{ route('tasks.edit', ['id' => $task->id]) }}">編集</a>
// formの追加
<form action="{{ route('tasks.delete', ['id' => $task->id]) }}" method="POST" name="deleteForm">
@csrf
<button type="submit">削除</button>
</form>
</td>
</tr>
@endforeach
</table>
</div>
詳細画面からも削除できるようにshow.blade.phpを修正します。
<style>
h1 {
text-align: center;
padding: 30px;
}
.container {
width: 60%;
margin: 0 auto;
}
table {
width: 100%;
border-collapse: collapse;
border-spacing: 0;
}
table th,table td {
padding: 10px 0;
text-align: center;
}
table tr:nth-child(odd){
background-color: #eee
}
.link {
display: flex;
justify-content: space-between;
}
</style>
<h1>タスク詳細</h1>
<div class="container">
<table>
<tr>
<th>ID</th>
<td>{{ $task->id }}</td>
</tr>
<tr>
<th>タスク</th>
<td>{{ $task->name }}</td>
</tr>
<tr>
<th>タスク内容</th>
<td>{{ $task->content }}</td>
</tr>
<tr>
<th>作成日時</th>
<td>{{ $task->created_at->format('Y年m月d日 H:i') }}</td>
</tr>
<tr>
<th>更新日時</th>
<td>{{ $task->updated_at->format('Y年m月d日 H:i') }}</td>
</tr>
</table>
<div class="link">
<div class="link__back">
<a href="/">戻る</a>
</div>
<div class="link__edit">
<a href="{{ route('tasks.edit', ['id' => $task->id]) }}">編集する</a>
</div>
<div class="link__delete">
-----------------修正前-------------
<a href="">削除する</a>
----------------修正後--------------
<form action="{{ route('tasks.delete', ['id' => $task->id]) }}" method="POST" name="deleteForm">
@csrf
<button type="submit">削除</button>
</form>
</div>
</div>
</div>
これで一覧画面・詳細画面から削除処理が実装できました。
Todoアプリの作成はこれで終わりです。
疑問点などがあればお気軽にページ下部にあるコメントやお問合せよりご質問ください。
休日で空いた時間の暇つぶしを探せるアプリを公開しています。
コメント