【Laravel】Requestの値取得方法まとめ・解説
💡Requestとは?
LaravelのIlluminate\Http\Request
クラスは、アプリケーションが処理している現在のHTTPリクエストを操作し、リクエストとともに送信される入力、クッキー、およびファイルを取得するオブジェクト指向の手段を提供しています。
(と、ドキュメントは言っています。)
強力で便利なクラスですが、注意点もあるため、Laravelを学び始めた方、使ってるけどよく知らない方は、ぜひ一読ください。(熱いフィールドバックも受付中)
内容が大体良さそう!と思っていただけたら、いいねしていただけると嬉しいです。
✅ Request::get()
コードを辿ると、Symfony\Component\HttpFoundation\SymfonyRequest
クラスに定義されていることがわかります。
コードは下記のようになっています。
public function get(string $key, mixed $default = null): mixed
{
if ($this !== $result = $this->attributes->get($key, $this)) {
return $result;
}
if ($this->query->has($key)) {
return $this->query->all()[$key];
}
if ($this->request->has($key)) {
return $this->request->all()[$key];
}
return $default;
}
$this->query
には、GET、$this->request
にはPOSTの値が入っているため、GET -> POST の順で、見つかったものから返すというような処理になります。
✅ Request::input()
Illuminate\Http\Request
クラス内でuse
されているInteractsWithInput
トレイトに定義されているメソッドです。トレイトなので、実質Request
クラス直属のメソッドになります。
public function input($key = null, $default = null)
{
return data_get(
$this->getInputSource()->all() + $this->query->all(), $key, $default
);
}
コードを見ての通りですが、$this->getInputSource()
、つまりフォーム等から送信されたリクエストの内容と、GETの内容を + 演算子で結合したものから、キーに該当する値を取得するようになっています。
また、配列を.
区切りで指定できます。
これは、data_get()
というヘルパー関数により実現されています。
✅ Request::all()
こちらも、Illuminate\Http\Concerns\InteractsWithInput
に定義されているメソッドなので、実質Request
クラス直属のメソッドになります。
ファイルを含めた全てのリクエスト内容を取得します。
$input = array_replace_recursive($this->input(), $this->allFiles());
の部分では、 $this->input()
と同じキーがファイルに存在すると、ファイルで上書きされます。優先順位がファイルの方が上のようです。
public function all($keys = null)
{
$input = array_replace_recursive($this->input(), $this->allFiles());
if (! $keys) {
return $input;
}
$results = [];
foreach (is_array($keys) ? $keys : func_get_args() as $key) {
Arr::set($results, $key, Arr::get($input, $key));
}
return $results;
}
✅ Request::only()
こちらも、Illuminate\Http\Concerns\InteractsWithInput
に定義されているメソッドなので、実質Request
クラス直属のメソッドになります。
only()
は、all()
で取得した値を元に、指定されたキーの値を取得します。
public function only($keys)
{
$results = [];
$input = $this->all();
$placeholder = new stdClass;
foreach (is_array($keys) ? $keys : func_get_args() as $key) {
$value = data_get($input, $key, $placeholder);
if ($value !== $placeholder) {
Arr::set($results, $key, $value);
}
}
return $results;
}
このメソッドも、data_get()
を使って、.
区切りの配列の指定ができます。
✅ Request::query() / Request::post()
こちらも、Illuminate\Http\Concerns\InteractsWithInput
に定義されているメソッドなので、実質Request
クラス直属のメソッドになります。
同じような仕組みですので、まとめて説明します。
コードはこのようになっています。
・query()
public function query($key = null, $default = null)
{
return $this->retrieveItem('query', $key, $default);
}
・ post()
public function post($key = null, $default = null)
{
return $this->retrieveItem('request', $key, $default);
}
どうやら、retrieveItem()
というメソッドがキモになっていそうです。
中身はこのようなコードです。
protected function retrieveItem($source, $key, $default)
{
if (is_null($key)) {
return $this->$source->all();
}
if ($this->$source instanceof InputBag) {
return $this->$source->all()[$key] ?? $default;
}
return $this->$source->get($key, $default);
}
中身はシンプルで、$source
を元に、プロパティを使い分けて、それに応じた内容を取得してきているようです。query()
であれば$this->query
、post()
であれば、$this->request
からそれぞれall()
を呼ぶような形になっています。
これらのプロパティは、Symfony\Component\HttpFoundation\Request
クラスに定義されています。
プロパティの定義を見ると、このようになっています。
/**
* Request body parameters ($_POST).
*
* @var InputBag
*/
public $request;
/**
* Query string parameters ($_GET).
*
* @var InputBag
*/
public $query;
つまり、それぞれInputBag
のインスタンス(ParameterBag
を継承)であり、post()
を実行すると$request
=$_POST
の内容、query()
は$query
=$_GET
の内容を取得するような処理になっています。
✅ Request::__get()
Illuminate\Http\Request
クラスに定義してあるメソッドです。
コードはシンプルで、all()
から取得、なければroute()
から取得しています。
public function __get($key)
{
return Arr::get($this->all(), $key, fn () => $this->route($key));
}
⚠ 例
ユーザ情報を編集するようなルーティングを用意します。
Route::get('users/{user}/edit', 'edit')->name('edit');
URLは、https://example.com/users/1/edit
のようになります。
2. ルーティングモデルバインディングしたUser
モデルインスタンスと、Request
を受け取るようにします。
class UserController extends Controller
{
public function edit(User $user, Request $request)
{
//
}
}
public function edit(User $user, Request $request)
{
$request->__get('user');
}
この場合、$user
と同じ、User
モデルのインスタンスが取得できます。
次に、URLにuser
というクエリパラメータを付与してみます。https://example.com/users/1/edit?user=hoge
のようになります。
public function edit(User $user, Request $request)
{
$request->__get('user');
}
同じように実行すると、hoge
になります。
✅ Request::route()
Illuminate\Http\Request
クラスのメソッドです。
Request::__get()
で少し触れましたが、このメソッドは、URLのパスパラメータから取得するメソッドです。
中身はこのようになっており、$this->getRouteResolver()
により、Illuminate\Routing\Route
クラスに解決されます。
public function route($param = null, $default = null)
{
$route = call_user_func($this->getRouteResolver());
if (is_null($route) || is_null($param)) {
return $route;
}
return $route->parameter($param, $default);
}
$route->parameter()
を見てみると、このようになっています。
public function parameter($name, $default = null)
{
return Arr::get($this->parameters(), $name, $default);
}
さらに$this->parameters()
を辿るとこのようなコードになっています。
public function parameters()
{
if (isset($this->parameters)) {
return $this->parameters;
}
throw new LogicException('Route is not bound.');
}
$this->parameters
がセットされる箇所を見てみると、bind()
というメソッドでRouteParameterBinder
クラスのparameters()
が呼ばれていることがわかります。
public function bind(Request $request)
{
$this->compileRoute();
$this->parameters = (new RouteParameterBinder($this))
->parameters($request);
$this->originalParameters = $this->parameters;
return $this;
}
この中は、このような、パスパラメータをバインドしてるっぽいコードになっています。
public function parameters($request)
{
$parameters = $this->bindPathParameters($request);
...
}
基本的には、ルートモデルバインディングしたモデルインスタンスをリクエストから取得する場合は、Request::route()
を使うと確実と言えます。
まとめ
これらを見てみた限り、リクエスト内容を取得するときは、Request::input()
が良い感じに取ってきてくれるため、こちらを使用すると良いと思います。
また、先述したように、ルートモデルバインディングしたインスタンスを取得したい場合は、Request::route()
が良いと思います。
Discussion