Изменение запроса, получение данных из сеанса
Сценарий:
- У меня нет AJAX.
- У меня есть форма поиска с
GET
метод иcsrf_protection
отключено, что фильтрует объекты, показанные и разбитые на страницыmyEntityListAction
, достижимы в Ури/myapp/myentity/list
- Пользователь открывает
/myapp/myentity/list
, отправьте форму фильтра и перейдите на страницу 2. Сейчас он включен/myapp/myentity/list?entity_filter[search]=something&page=2
- Пользователь открывает другую страницу (скажем, детали одного из показанных объектов), а затем нажимает на
/myapp/myentity/list
Я хочу, чтобы он увидел страницу /myapp/myentity//list?entity_filter[search]=something&page=2
Я пытаюсь сделать фильтры привязанными к сеансу пользователя, чтобы при повторном открытии пользователя /myapp/myentity/list
без параметров он получает последний увиденный результат с теми же фильтрами и номером страницы.
Я следовал этому подходу, но я думаю, что он сильно устарел, потому что я изменяю $request
объект и $_GET
superglobal (из-за библиотеки разбивки на страницы, которая использует непосредственно $_GET), несмотря на то, что она работает.
/**
* @Route("/myapp/myentity/list", name="entity_list")
* @Method({"GET"})
*/
public function myEntityListAction(Request $request) {
if (0===$request->query->count()) { //querystring is empty
$prev_query=$request->getSession()->get('my_entity_list', null);
if ($prev_query) { //is there something in session?
$_GET=$prev_query;
$original_request=$request;
$request=$request->createFromGlobals();
$request->setSession($original_request->getSession());
}
} else { //i have something in my querystring
$request->getSession()->set('my_entity_list', $request->query->all()); //i store it in session
}
//...do the other stuff (form, filters, pagination, etc)
}
Я думаю, что я буду следовать другому подходу, перенаправляя пользователя на /myapp/myentity/list?entity_filter[search]=something&page=2
(чтение из сессии), так что мне не нужно ни изменять $_GET
или же $request
,
Возникает вопрос: как я могу безопасно отредактировать запрос $, чтобы добавить или изменить что-то, что мне нужно, без перенаправления? Могу ли я безопасно сделать это с подзапросом?
2 ответа
Вы можете использовать перед фильтром для этого. В слушателе проверьте ваш сеанс, извлеките сохраненный путь (или фильтры) и просто перенаправьте (если хотите), используя что-то вроде
$event->setController(function() use ($redirectUrl) {
return new RedirectResponse($redirectUrl);
});
Также вы можете получить запрос, используя $event->getRequest()
и измени его как хочешь.
Повторное объяснение настройки
Вы не можете безопасно редактировать запрос. Запрос не должен быть изменен внутри контроллера, потому что это "последнее место", которым вы будете его использовать (даже если вы можете использовать его и в представлениях). Это не совсем безопасно.
Перенаправления основаны на ответах, а не на запросах.
(Бонус: что-то хорошее, чтобы позволить пользователю сбросить (или "очистить") эту информацию в сеансе. Я предлагаю вам создать для этого кнопку.)
Давайте еще раз объясним ваши (уже хорошие) сценарии:
- Шаг 1:
Пользователь переходит к/myapp/myentity/list
Ничего в запросе, ни в сессии.
Список показывается как надо - Шаг 2:
Пользователь отправляет форму поиска, нажавPage 2
например
Отправка формы заставляет пользователя перейти на/myapp/myentity/list?entity_filter[search]=something&page=2
Как только этот запрос сделан, контроллер сохраняет строку запроса в сеансе как "последнюю увиденную строку запроса",my_entity_list
параметр сеанса, который вы уже используете.
Показать список как следует с фильтрами - Шаг 3:
Пользователь возвращается к/myapp/myentity/list
например, нажав на логотип
Ничего в запросе. Но имея что-то на сессии. Пользователь перенаправлен на/myapp/myentity/list?{last_query_string}
А затем вернитесь к шагу 2 - Шаг 4:
Пользователь нажимает кнопку "Очистить фильтры".
AJAX или простой запрос, не имеет значения:my_entity_list
сбрасывается с сессии любым контроллером.
Перенаправить пользователя на/myapp/myentity/list
,
Вернуться к шагу 1.
Теперь код
Ваш код также должен быть реорганизован примерно так:
/**
* @Route("/myapp/myentity/list", name="entity_list")
* @Method({"GET"})
*/
public function myEntityListAction(Request $request) {
// First, get query string
$queryStringArguments = $request->query->all();
if (0 === count($queryStringArguments)) {
$lastQueryStringArguments = $request->getSession()->get('my_entity_list', null);
if ($lastQueryStringArguments) {
// Just replace the var, don't manipulate the request
$queryStringArguments = $lastQueryStringArguments;
}
}
// Whatever the var is retrieved from request or session,
// this will always be saved in session.
if (count($queryStringArguments)) {
$request->getSession()->set('my_entity_list', $queryStringArguments); //i store it in session
}
//...do the other stuff (form, filters, pagination, etc)
}
И, наконец, лучшие практики
В вашем случае то, что вы делаете, абсолютно не безопасно от уколов.
Вы должны проверить строку запроса и получить только те данные, которые вам нужны.
Это можно сделать с помощью FormType
или простые ручные проверки, и вы должны сбросить все нежелательные / неиспользуемые аргументы строки запроса, чтобы избежать потенциальных инъекций.
Использование переменной типа $allowedParams = ['page', 'search_query', 'filter_by_id'];
или что-то подобное очень просто реализовать и поможет вам сбросить все ключи, которых нет в этом массиве (и, следовательно, не добавлять их в сеанс и не манипулировать вашими формами с помощью html/javascript-инъекций)