今回、ToDo 一覧画面にステータス変更機能を追加します。
画面レイアウトと仕様
タスク一覧画面(URL「/」)を下記画面イメージの通り修正します。
各タスクの左にステータス変更ボタンを設定します。 各ボタンの仕様は下記表になります。
イベント | URL | 備考 |
---|---|---|
未着手 | /tasks/{taskid}/status/1 |
get |
着手中 | /tasks/{taskid}/status/2 |
get |
完了 | /tasks/{taskid}/status/3 |
get |
延期 | /tasks/{taskid}/status/4 |
get |
ステータスボタンをクリックすると、ステータス変更依頼をサーバ側に送信します。
送信先が、/tasks
で、送信方法が get です。
誤ってステータス変更したものを元のステータスに訂正することを考慮して、ステータス変更に制約は設けません。 ステータス変更の制約とは、ステータスを完了としたものは、未着手に変更できないように制限するなどです。
テストケースとテストコード実装
考えられる大まかなテストケースとしては下記になります。
- ステータスが未着手になること
- ステータスが着手中になること
- ステータスが完了になること
- ステータスが延期になること
上記テストケースをコーディングする前にテストケースクラスを作成します。
php artisan make:test TaskStatusChangeTest
生成後にuse RefreshDatabase
など必要なものを追記します。
ステータスが未着手になること
新規登録画面のテストのときに使用したdataProvider
を使いテストケースを記述します。
public function provideStateTestParams()
{
return [
'ステータスが未着手になること' => ['Ready', '2'],
'ステータスが着手中になること' => ['Doing','3'],
'ステータスが完了になること' => ['Done', '4'],
'ステータスが延期になること' => ['notReady', '1'],
];
}
dataProvider
を使用してテストを行うメソッドのコメントに、
@dataProvider
でプロバイダのメソッド名を指定します。
/**
* @dataProvider provideStateTestParams
*
* @param int $beforeStatus
* @param int $afterStatus
*/
public function testUpdateState($beforeStatus,$afterStatus): void
{
//1件のタスクを指定のステータスで作成。
$task = factory(Task::class)->state($beforeStatus)->create();
//スタータス更新を行います。
$response = $this->get(route('task.updateStatus',['id' => $task->id,'afterstatus'=>$afterStatus]) );
//画面が指定先にリダイレクトされていることを確認
$response->assertRedirect(route('home'));
//スタータスの更新が行われたかを確認
$this->assertDatabaseHas('tasks', [
'id' => $task->id,
'status' => $afterStatus,
'created_at' => $task->created_at
]);
//更新日付が新しい日付になったかを確認
$updatedTask = Task::find($task->id);
$this->assertGreaterThan(
$task->updated_at,
$updatedTask->updated_at,
);
}
テスト実施
テストを実施します。
$ ./vendor/bin/phpunit tests/Feature/TaskStatusChangeTest.php --testdox
テストはすべてエラーになることを確認します。 テストコードに間違いがある場合は修正します。
実装
router
Web.php に、ルートを追加します。
ボタン別に URL が割り当てられ、全部で URL が 4 種類あります。
しかし、/tasks/{taskid}/status/{afterState}
とすれば、ひとつにまとめることができます。
{afterState}
には、未着手、着手中、完了、延期のコード値が入ります。
Route::get('/tasks/{id}/status/{afterstatus}', 'TaskController@updateStatus')->where(['id'=>'[0-9]+','afterstatus'=> '[1-4]'])->name('task.updateStatus');
controller
TaskController
にupdateState
を追加します。
public function updateStatus($id,$afterStatus)
{
$task = Task::find($id);
$task->status = $afterStatus;
$task->save();
return redirect(route('home'));
}
指定された id を key にタスクを取得して、ステータスを指定のものに変更して更新します。 更新後は画面を再表示します。
画面
index.balde.html を修正します。@section('content')
と@endsection
で囲まれた部分を下記のように書き換えます。
<ul class="list-group">
@foreach ($tasks as $task)
<li class="list-group-item d-flex justify-content-between align-items-center">
<a href="{{ route('task.edit',['id' => $task->id]) }}" dusk="{{ 'edit-' . $task->id }}" >{{ $task->status_name }}-{{ $task->title }}</a>
<div>
<a class="btn btn-primary btn-sm mr-1" role="button" href="{{ route('task.updateStatus',['id' => $task->id,'afterstatus'=>1]) }}">
未着手
</a>
<a class="btn btn-primary btn-sm mr-1" role="button" href="{{ route('task.updateStatus',['id' => $task->id,'afterstatus'=>2]) }}">
着手中
</a>
<a class="btn btn-primary btn-sm mr-1" role="button" href="{{ route('task.updateStatus',['id' => $task->id,'afterstatus'=>3]) }}">
完了
</a>
<a class="btn btn-primary btn-sm" role="button" href="{{ route('task.updateStatus',['id' => $task->id,'afterstatus'=>4]) }}">
延期
</a>
</div>
</li>
@endforeach
</ul>
それぞれのスタータスボタンと飛び先を追加しました。
テスト
$ ./vendor/bin/phpunit tests/Feature/TaskStatusChangeTest.php --testdox
PHPUnit 9.5.1 by Sebastian Bergmann and contributors.
Task Status Change (Tests\Feature\TaskStatusChange)
✔ Update state with ステータスが未着手になること
✔ Update state with ステータスが着手中になること
✔ Update state with ステータスが完了になること
✔ Update state with ステータスが延期になること
Time: 00:00.262, Memory: 34.01 MB
OK (4 tests, 16 assertions)
GETでの更新は問題
本来なら、テストをクリアして完成となるはずですが、このプログラムは http メソッドの GET で更新しています。 思い出してください。GET では情報の要求のみで、データの更新はご法度でした。 データの更新をするには PUT メソッドを使います。