Laravel 5 Форма Предварительная обработка данных запроса формы

Я обрабатываю форму, в которой пользователь может обновить дату своего рождения. Форма дает пользователю 3 отдельных поля для day, month и year. Конечно, на стороне сервера я хочу рассматривать эти 3 отдельных поля как одно значение, т.е. yyyy-mm-dd.

Поэтому перед проверкой и обновлением моей базы данных я хочу изменить запрос формы для создания поля date_of_birth путем объединения year, month и day с символами - для создания формата даты, который мне нужен (И, возможно, отключить исходные 3 поля).

Достижение этого вручную с помощью моего контроллера не является проблемой. Я могу просто захватить входные данные, соединить поля, разделенные символами -, и отключить их. Затем я могу выполнить проверку вручную, прежде чем перейти к команде для обработки обработки.

Тем не менее, я бы предпочел использовать FormRequest для проверки валидации и внести это в мой метод контроллера. Поэтому мне нужен способ фактического изменения запроса формы до выполнения проверки.

Я нашел следующий вопрос, похожий: Laravel 5 Запрос - изменение данных

Он предлагает переопределить метод 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, чтобы вытащить данные.

Я ищу более конкретный способ изменения данных в моем запросе формы, который не требует вызова определенного метода.

Приветствия

Ответы

Ответ 1

в 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();
}

Ответ 2

После некоторого вовлечения в себя я придумал следующее:

приложение/Http/Запросы/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 следующим образом:

приложение/Http/Запросы/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 выше, также будет работать очень хорошо.

Ответ 3

Я применил аналогичный подход к Julia Logvina, но я думаю, что этот способ - несколько более элегантный способ добавления/изменения полей перед проверкой (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() добавит новое поле в ваш запрос.

Ответ 4

Вы по-прежнему переопределяете метод all(), но попробуйте его следующим образом:

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

Тогда вы фактически не вызываете метод самостоятельно - он будет вызываться самим валидатором при выполнении правил.

Ответ 6

Мне тоже нужен был быстрый и грязный способ сделать это. Я хотел использовать решение 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 другие нуждаются.

Ответ 7

Так Laravel 5.4, вы можете использовать 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/manipulation-request-data-before-performing-validation-in-laravel