Управление данными запроса перед валидацией

Управление данными запроса перед валидацией

При использовании Запросов формы (Form request) может пригодиться возможность управлять данными запроса перед выполнением правил валидации. Например:

  • Конвертация данных в нужный формат, ожидаемый валидацией (например, список значений через запятую — в массив).
  • Преобразование значения в другой тип (например, строка в число или строка в логическое значение)
  • Исправление распространенных пользовательских ошибок, например, опечаток.
  • Удаление нежелательного или потенциально опасного контента из входных данных.

Пример формы запроса

Начнем с примера запроса формы для сохранения записи в блог. Обратите внимание на правила, к которым применяются входные данные.

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',
        ];
    }
}

Давайте предположим, что пользователь отправил форму для создания записи и передал следующие входные данные:

[
    'title' => 'My bolg post',
    'body' => 'This is the <script>alert('Evil!')</script> post body.',
    'tags' => 'laravel,code,updates',
    'is_published' => 'true',
    'author_name' => 'Ben Sampson',
]

tags отправлены с фронтенда в виде списка значений, разделенных запятой, а is_published является строкой. Оба из них не пройдут валидацию, несмотря на то, что они верны с точки зрения содержимого, просто в неправильном формате.

Кроме того, похоже, что title содержит опечатку, а body — вредоносный код. Технически говоря, это не проблемы валидации, но мы все же можем спасти пользователя от себя самого и защитить наше приложение.

Метод prepareForValidation

Если посмотреть базовый класс Illuminate\Foundation\Http\FormRequest, который расширяет все запросы форм, то мы увидим, что он использует трейт ValidatesWhenResolvedTrait. Этот трейт содержит нужный нам метод, который позволяет использовать данные запроса до начала валидации. Метод имеет соответствующее название prepareForValidation и, по умолчанию, ничего не делает, что означает, что он был помещен туда с единственной целью — быть переопределенным.

protected function prepareForValidation()
{
    // отсутствуют дефолтные действия
}

Управление данными запроса

В запросе формы мы можем использовать метод prepareForValidation для управления любыми входными данными.

Поскольку базовый класс FormRequest расширяет класс Request, то у нас есть доступ к вспомогательному методу merge, который мы можем использовать для обновления только нужных нам входных значений. Мы также можем получить доступ к самим входным значениям, как и к свойствам класса.

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,
        ]);
    }
}

Используя магические хелперы, которые где-то есть в нашем приложении (тсссс, их нет), нам удалось получить такие данные:

[
    'title' => 'My blog post',                  // ✅ Опечатка исправлена!
    'body' => 'This is the post body.',         // ✅ Вредоносный код удален!
    'tags' => ['laravel', 'code', 'updates'],   // ✅ Теперь это массив!
    'is_published' => true,                     // ✅ Теперь это логическое значение!
    'author_name' => 'Ben Sampson',             // ✅ Все тоже самое
]

Значения обновлены в самом запросе, поэтому, как бы мы ни обращались к ним в нашем контроллере после валидации, мы получим обновленные значения.

Автор: Ben Sampson
Перевод: Demiurge Ash