Когда я впервые познакомился с Symfony, то меня поразил компонент symfony/http-foundation
. Думаю, это один из самых важных пакетов современного PHP-приложения. Он заполняет лакуны основных PHP-функций, предоставляя дружественный объектно-ориентированный интерфейс для запросов и ответов.
В Laravel объекты Illuminate Request и Response
используют компонент HTTP Foundation через наследование и предоставляют отличный удобный API поверх основных классов.
В этой статье мы рассмотрим некоторые из методов объекта Illuminate Request.
Класс Illuminate\Http\Request
предлагает функционал в трёх трейтах, которые мы и рассмотрим:
InteractsWithContentTypes
InteractsWithInput
InteractsWithFlashData
Каких-то откровений и уникальных знаний здесь не будет, но, уверен, что вы откроете для себя один-два полезных метода. И, я надеюсь, что новички, которые не очень хорошо еще знают фреймворк смогут изучить эти важные классы и оценить все удобства Illuminate Request.
Взаимодействие с типами контента
В течение жизненного цикла запроса/ответа иногда необходимо определить тип запроса через HTTP-заголовок Content-Type
. Для этого InteractsWithContentTypes
предоставляет нам много синтаксического сахара, вместо того чтобы разбирать запрос через HTTP foundation.
Например, мы можем использовать следующие JSON-методы для определения, запрашивается ли JSON. И мы получим однозначный boolean
-ответ:
$request->wantsJson(); $request->expectsJson(); $request->isJson(); $request->acceptsJson();
Во- первых, метод isJson()
проверяет наличие /json
и +json
в заголовке Content-Type
. Он полезен для определения, отправил ли клиент JSON.
Разница между isJson()
и wantsJson()
заключается в следующих нюансах: wantsJson()
определяет заголовок Accept
при формировании правильного ответа на запрос, в то время как isJson()
используется для определения формата текущего запроса.
Точно так же метод expectsJson()
определяет, ожидает ли входящий запрос JSON-ответа: будет true
, если это AJAX-запрос, не PJAX-запрос, и принимает любой тип содержимого ( */*
).
Наконец, метод acceptptsJson()
полезен для определения есть ли application/json
в допустимых типах ответа. В этом методе используется основной метод accepts()
, который принимает строку или массив с типами контента:
$request->accepts(['application/xml', 'text/xml']);
Последний метод, который я хотел бы упомянуть из этого трейта — это format()
, который используется для определения формата ожидаемого ответа (с необязательным дефолтным значением):
// Определяет формат на основе запроса // Возвращает json, если формат не найден // среди допустимых типов контента $request->format('json');
Существует еще несколько методов, с которыми вы можете ознакомиться посмотрев исходник трейта InteractsWithContentTypes.php.
Взаимодействие с Входными Данными
Удобство работы с HTTP Input — моя любимая часть Illuminate Request.
Основная рабочая лошадка трейта InteractsWithInput
это метод input()
. Он очень простой и я покажу его вам полностью, прежде чем мы начнём его использовать:
/** * Получение элемента ввода из запроса * * @param string|null $key * @param mixed $default * @return mixed */ public function input($key = null, $default = null) { return data_get( $this->getInputSource()->all() + $this->query->all(), $key, $default ); }
Если заглянуть под капот, хелпер data_get()
, в сочетании с этим методом, предоставляет универсальный комплекс для получения входных данных из различных источников:
- Ввод
ParameterBag
- запрос
Request
Обычно этот метод используется для получения параметров POST|PUT|PATCH
и получения данных из строки запроса:
$email = $request->input('email');
Основной класс Request
также использует метод all()
трейта InteractsWithInput
для предоставления сокращенной версии вызова входных данных:
// Внутри вызывается $request->all() // и пытается получить входные данные из запроса $request->email
Еще один мой любимый метод в этом трейте это only()
. Обычно я вычищаю всё, кроме данных, которые мне нужны и которые я потом сохраню:
// вариативные аргументы через func_get_args() $request->only('email', 'password'); // или черех массив $request->only(['email', 'password']);
С помощью only()
я вношу в белый список нужные параметры запроса, чтобы избежать непреднамеренной утечки данных клиента.
Еще один полезный метод — это получение входных данных в виде boolean
, для определения являются ли они true
или false
:
// Проверка opt_in на наличие логических типов значенией // при дефолтном значении true // Вернёт true если на входе: 1, true, on, yes $request->boolean('opt_in', true);
У этого трейта есть полезные методы для работы с HTTP-заголовками:
// Полечение токена из заголовка авторизации // Удаление префикса "Bearer", если он имеется // то есть, "Authorization: Bearer 1234" вернёт "1234". $request->bearerToken(); $request->hasHeader('X-Custom-Header'); $request->header('X-Custom-Header');
Эти методы позволяют избежать базовый запросов Symfony:
// Эквивалентно $request->header('X-Custom-Header'); $request->headers->get('X-Custom-Header'); // Эквивалентно $request->hasHeader('X-Custom-Header') ! is_null($request->headers->get('X-Custom-Header'));
Еще несколько полезных вспомогательных методов для работы с входными данными:
// Все данные кроме password $request->except('password'); // Проверяем, есть ли в запросе ключ $request->has('age'); // Проверяем, есть ли в запросе какой-либо их следующих ключей $request->hasAny('age', 'height', 'weight'); // Получаем все ключ входных данных и файлов $request->keys(); // Проверяем, отсутствуют ли в запросе следующие данные $request->missing('age'); // Проверяем, заполненно ли поле See if the input is a non-empty value $request->filled('age'); // Проверяем, заполненны ли следующие поля $request->anyFilled('age', 'height', 'weight'); // Получаем ?id=12345 $request->query('id'); // Получаем массив всех файлов запроса $request->allFiles(); // Проверяем, есть ли загруженный файл для данного ключа $request->hasFile('avatar'); // Получаем файл из запроса $request->file('avatar');
Взаимодействие с данными сессии
Общей потребностью серверных приложениях является сохранение данных запроса в сессии, например при возникновении ошибок валидации. Передача данных в сессию гарантирует, что пользователь сможет исправить любые невалидные данные в форме и сохранить актуальные данные для использования в следующем запросе и ответе.
Возможно, вы знакомы с хелпером old()
в blade-файлах, который заполняет поля сессионными данными из предыдущего запроса:
<input type="email" value="{{ old("email") }}" required />
Он использует метод old()
в этом же трейте:
function old($key = null, $default = null) { return app('request')->old($key, $default); }
Как получить данные из сессии?
Если вы еще новичок в Laravel, то сохранении данных в сессии может вам показаться волшебством, так как Validation делает это автоматически. При возникновении ошибок валидации фреймворк кидает исключение ValidationException
, которое, в конечном итоге, сохраняет данные в сессии с помощью Response
через обработчик исключений:
/** * Преобразование исключения валидации в ответ * * @param \Illuminate\Http\Request $request * @param \Illuminate\Validation\ValidationException $exception * @return \Illuminate\Http\Response */ protected function invalid($request, ValidationException $exception) { return redirect($exception->redirectTo ?? url()->previous()) ->withInput(Arr::except($request->input(), $this->dontFlash)) ->withErrors($exception->errors(), $exception->errorBag); }
Обратите внимание, что $this->dontFlash
гарантирует, что поля password
и password_confirmation
не будут сохранены в сессии.
В большинстве случаев валидатор позаботится о переносе данных в сессию, но вы также можете вручную сохранить в ней входные данные:
// сохраняет данные $request->input() в сессии $request->flash();
Еще раз подчеркну, что при использовании этого метода обязательно позаботьтесь о том, чтобы конфиденциальные данные не передавались в сессию пользователя. Более аккуратный способ, это метод flashOnly()
:
$request->flashOnly('email', 'first_name', 'last_name');
или наоборот:
$request->flashExcept('password', 'secret_input');
Макросы и остальное
Поскольку объект Illuminate Request наследует HTTP Foundation Request, то всё, что есть в в нём, вы можете использовать. Ниже я дам ссылку на документацию по компоненту, если вы захотите узнать об этом больше.
Кроме того, вы можете расширить объект Request с помощью макросов. Laravel делает это с помощью метода Request::validate()
:
Request::macro('validate', function (array $rules, ...$params) { return validator()->validate($this->all(), $rules, ...$params); });
Дополнительные материалы
Я надеюсь, что статья была полезна как для тех, кто еще мало знаком с фреймворком Laravel, и хочет открыть для себя полезные инструменты, надстроенные поверх основного HTTP-слоя. Так и для более опытных, которым мы показали несколько новых методов объекта Illuminate Request или же вдохновили глубже изучить эти классы.
Для того, чтобы больше узнать об объектах запроса и ответа, рекомендуем ознакомиться со следующими ресурсами:
- Компонент HttpFoundation — Документация Symfony
- HTTP-запросы — Документация Laravel
- Illuminate/Http at 8.x — laravel/framework — GitHub
Автор: Paul Redmond
Перевод: Алексей Широков
Наш Телеграм-канал — следите за новостями о Laravel.