Requestオブジェクトでフォームの値を受け取る

laravelアイキャッチ Laravel

こんにちは、かつコーチです。

前回は、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->companynull になります。

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)の書き方

タイトルとURLをコピーしました