「PHPフレームワーク Laravel Webアプリケーション開発」の感想・備忘録5

スポンサーリンク

リクエスト

リクエストを参照する3つの方法

1. Requestファサード

$name = \Request::input('name');
$inputs = \Request::all();

Laravel5では別名で同じ機能を持つInputファサードがあったが、Laravel6で廃止された。
(クラスは存在するがエイリアスが設定されていない)

2. Requestオブジェクト

Illuminate\Http\Requestインスタンスを直接使用する場合は、メソッドインジェクションを使う。

class HogeController extends Controller
{
    public function index(Request $request)
    {
        // echo $request->input('name');
    }
}

3. フォームリクエスト

php aritsan make:request HogeRequestで生成可能。

フォームリクエストはIlluminate\Http\Requestを継承したクラスであり、バリデーションルールや認証機能を追加することができる。
バリデーションをコントローラから分離でき、コードの疎結合化につながる。

内部的には、サービスコンテナ(Illuminate\Foundation\Application)のresolvingメソッドとafterResolvingメソッドを使ってインスタンス生成とバリデーションを実行している。
コンテナイベントと呼ばれる機能で、コンテナが解決を行なった際に呼び出されるクロージャを登録することができる。
https://readouble.com/laravel/6.x/ja/container.html#container-events
resolving⇒afterResolvingの順番で実行される。

Illuminate/Foundation/Providers/FormRequestServiceProviderのbootメソッドは以下のようになっており、resolvingでinitializeRequestメソッド、afterResolvingでvalidateメソッド、をそれぞれコールしている。

$this->app->afterResolving(ValidatesWhenResolved::class, function ($resolved) {
    $resolved->validate();
});
$this->app->resolving(FormRequest::class, function ($request, $app) {
    $this->initializeRequest($request, $app['request']);
    $request->setContainer($app)->setRedirector($app->make(Redirector::class));
});

ちなみに、サービスコンテナへのFormRequestインスタンスのバインドはlluminate/Routing/RouteDependencyResolverTraitのtransformDependencyメソッドで行われている。
(アクションメソッドにタイプヒンティングしてあるクラス名を取得してバインドしている)

Requestクラスのメソッド

onlyメソッド

信頼できるリクエスト以外では、allメソッドではなくonlyメソッドを使い、指定した項目のみ取得するべきである。
$inputs = Input::only('name', 'age');
※nameやageが存在しない場合、$inputsにnameやageは含まれない。
(Laravel5.5未満では、$data[‘email’]にnullがセットされる)
$inputs = $Input::all('name','email');
とすると、存在しないものはnullとしてセットされる。

fileメソッド

アップロードされたファイルを取得する。
SplFileInfoを継承したSymfony\Component\HttpFoundation\File\UploadFileインスタンスが返される。
$file = Input::file('hoge');
$content = file_get_contents($file->getRealPath());

クッキー、HTTPヘッダ、サーバ情報の取得

  • $name = Input::cookie('name');
  • $acceptLanguage = Input::header('Accept-Language');
  • $remoteAddr =Input::server('REMOTE_ADDR');

バリデーション

バリデーションルール

配列で指定する方法と文字列をパイプで区切る方法がある。
正規表現を使う場合にパイプがメタ文字として扱われてしまうため、配列で指定するべき
$rule = ['email' => ['required', 'email']];

バリデーションを実行する3つの方法

1. コントローラのvalidateメソッド

$this->validate(
    $request,
    ['name' => ['required', 'max:10']],
    ['name.required' => '名前は必ず入力してください']
);

エラーの場合は、直前の画面にリダイレクトされる。

2. Validatorクラスのfailsメソッド

$validator = Validator::make(
    $request->all(),
    ['name' => ['required', 'max:10']],
    ['name.required' => '名前は必ず入力してください', 'name.max' => '名前は10文字以内で入力してください']
);
if ($validator->fails()) {
    // エラーの場合の処理
}

エラーの場合の処理は、自分で実装する。

3. フォームリクエストへのルール定義

public function rules() {
    return ['name' => ['required', 'max:10']];
}
public function messages() {
    return ['name.required' => '名前は必ず入力してください', 'name.max' => '名前は10文字以内で入力してください'];
}

エラーの場合は、直前の画面にリダイレクトされる。
エラーの場合の処理は、Illuminate/Foundation/Http/FormRequestのメソッドオーバーライドやプロパティ設定で変更可能。
エラーメッセージはmessagesメソッドオーバーライドで変更可能。

エラー内容の取得

エラー内容はIlluminate\Support\MessageBagインスタンスで保持されていて、ビューでは$errorsでアクセスできる。
($errorsは常に存在するため、存在チェックは不要)
エラー時にリダイレクトされた場合は、$errorsにエラー内容が自動的にセットされる。

Validatorクラスのfailsメソッドを使う場合は、redirect()やview()にwithErrors()を付加する必要がある。
(withInput()で入力値を付加)
return view('home')->withErrors($validator);

  • $errors->all():エラーメッセージ配列の取得。
  • $errors->has(‘name’):nameのエラー有無を取得。
  • $errors->first(‘name’):nameのエラーメッセージ(先頭)を取得。
@foreach ($errors->all() as $error)
    <p>{{ $error }}</p>
@endforeach
@if ($errors->has('name'))
    <p>{{ $errors->first('name') }}</p>
@endif

バリデーションルールの作成

Validator::extends()を使って定義する。

// 定義
\Validator::extend('abc', function($attrbute, $value, $parameters) {
    return preg_match('/^[abcABC]+$/', $value);
});
// 利用
$validator = \Validator::make(
    $request->all(),
    ['name' => ['required', 'abc']],
    ['name.required' => '名前は必ず入力してください', 'name.abc' => '名前はabcだけで入力してください']
);
if ($validator->fails()) {
    // エラーの場合の処理
}

Validator::extends()を使うこの方法は手軽だが、1回だけ使う場合に用いるべきである。
複数箇所で使用する場合は、独自のバリデーションクラスを作成する必要がある。
https://readouble.com/laravel/5.8/ja/validation.html#custom-validation-rules

特定の条件の場合のみ適用するルール

Validatorインスタンスのsometimesメソッドを使う。

$validator = \Validator::make(
    $request->all(),
    ['sex' => ['required']],
    ['sex.required' => '性別は必ず選択してください', 'age.required' => '男性の場合は年齢を入力してください']
);
$validator->sometimes('age', 'required', function ($input) {
    return $input->sex === 'man';
});
if ($validator->fails()) {
    // エラーの場合の処理
}

コメント