こんにちは、かつコーチです。
前回は、Bladeコンポーネントで画面のパーツを再利用する方法を解説しました。
画面が作れるようになったら、次に気になるのは「フォームに入力された値を、コントローラ側でどう受け取るか」ですよね。
PHPの生の書き方だと $_POST['name'] のように配列から値を取り出していましたが、LaravelではRequestオブジェクトという仕組みを使います。
今回は、このRequestオブジェクトの基本的な使い方を、実際のフォーム送信の流れに沿って解説します。
Requestオブジェクトとは?
HTTPリクエストの情報をまとめて扱うクラス
Requestオブジェクトとは、ブラウザから送られてきたリクエストの情報(フォームの入力値、URLのクエリパラメータ、ヘッダーなど)を、まとめて扱えるようにしたLaravelのクラスです。
生のPHPでは、送信方法によって $_GET と $_POST を使い分ける必要がありました。
Laravelでは、この違いを意識しなくても、Requestオブジェクトのメソッドひとつで値を取り出せます。
コントローラでの受け取り方
コントローラのメソッドの引数に Illuminate\Http\Request の型を指定するだけで、Laravelが自動的にRequestオブジェクトを渡してくれます。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ContactController extends Controller
{
public function store(Request $request)
{
$name = $request->input('name');
$email = $request->input('email');
// ここでDB保存などの処理を行う
return redirect('/contact/complete');
}
}
このように引数に型を書いておくだけで値が渡ってくる仕組みを、Laravelでは依存性注入(Dependency Injection)と呼びます。
「Requestという名前のクラスを引数に書いておけば、Laravel側がよしなに用意してくれる」くらいの理解でひとまず大丈夫です。
フォームの値を取得する方法
input()で1つの値を取得する
もっとも基本的な取得方法が input() メソッドです。
<?php
$name = $request->input('name');
name という名前のinput要素(<input name="name">)の値を取得します。
第2引数にデフォルト値を渡すこともできます。
<?php
$age = $request->input('age', 20); // ageが送られてこなければ20が入る
アクセサ形式で取得する
input() を省略して、プロパティのようにアクセスする書き方もよく使われます。
<?php
$name = $request->name;
$email = $request->email;
input() を使う書き方との違いは、デフォルト値を指定できない点です。
「値が存在するのが前提の項目」はアクセサ形式、「未入力の可能性がある項目」は input() にデフォルト値を添えて書く、という使い分けをすると読みやすいコードになります。
all()でまとめて取得する
送信されたすべての値をまとめて取得したい場合は all() を使います。
<?php
$data = $request->all();
// ['name' => '山田太郎', 'email' => 'yamada@example.com', ...]
デバッグ時に「今どんな値が送られてきているか」を確認したいときにも重宝します。
<?php
dd($request->all());
dd()(dump and die)で内容を出力してから処理を止められるので、フォームの値が正しく届いているかを確認するときの定番の方法です。
only()・except()で必要な項目だけ絞り込む
登録処理などでは、フォームの値をそのままモデルに渡したい場面がよくあります。
そんなときに便利なのが only() と except() です。
<?php
// name と email だけを取得する
$data = $request->only(['name', 'email']);
// _token(CSRFトークン)以外をすべて取得する
$data = $request->except(['_token']);
create() や update() にそのまま渡す形にしておくと、コードがすっきりします。
<?php
use App\Models\Contact;
public function store(Request $request)
{
Contact::create($request->only(['name', 'email', 'message']));
return redirect('/contact/complete');
}
つまずきやすいポイント:存在しないキーへのアクセスでハマった話
input()とプロパティアクセスの違いに気づかなかった
私が初めてRequestオブジェクトを使ったとき、任意項目(未入力でもよい項目)の扱いでつまずいたことがあります。
お問い合わせフォームに「会社名(任意)」という欄を用意していたのですが、次のように書いてしまいました。
❌ Before:未入力を考慮せずアクセサ形式で書く
<?php
public function store(Request $request)
{
$company = $request->company;
// 会社名がある場合だけ「様」を付けて表示用の文字列を作る処理のつもり
$companyLabel = $company . '様';
// 会社名が未入力の場合、$company が null になり
// "様" というラベルだけが不自然に生成されてしまう
}
未入力時、$request->company は null になります。
null と文字列を連結しても即座にエラーにはならないため、しばらく気づかず、「会社名なしの人にも謎の”様”というラベルが出る」という不具合を本番で見つけて青ざめた経験があります。
✅ After:input()のデフォルト値とnull合体演算子で明示的に処理する
<?php
public function store(Request $request)
{
$company = $request->input('company', '');
$companyLabel = $company !== '' ? $company . ' 様' : '';
// もしくは filled() で「値があるかどうか」を明示的にチェックする
if ($request->filled('company')) {
$companyLabel = $request->input('company') . ' 様';
}
}
「未入力の可能性がある値」を扱うときは、input() にデフォルト値を渡すか、filled() メソッドで存在チェックをしてから使う、という習慣をこの一件以来徹底するようになりました。
has()とfilled()の違い
似たメソッドに has() もありますが、filled() との違いに注意が必要です。
| メソッド | 判定内容 |
|---|---|
has('key') | キー自体が送信されているか(空文字でもtrue) |
filled('key') | キーが存在し、かつ値が空でないか |
たとえば <input name="company" value=""> のように空文字が送られてきた場合、has('company') は true を返しますが、filled('company') は false を返します。
「入力されているかどうか」を判定したい場面では、基本的に filled() を使うのが安全です。
応用・一歩先の使い方
ファイルアップロードの値を受け取る
フォームで画像などのファイルをアップロードする場合は、input() ではなく file() を使います。
<?php
public function store(Request $request)
{
if ($request->hasFile('avatar')) {
$path = $request->file('avatar')->store('avatars', 'public');
}
}
hasFile() でファイルが送信されているか確認してから file() で取得する、という流れがセットで使われます。
メソッドチェーンで条件付き取得をする
Laravelには、値の有無によって処理を分けたいときに便利な whenFilled() というメソューもあります。
<?php
$request->whenFilled('company', function ($company) {
// 会社名が入力されているときだけ実行される処理
return $company . ' 様';
});
if文を並べるよりも「この値があるときだけ実行する」という意図がコードから読み取りやすくなるため、条件分岐が増えてきたコントローラでは検討する価値があります。
まとめ
この記事のポイント
- RequestオブジェクトはHTTPリクエストの情報をまとめて扱うクラスで、コントローラの引数に型を書くだけで受け取れる
- 値の取得は
input()、アクセサ形式、all()、only()/except()を場面によって使い分ける - 未入力の可能性がある値は
input()のデフォルト値かfilled()での存在チェックを忘れない has()は空文字でもtrueになるが、filled()は値が空でないことまで確認する- ファイルは
input()ではなくhasFile()/file()で受け取る
次に読むべき記事
フォームの値を受け取れるようになったら、次は「その値が正しい形式かどうか」をチェックするバリデーションを学んでいきましょう。
→ 次の記事:Laravelのバリデーション(Validation)の書き方