Laravel初心者向けチュートリアルのTODOアプリ②タスクの詳細の表示と追加

Laravel初心者向けチュートリアルのTODOアプリ②タスクの詳細の表示と追加

1543 回閲覧されました

みなさんこんにちは、jonioです。

今回はタスクの詳細の表示とタスクの追加のアウトプットです。

それでは解説しますが1回目の記事をまだ読んでない方は↓から記事を読む事ができます。

 

詳細ページを表示するファイルの作成

詳細ページを表示するファイル(detail.blade.php)をtasksフォルダの下に作成します。

すぐに編集するのでファイルの中には適当に書いてください。

このページですが表示するためにルーティングとコントローラーの設定をしないといけないので設定します。

 

詳細を表示するページ(ルーティングの設定)

「プロジェクト名 > routes > web.php」の編集をします。

<?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.detail');                //この行を追加

20行目の「/{id}」のidですがidカラムの事です。

次はコントローラーですがidをコントローラーに渡す時はidの前に$を付けて「$id」をアクションの引数にします。

 

詳細を表示するページ(コントローラーの設定)

「プロジェクト名 > app > Http > Controllers > TasksController.php」を編集します。

<?php

namespace App\Http\Controllers;

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

class TasksController extends Controller
{
    public function index()
    {
        $tasks = Task::get();
        return view('tasks.index', compact('tasks'));
    }


    //ここから追加
    public function show($id)
    {
        $task = Task::find($id);
        return view('tasks.show', compact('task'));
    }
    //ここまで追加
    
    
}

18行目ですがルーティングのidをコントローラーに渡すためにshowアクションの引数に$idを使っています。

今回はタスクの詳細を見ますが1つ1つのタスクの詳細は違ってそれを見るためにはデータベースから特定のタスク(特定のid)の詳細を持ってこないといけません。

そんな場合は20行目の「find($id)」を使いますがこれはEloquentモデルのfindメソッドです。

idに対応したタスクの詳細を表示するためにdetail.blade.phpの編集をします。

 

