web-dev-qa-db-ja.com

Laravel 5 Form Request data pre-manipulation

ユーザーが生年月日を更新できるフォームを処理しています。このフォームは、daymonth、およびyearの3つの個別のフィールドをユーザーに提供します。もちろんサーバー側では、これら3つの個別のフィールドを1つの値、つまりyyyy-mm-ddとして扱います。

したがって、データベースを検証および更新する前に、フォーム要求を変更して、yearmonth、およびdaydate_of_birth文字と連結して-フィールドを作成し、日付形式を作成します。必要です(そして、おそらく元の3つのフィールドの設定を解除します)。

私のコントローラーでこれを手動で達成することは問題ではありません。入力を取得し、-文字で区切られたフィールドを結合して設定解除するだけです。その後、処理を処理するコマンドに渡す前に、手動で検証できます。

ただし、FormRequestを使用して検証を処理し、それをコントローラーメソッドに挿入することをお勧めします。したがって、検証を実行する前にフォームリクエストを実際に変更する方法が必要です。

同様の次の質問を見つけました: Laravel 5 Request-altering data

フォームリクエストのallメソッドをオーバーライドして、検証前にデータを操作するためのロジックを含めることをお勧めします。

<?php namespace App\Http\Requests;

class UpdateSettingsRequest extends Request {

    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [];
    }

    public function all()
    {
        $data = parent::all();
        $data['date_of_birth'] = 'test';
        return $data;
    }

これはすべて検証に適していますが、allメソッドをオーバーライドしても、フォームリクエストオブジェクトのデータは実際には変更されません。そのため、コマンドの実行に関しては、フォームリクエストには変更されていない元のデータが含まれています。オーバーライドされたallメソッドを使用してデータを引き出す場合を除きます。

特定のメソッドの呼び出しを必要としないフォームリクエスト内のデータを変更する、より具体的な方法を探しています。

乾杯

26
Jonathon

in laravel 5.1あなたはそれを行うことができます

<?php namespace App\Http\Requests;

class UpdateSettingsRequest extends Request {

public function authorize()
{
    return true;
}

public function rules()
{
    return [];
}

protected function getValidatorInstance()
{
    $data = $this->all();
    $data['date_of_birth'] = 'test';
    $this->getInputSource()->replace($data);

    /*modify data before send to validator*/

    return parent::getValidatorInstance();
}
35

自分をいじってから、次のことを思いつきました。

app/Http/Requests/Request.php

<?php namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

abstract class Request extends FormRequest {

    /**
    * Override the initialize method called from the constructor to give subclasses
    * an opportunity to modify the input before anything happens.
    *
    * @param array $query
    * @param array $request
    * @param array $attributes
    * @param array $cookies
    * @param array $files
    * @param array $server
    * @param null $content
    */
    public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
    {
        parent::initialize($query, $request, $attributes, $cookies, $files, $server, $content);

        // Grab the input
        $data = $this->getInputSource()->all();
        // Pass it off to modifyInput function
        $data = $this->modifyInput($data);
        // Replace modified data back into input.
        $this->getInputSource()->replace($data);
    }


    /**
    * Function that can be overridden to manipulate the input data before anything
    * happens with it.
    *
    * @param array $data The original data.
    * @return array The new modified data.
    */
    public function modifyInput(array $data)
    {
        return $data;
    }

}

次に、クラスを拡張するときに、次のようにmodifyInputメソッドをオーバーライドできます。

app/Http/Requests/TestRequest.php

<?php namespace App\Http\Requests;

class TestRequest extends Request {

    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [];
    }

    /**
     * Modify the input.
     */
    public function modifyInput(array $data)
    {
        $data['date_of_birth'] = 'something';

        // Make sure to return it.
        return $data;
    }

}

これは私のニーズに合っているようです。この方法で行うことの欠点はわかりませんので、コメントや批評を歓迎します。

上記のShift Exchangeによる回答も問題なく機能します。

9
Jonathon

Laravel 5.4なので、FormRequestクラスでprepareForValidationメソッドを使用できます。

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StorePostRequest extends FormRequest
{
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'title' => 'required|max:200',
            'body' => 'required',
            'tags' => 'required|array|max:10',
            'is_published' => 'required|boolean',
            'author_name' => 'required',
        ];
    }

    /**
     * Prepare the data for validation.
     *
     * @return void
     */
    protected function prepareForValidation()
    {
        $this->merge([
            'title' => fix_typos($this->title),
            'body' => filter_malicious_content($this->body),
            'tags' => convert_comma_separated_values_to_array($this->tags),
            'is_published' => (bool) $this->is_published,
        ]);
    }
}

より詳細な説明がここにあります: https://sampo.co.uk/blog/manipulating-request-data-before-performing-validation-in-laravel

7
BenSampo

私はこれがそうするための最良のアプローチだと思います: Laravel 5.1フォームリクエストの検証の前に入力を変更します

Laravel 5.4+では、このようなもの専用のメソッドがあるので、それを使用します:prepareForValidation

3

私はジュリア・ログビナと同様のアプローチを取りましたが、この方法は検証前にフィールドを追加/変更するためのわずかにエレガントな方法だと思います(Laravel 5.1)

_<?php

namespace App\Http\Requests;

use App\Http\Requests\Request;

class UpdateSettingsRequest extends Request
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {        
        return [];
    }


    /** 
     * Extend the default getValidatorInstance method
     * so fields can be modified or added before validation
     *
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function getValidatorInstance()
    {

        // Add new data field before it gets sent to the validator
        $this->merge(array('date_of_birth' => 'test'));

        // OR: Replace ALL data fields before they're sent to the validator
        // $this->replace(array('date_of_birth' => 'test'));

        // Fire the parent getValidatorInstance method
        return parent::getValidatorInstance();

    }

}
_

これにより、デフォルトのgetValidatorInstanceが拡張されるため、バリデーターに到達する前にリクエストの入力値を変更できます(元の変更されていないデータの使用を防止します)。データが変更されると、元のgetValidatorInstanceが起動され、その後はすべてが通常どおり続行されます。

$this->replace(array())または$this->merge(array())のいずれかを新しいフィールドをリクエストに使用できます。上記のスニペットに両方を行う方法の例を含めました。

replace()は、すべてのフィールドを指定した配列に置き換えます。

merge()は、リクエストに新しいフィールドを追加します。

3
bmagg

それでもall()メソッドをオーバーライドしますが、次のように試してください

public function all()
{
    $input = $this->all();
    $input['date_of_birth'] = $input['year'].'-'.$input['month'].'-'.$input['day'];
    $this->replace($input);
    return $this->all();
}

次に、実際にはcallメソッドを使用しないでください-ルールを実行するときにバリデーター自体によって呼び出されます。

2
Laurence

私もこれを達成するための迅速で汚い方法が必要でした。 The Shift Exchangesソリューションを使用したかったのですが、無限の再帰ループを作成する$thisの呼び出しが原因で機能しませんでした。代わりに親メソッドを参照するように簡単に変更すると、問題が修正されます。

public function all()
{
    $input = parent::all();
    $input['date_of_birth'] = $input['year'].'-'.$input['month'].'-'.$input['day'];
    $this->replace($input);
    return parent::all();
}

HTH他の人が必要です。

0
snstoller