Вопрос или проблема
Я немного запутался относительно “правильного” способа получения текущего объекта сессии в контроллере Symfony 5.3. Текущая документация говорит о том, что нужно указать тип аргумента как SessionInterface
. Однако эта запись в блоге Symfony говорит, что SessionInterface
устарела в пользу использования RequestStack
.
В сервисах ясно, что я должен внедрить RequestStack
и вызвать $requestStack->getSession()
. Однако в большинстве методов контроллера я уже внедряю объект Request
, который также имеет метод getSession()
, и он, похоже, работает.
Можно ли получать сессию из объекта Request
, или мне следует дополнительно внедрять RequestStack
в свои методы контроллера (это кажется почти дублированием)
Быстрый пример кода:
// в контроллере
public function myRoute(Request $request): Response
{
$session = $request->getSession(); // это работает
}
// кажется глупым также внедрять RequestStack, когда у меня уже есть Request
public function myRoute(Request $request, RequestStack $requestStack): Response
{
$requestStack->getSession(); // это работает
}
// так, как показывает текущая документация
public function myRoute(Request $request, SessionInterface $session): Response
{
// это вызывает предупреждение об устаревании из-за внедрения SessionInterface
}
Документация еще не была обновлена.*
В Symfony 5.3+ вне контекста контроллера следует получать сессию из RequestStack
, как вы и делаете, и это описано в блоге. Там указаны причины, почему получение данных сессии из объекта Request
кажется неправильным, и почему SessionInterface
устарела в пользу RequestStack
:
- Сессия является объектом данных (например, как объект Request), поэтому для нее не должно быть определено сервиса в контейнере;
- Сессии не являются частью спецификации HTTP (ни HTTP/1.1, ни HTTP/2, ни HTTP/3), потому что HTTP без состояния. Поэтому странно управлять сессиями как частью компонента HttpFoundation.
Если вы уже получаете объект Request
(например, вы находитесь в контексте контроллера), вы также можете получить его оттуда напрямую, так как Request::getSession()
не устарел. Это нормально, и это просто часть удобства работы в рамках фреймворка.
Но если вы этого не делаете, получайте RequestStack
вместо SessionInterface
напрямую.
public function myRoute(RequestStack $requestStack): Response
{
$requestStack->getSession();
}
(И если вы это сделаете, вы также можете получить объект Request
оттуда, заменяя внедрение объекта данных на объект, похожий на сервис, чтобы получить эти данные).
* Помните, что сама документация является открытым исходным кодом, и они приветствуют пул-реквесты, чтобы поддерживать её в актуальном состоянии!
Ответ или решение
В Symfony 5.3 работа с объектом сессии в контроллерах требует более аккуратного подхода, чем в предыдущих версиях. Это связано с тем, что вместе с изменениями в архитектуре Symfony делаются акценты на более устойчивые и предсказуемые методы работы с сессиями. Давайте разберем, как правильно получать объект сессии в контроллере, основываясь на вашей запросе.
1. Инъекция и доступ к объекту сессии
В новых версиях Symfony вы можете использовать несколько способов для доступа к объекту сессии. Однако, с учетом предостережений из документации и блога Symfony, лучше всего придерживаться рекомендаций. В частности, стоит рассмотреть два подхода:
1.1 Получение объекта сессии через объект Request
Если вы работаете в контексте контроллера и у вас уже есть доступ к объекту Request
, вы можете просто вызывать метод getSession()
, который не был задепрецирован:
public function myRoute(Request $request): Response
{
$session = $request->getSession(); // Получение сессии через Request
// работа с сессией
}
Этот способ является удобным и вполне приемлемым, так как метод getSession()
возвращает текущую сессию, ассоциированную с конкретным запросом.
1.2 Использование RequestStack
Альтернативой может быть инъекция RequestStack
, как упоминается в документации:
public function myRoute(RequestStack $requestStack): Response
{
$session = $requestStack->getSession(); // Получение сессии через RequestStack
// работа с сессией
}
Этот подход может быть предпочтительным, если вы не ограничены контекстом контроллера или вам необходимо обрабатывать более сложные сценарии, где доступ к текущему объекту Request
может отсутствовать.
2. Почему SessionInterface
больше не рекомендуется
В Symfony 5.3 SessionInterface
больше не рекомендуется использовать, несмотря на то, что он всё ещё доступен. Два основных причины:
-
Отсутствие удобного API: Сессии, как данные, не должны рассматриваться как служебные объекты, эти данные зависят от контекста запроса и не должны быть в контейнере как сервис.
-
Состояние HTTP: Важно помнить, что протокол HTTP является безсостоянием по своей природе, и использование сессий противоречит этой концепции.
Поэтому, если вам нужно получить сессию в контексте контроллера, использование либо Request
, либо RequestStack
является лучшим выбором.
Заключение
Таким образом, хотя оба вышеуказанных метода допустимы, наиболее логичным выбором является использование метода getSession()
на объекте Request
, если он уже доступен в контроллере. Если вы добавляете новую функциональность или работаете вне контроллера, предпочтите инъекцию RequestStack
. Это позволит вам следовать наилучшим практикам и избегать использования устаревших методов.
Если вам нужно внести изменения в документацию или задать вопросы, не стесняйтесь делать это, так как сообщество Symfony активно поддерживает совместные усилия по улучшению документации.