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();
}
Тогда вы фактически не вызываете метод самостоятельно - он будет вызываться самим валидатором при выполнении правил.
Ответ 5
Я думаю, что это лучший подход для этого: Laravel 5.1 Изменить входные данные перед проверкой запроса формы
В Laravel 5.4+ есть специальный метод для подобных вещей, поэтому используйте его: prepareForValidation
Ответ 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