フォームとバリデーション
CRUD? データ操作の基本4種「Create(作成)・Read(取得)・Update(更新)・Delete(削除)」の頭文字。Webアプリの基本機能。 の「C(Create)」「U(Update)」にはフォームが欠かせません。今回はHTMLフォームでデータを受け取り、 バリデーション? フォームに入力されたデータが正しい形式かをチェックする処理。「メールアドレスの形式か」「空欄でないか」などを検証する。 で検証する流れを一通り実装します。
新しいルートを追加する
フォームには2種類のルートが必要です。「フォームページを表示する」と「送信されたデータを受け取って処理する」の2つです。
routes/web.php を開き、次の2行を追加してください(use App\Http\Controllers\TaskController; の行もなければ追加します)。
<?php
// 📁 routes/web.php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TaskController; // ← なければ追加
// 既存のルートの下に追加
Route::get('/tasks/create', [TaskController::class, 'create']); // フォームページ表示
Route::post('/tasks', [TaskController::class, 'store']); // データ受け取り
get はページを表示するだけ、post はフォームからデータが送られてきたときの処理です。
コントローラーにメソッドを追加する
app/Http/Controllers/TaskController.php を開き、2つのメソッドを追加します。
<?php
// 📁 app/Http/Controllers/TaskController.php
namespace App\Http\Controllers;
use App\Models\Task;
use Illuminate\Http\Request; // ← この行が先頭にあることを確認
class TaskController extends Controller
{
// ──────────────────────────────────────────────
// フォームページを表示する
// ──────────────────────────────────────────────
public function create()
{
return view('tasks.create');
// resources/views/tasks/create.blade.php を表示
}
// ──────────────────────────────────────────────
// フォームの送信を受け取って保存する
// ──────────────────────────────────────────────
public function store(Request $request)
{
// $request にフォームのデータが入っている
$title = $request->input('title'); // フォームの name="title" の値
$body = $request->input('body'); // フォームの name="body" の値
Task::create([
'title' => $title,
'body' => $body,
'done' => false,
]);
return redirect('/tasks'); // 保存後に一覧ページへ移動
}
}
Request $request は送られてきたリクエスト全体を受け取るオブジェクトです。$request->input('フィールドのname属性') でフォームの値を取り出せます。
フォームのビューを作る
resources/views/tasks/create.blade.php を新規作成します。
myapp/
└── resources/
└── views/
└── tasks/ ← フォルダを新規作成(なければ)
└── create.blade.php ← ファイルを新規作成
resources/views/tasks/create.blade.php の内容:
<!-- 📁 resources/views/tasks/create.blade.php(新規作成) -->
@extends('layouts.app')
@section('title', 'タスクを追加')
@section('content')
<h1>タスクを追加</h1>
<form method="POST" action="/tasks">
@csrf
<div>
<label for="title">タイトル</label>
<input type="text" id="title" name="title" value="{{ old('title') }}">
</div>
<div>
<label for="body">内容</label>
<textarea id="body" name="body">{{ old('body') }}</textarea>
</div>
<button type="submit">追加する</button>
</form>
@endsection
@csrf は必ず書く
@csrf はフォームの中に必ず入れてください。これは CSRF? 悪意あるサイトから偽のリクエストを送りつける攻撃手法。Laravelはフォームに隠しトークンを埋め込んで防いでいる。 攻撃を防ぐための隠しトークンを埋め込む命令です。書き忘れると、フォームを送信したときに「419 Page Expired」というエラーが表示されます。
実際に展開されると次のような隠しフィールドになっています。
<input type="hidden" name="_token" value="ランダムな文字列">
バリデーションを追加する
フォームから送られたデータをそのまま保存するのは危険です。 バリデーション? フォームに入力されたデータが正しい形式かをチェックする処理。「メールアドレスの形式か」「空欄でないか」などを検証する。 でデータが正しい形式かを確認してから保存します。
TaskController.php の store() メソッドを次のように書き換えます。
// 📁 app/Http/Controllers/TaskController.php
// store() メソッドを書き換える
public function store(Request $request)
{
// バリデーション(検証)を実行する
$validated = $request->validate([
'title' => ['required', 'max:100'], // 必須・100文字以内
'body' => ['nullable', 'max:1000'], // 任意・1000文字以内
]);
// → 検証に失敗すると自動でフォームページに戻る
// → 成功すると $validated に検証済みの値が入る
Task::create([
'title' => $validated['title'],
'body' => $validated['body'] ?? null,
'done' => false,
]);
return redirect('/tasks');
}
validate() の配列には「'フィールド名' => ['ルール1', 'ルール2', ...]」を書きます。
よく使うバリデーションルール:
| ルール | 意味 |
|---|---|
required | 必須(空欄は不可) |
nullable | 空欄でもOK |
max:100 | 最大100文字 |
min:8 | 最小8文字 |
email | メールアドレスの形式 |
integer | 整数 |
unique:users | usersテーブルで重複しない |
バリデーションエラーを表示する
validate() に失敗すると、Laravelは自動でフォームページに戻り $errors という変数を渡してくれます。ビューにエラー表示を追加しましょう。
resources/views/tasks/create.blade.php の <form> タグの直前に追加します。
<!-- 📁 resources/views/tasks/create.blade.php -->
<!-- <form> タグの直前に追加 -->
@if ($errors->any())
<div style="color: red;">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
特定のフィールドのエラーだけ、フィールドの直下に表示するには @error ディレクティブが使えます。
<!-- 📁 resources/views/tasks/create.blade.php -->
<!-- title の input タグの直後に追加 -->
<input type="text" id="title" name="title" value="{{ old('title') }}">
@error('title')
<p style="color: red;">{{ $message }}</p>
@enderror
old() で入力値を保持する
old('title') は「直前にこのフィールドに入力された値」を返します。バリデーションに失敗してフォームページに戻ったとき、入力した値が消えずに残るようになります。
完了メッセージを表示する
タスクを保存した後「追加しました」と表示するには フラッシュメッセージ? リダイレクト後に一度だけ表示されるメッセージ。「保存しました」などの完了通知によく使われる。次のリクエスト後は消える。 を使います。
store() メソッドの redirect() 部分を次のように変更します。
// 📁 app/Http/Controllers/TaskController.php
// store() の最後の return を書き換える
return redirect('/tasks')->with('success', 'タスクを追加しました');
// ↑ セッションに一時的にメッセージを保存
次に、一覧ページのビュー resources/views/tasks/index.blade.php を開き、一覧の上にメッセージ表示を追加します。
<!-- 📁 resources/views/tasks/index.blade.php -->
<!-- <h1> タグの直後に追加 -->
@if (session('success'))
<p>{{ session('success') }}</p>
@endif
このメッセージはリダイレクト後に1回だけ表示されます。ページをリロードすると自動的に消えます。
リダイレクトとは
リダイレクト? ユーザーを別のURLへ誘導すること。フォーム送信後に一覧ページへ飛ばすなど、操作の完了を示すときによく使う。 は「今のページからあのURLへ移動して」とブラウザに指示することです。
フォーム送信後にそのまま同じページに留まると、ブラウザをリロードしたときにフォームが再送信されてしまいます(データが2重登録される)。これを防ぐためにも、保存後は別ページへリダイレクトする習慣をつけましょう。
まとめ
この回でやったこと:
routes/web.phpにGETとPOSTの2つのルートを追加したcreate()でフォームビューを返し、store()で入力を受け取った$request->input()でフォームの値を取り出した$request->validate()でバリデーションを実装した$errorsとold()でエラー時の表示を整えたflash_messageで完了メッセージを表示した
次回はいよいよ最終回。ここまでの知識をすべて使ってタスク管理アプリのCRUDを完成させます。