詳細を表示するページ(detail.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="">編集する</a>
        </div>
        <div class="link__delete">
            <a href="">削除する</a>
        </div>
    </div>
</div>

何度も「$task」が出てきていますがTasksController.phpの20行目の$taskです。

46行目に「created_at->format(Y年m月d日 H:i) 」があって50行目に「$task->updated_at->format(Y年m月d日 H:i)」がありますがformat(Y年m月d日 H:i) で日付の表示ができこの書き方はデータベースの内容を表示する時にコントローラーでEloquentモデルを使っている場合に使えます。

データベースの内容を表示する時にクエリビルダを使っているとエラーになるので注意してください。

これでタスクの詳細までできましたがタスクを表示しているページ(index.blade.php)でタスクの詳細を見るための設定をしていないので設定します。

index.blade.phpは↓です。

 

index.blade.php

コードを↓にします。

<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">
    <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="">削除</a>
            </td>
        </tr>
        @endforeach
    </table>
</div>

47行目を修正しています。

「route()」ですがrouteへルパと言いリンクに使い書き方は↓です。

<a href="{{ route('表示したいファイル名') }}"></a>

今はid(パラメーターと言います)を指定していますがパラメーターを含む場合は↓になります。

<a href="{{ route('表示したいファイル名', ['パラメータ名'=>'値']) }}"></a>

これでタスクが表示されているページ(index.blade.php)の詳細をクリックすると詳細が表示されます。

3つ縦に並んだ詳細の内一番上をクリックすると↓になります。

最後はタスクの追加を説明します。

タスクを追加するページに移動するのとデータベースに登録する2つの作業をしないといけないのですがまずはタスクを追加するページに移動するのから説明します。

 

タスクを追加するページ(ルーティングの設定)

「プロジェクト名 > routes > web.php」の編集をしますがタスクを追加するページを「add.blade.php」としてtasksフォルダの下に作成してください。

<?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');                           //この行を追加

1つだけ注意しないといけない事があります。

「/tasks/add」ですが「/tasks」や「/add」でもいい気がしませんか?(tasksやaddの名前は自分で決めています)

「/tasks」や「/add」にした場合20行目の「/{id}」とパス(url)の構造が同じになるため「/tasks」や「/add」にアクセスした時に20行目のshowアクションが作動します。

そうならないようにするために「/tasks/add」にしています。

これはLaravelの性質なので覚えましょう。

次はコントローラーの設定です。

 

タスクを追加するページ(コントローラーの設定)

「プロジェクト名 > app > Http > Controllers > TasksController.php」を編集します。

<?php

namespace App\Http\Controllers;

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

class TasksController extends Controller
{
    public function index()
    {
        $tasks = Task::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');
    }
    //ここまで追加
    
    
}

次はビューです。

 

タスクを追加するページ(add.blade.php)

<style>
    h1 {
        text-align: center;
        padding: 30px;
    }
    .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>
<form action="" method="" 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>

27行目に「@csrf」がありますがLaravelでフォームを作る時はこれがないとエラーになるので絶対に書きましょう。

csrfはクロスサイトリクエストフォージェリというハッキングみたいな物です。

今の状態はタスクを追加するページに移動するリンクがないのでindex.blade.phpに作成します。

 

index.blade.php

<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="">削除</a>
            </td>
        </tr>
        @endforeach
    </table>
</div>

48行目ですがrouteへルパはパラメーターの受け渡しがないのでこの書き方になっています。

これでindex.blade.phpは↓の表示になります。

「+タスクを追加する」をクリックすると↓になります。

それではタスクに追加した内容をデータベースに登録してそれをタスク一覧のページ(index.blade.php)と詳細のページ(detail.blade.php)で表示させます。

同じ工程が2回出てきていますがルーティング→コントローラー→ビューの順にコードを書くと書きやすいと思います。

 

タスクの追加(ルーティングの設定)

「プロジェクト名 > routes > web.php」の編集をします。

<?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');

// 追加したタスクをデータベースに追加
Route::post('/tasks/add', [TasksController::class, 'store'])->name('tasks.store');          //この行を追加

26行目の「->name(‘tasks.store’)」ですがタスクをデータベースに追加する時にページは必要ないのでリンク先を「tasks.store」にしていますが何でもいいです。(ネットで調べたのですが情報を見つけることができなかったので仕様なのかもしれません)

次はコントローラーの設定です。

 

タスクの追加(コントローラーの設定)

「プロジェクト名 > app > Http > Controllers > TasksController.php」を編集します。

<?php

namespace App\Http\Controllers;

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

class TasksController extends Controller
{
    public function index()
    {
        $tasks = Task::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');
    }
    
    
    //ここから追加
    public function store(Request $request)
    {
        $result = Task::create([
            'name' => $request->name,
            'content' => $request->content,
        ]);

        return redirect()->route('tasks.index');
    }
    //ここまで追加
    
    
}

29行目のstore(Request $request)の「Request」ですが「use Illuminate\Http\Request」を省略したものでこれでフォームに入力した(タスクの)内容を受け取ります。

そして受け取った内容を「$request」として使う事ができます。

31行目の「Task::create」はEloquentモデルのcreateメソッドです。

createメソッドでは引数を配列の形で使います。

32行目・33行目とフォームに入力する値とデータベースのテーブルを色で対応させます。

上の図と下の図の赤枠と青枠が対応しています。

上の図と下のテーブルの黄色枠と緑枠が対応しています。

データベースにタスクと内容の追加が終わったらタスクを表示するページにリダイレクトさせますがそれが36行目です。

データベースにタスクと内容を登録しますがデータベースとのやりとりはモデルが行うのでTaskモデルの編集をします。

 

モデルの編集

Task.phpを編集します。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Task extends Model
{
    use HasFactory;

  
    // ここから追加
    protected $table = 'tasks';

    protected $primaryKey = 'id';

    protected $fillable = [
        'name',
        'content',
        'created_at',
        'updated_at',
    ];
    //ここまで追加
  
  
}

14行目に「protected $table」がありますがこれでEloquentモデルを使ってデータベースに接続する時にどのテーブルかの指定ができます。

16行目ですが今はtasksテーブルしかないのですが場合によっては複数のテーブルを使う場合があるので記載します。

idを主キーと言いますが主キーはどのテーブルかを判断することができる目印みたいな物です。

18行目の「protected $fillable」ですがtasksテーブルに追加するのを可能にするカラムを指定しますがここに何も書かないとカラムに値を追加することができません。

追加したい内容があるカラムに対して「protected $fillable」を設定せずにフォームから追加しようとすると↓の表示となりエラーが出ます。

次はタスクを追加するフォームがあるページ(add.blade.php)の設定をします。

 

タスクの追加(add.blade.php)

add.blade.phpのコードを↓にします。

<style>
    h1 {
        text-align: center;
        padding: 30px;
    }
    .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>
<form action="{{ route('tasks.store') }}" 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>

26行目を編集します。

26行目の「tasks.store」ですがフォームからデータベースに追加する時のリンク先です。

web.phpの26行目の「Route::post(‘/tasks/add’, [TasksController::class, ‘store’])->name(‘tasks.store’); 」の「tasks.store」です。

これでフォームに入力するとタスクが追加されます。

試しに追加しました、↓です。

今回はここまでですが今のままではフォームに何も入力せずにタスクの追加をしようとすると↓のエラーになります。

次回はその部分の修正とタスクを追加できないのとタスクの編集と削除の解説をしますが↓です。