Управление сессиями

Компонент Symfony HttpFoundation имеет очень мощную и гибкую подсистему сессий, которая сроектирована для предоставления возможности управления сессиями через простой объектно-ориенттированный интерфейс, используя различные драйверы хранения сессий.

Сессии используются через простую реализацию Session интерфейса SessionInterface.

Caution

Убедитесь в том, что ваша PHP сессия ещё не запущена перед там, как использовать класс Session. Если у вас есть унаследованная система сессий, которая запускает вашу сессию, см. Унаследованные сессии.

Быстрый пример:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
use Symfony\Component\HttpFoundation\Session\Session;

$session = new Session();
$session->start();

// устанавливать и получать атрибуты сессии
$session->set('name', 'Drak');
$session->get('name');

// устанавливать флеш-сообщения
$session->getFlashBag()->add('notice', 'Profile updated');

// извлекать сообщения
foreach ($session->getFlashBag()->get('notice', array()) as $message) {
    echo '<div class="flash-notice">'.$message.'</div>';
}

Note

Сессии Symfony созданы для замены нескольких оригинальных PHP функций. Приложениям стоит избегать использования session_start(), session_regenerate_id(), session_id(), session_name(), и session_destroy(), а вместо этого использовать API в следующем разделе.

Note

Несмотря на то, что рекомендуется запускать сессию ясно, на самом деле она начнётся по требованию, то есть, если будет создан запрос к сессии прочитать или записать данные сессии.

Caution

Сессии Symfony несовместимы с директивой php.ini session.auto_start = 1. Эту директиву нужно выключить в php.ini, в директивах веб-сервера или в .htaccess.

API Сессии

Класс Session реализует SessionInterface.

Session имеет простой API, который разделяется на несколько групп.

Рабочий процесс сессии

start()
Запускает сессию - не используйте session_start().
migrate()
Повторно генерирует ID сессии - не используйте session_regenerate_id(). Этот метод может опционально изменять время жизни нового куки, который будет излучен путём вызова этого метода.
invalidate()
Очищает все данные сессии и повторно генерирует ID сессии. Не используйте session_destroy().
getId()
Получает ID сессии. Не используйте session_id().
setId()
Устанавливает ID сессии. Не используйте session_id().
getName()
Получает имя сессии. Не используйте session_name().
setName()
Устанавливает имя сессии. Не используйте session_name().

Атрибуты сессии

set()
Устанавливает атрибут по ключу.
get()
Получает атрибут по ключу.
all()
Получает все атрибуты в виде массива ключ => значение.
has()
Возвращает "true", если атрибут существует.
replace()
Устанавливает несколько атрибутов одновременно: берёт массив ключей и устанавливает в каждом пару ключ => значение.
remove()
Удаляет атрибут по ключу.
clear()
Очистить все атрибуты.

Атрибуты хранятся внутренне в "Сумке", PHP объекте, который действует, как массив. Для управления "Сумкой" существует несколько методов:

registerBag()
Регистрирует SessionBagInterface.
getBag()
Получает SessionBagInterface по имени сумки.
getFlashBag()
Получает FlashBagInterface. Это просто сокращение для удобства.

Метаданные сессии

getMetadataBag()
Получает MetadataBag, который подержит информацию о сессии.

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

Управление PHP сессией требует использование суперглобального $_SESSION, однако, это несколько противоречит тестируемости кода и инкаспуляции в парадигме OOP. Чобы преодолеть это, Symfony использует сумки сессии, связанные с сессией, чтобы инкапсулировать конкретный набор данных атрибутов или флеш-сообщений.

Такой подход также уменьшает засорение пространства имён в рамках суперглобального $_SESSION, так как каждая сумка хранит все свои данные под уникальным пространством имён. Это позволяет Symfony мирно сосуществовать с другими приложениями или библиотеками, которые могут использовать суперглобальный $_SESSION, и все данные остаются полностью совмеситмыми с управлением сессий Symfony.

Symfony предоставляет два вида сумок хранения, с двумя разными реализациями. Все написано с учетом интерфейсов, так что вы можете расширить или создать ваши собственные виды сумок, по необходимости.

SessionBagInterface имеет следующий API, который в основном предназначен для внутренних целей:

getStorageKey()
Возвращает ключ, под которым сумка будет хранить свой массив в $_SESSION. Обычно это значение может остаться в состоянии по умолчанию и используется только внутренне.
initialize()
Вызывается внутренне классами хранения сессий Symfony, чтобы связать данные сумки с сессией.
getName()
Возвращает имя сумки сессии.

Атрибуты

Целью сумок, реализующих AttributeBagInterface является обработка хранилища атрибутов сессии. Это может включать в себя такие вещи, как ID пользователя, настройки входа "запомнить меня" или другую информацию, основанную на состоянии пользователя.

AttributeBag
Это стандартная реализация по умолчанию.
NamespacedAttributeBag
Эта реализация позволяет хранение атрибутов в структурированном пространстве имён.

Любая система хранения ключ-значение ограничена в том, какие сложные данные могут храниться, так как каждый ключ должен быть уникален. Вы можете достичь организации простраства имён, введя соглашение об именовании ключей, чтобы разные части вашего приложения могли работать без сбоев. Например, module1.foo и module2.foo. Однако, иногда не очень практично, если данные атрибутов находятся в массиве, например, наборе токенов. В таком случае, управление массивом становится сложной обязанностью, так как вам нужно извлекать массив, потом обрабатывать его, а потом сохранять его снова:

1
2
3
4
5
6
$tokens = array(
    'tokens' => array(
        'a' => 'a6c1e0b6',
        'b' => 'f4a7b1f3',
    ),
);

Поэтому любая обработка этого может быстр остать некрасивой, даже простое добавление токена в массив:

1
2
3
$tokens = $session->get('tokens');
$tokens['c'] = $value;
$session->set('tokens', $tokens);

Со структурированным пространством имён, ключ может быть переведен в структуру массива, вроде этого, используя символ пространства имён (по умолчанию /):

1
$session->set('tokens/c', $value);

Таким образом вы можете с лёгкостью получить доступ к ключу в рамках сохранённого массива напрямую.

AttributeBagInterface имеет простой API

set()
Устанавливает атрибут по ключу.
get()
Получает атрибут по ключу.
all()
Получает все атрибуты в виде массива ключ => значение.
has()
Возвращает "true", если атрибут существует.
replace()
Устанавливает несколько атрибутов одновременно: берёт массив ключей и устанавливает для каждого пару ключ => значение.
remove()
Удаляет атрибут по ключу.
clear()
Очищает сумку.

Флеш-сообщения

Цель FlashBagInterface - предоставить способ установки и извлечения сообщений на основанни каждой сессии. Обычный рабочий процесс выглядел бы, как установка флеш-сообщений в запросе и его отображение после перенаправления страницы. Например, пользователь отправляет форму, которая задействует контроллер обновлений, и после обработки контроллер перенаправляет страницу либо на обновлённую страницу, либо на страницу ошибки. Флеш-сообщения, установленные в запросе предыдущей страницы, будут отображены сразу же после того, как будет загружена последующая страница для этой сессии. Однако это только одно применение для флеш-сообщений.

AutoExpireFlashBag
В этой реализации сообщения, установленные в одной загрузке страницы, будут доступны для отображения только при следующей загрузке страницы. Срок действия таких сообщений автоматически истечёт, независимо от того, будут они извлечены, или нет.
FlashBag
В этой реализации, сообщения будут оставаться в сессии до тех пор, пока их ясно не извлекут или очистят. Это позволяет использовать ESI кеширование.

FlashBagInterface имеет простой API

add()
Добавляет флеш-сообщение в стек указанного типа.
set()
Устанавливает флеши по типу; Этот метод удобным образом берёт как одиночные сообщения в качестве string, либо несколько сообщений в качестве array.
get()
Получает флеши по типу и очищает те флеши в сумке.
setAll()
Устанавливает все флеши, принимает массив массивов с ключами type => array(messages).
all()
Получает все флеши (как массив массивов с ключами) и очищает флеши из сумки.
peek()
Получает флеши по типу (только для чтения).
peekAll()
Получает все флеши (только для чтения) в качестве массива массивов с ключами.
has()
Возвращает "true", если тип существует, и "false" - если нет.
keys()
Возвращает массиво сохранённых типов флешей.
clear()
Очищает сумку.

Для обычных приложений обычно достаточно иметь одно флеш-сообщение на тип, например, уведомление о подтверждении после отправки формы. Однако, флеш-сообщения хранятся в массиве с ключами по $type флеша, что означает, что ваше приложение может выдавать несколько сообщений на заданный тип. Это позволяет использование API для более сложных сообщений в вашем приложении.

Примеры установки нескольких флешей:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
use Symfony\Component\HttpFoundation\Session\Session;

$session = new Session();
$session->start();

// добавить флеш-сообщения
$session->getFlashBag()->add(
    'warning',
    'Your config file is writable, it should be set read-only'
);
$session->getFlashBag()->add('error', 'Failed to update name');
$session->getFlashBag()->add('error', 'Another error');

Отображение флеш-сообщений может выглядеть следующим образом.

Просто отобразить один тип сообщений:

1
2
3
4
5
6
7
8
9
// отобразить предупреждения
foreach ($session->getFlashBag()->get('warning', array()) as $message) {
    echo '<div class="flash-warning">'.$message.'</div>';
}

// отобразить ошибки
foreach ($session->getFlashBag()->get('error', array()) as $message) {
    echo '<div class="flash-error">'.$message.'</div>';
}

Компактный метод для обработки отображения всех флешей одновременно:

1
2
3
4
5
foreach ($session->getFlashBag()->all() as $type => $messages) {
    foreach ($messages as $message) {
        echo '<div class="flash-'.$type.'">'.$message.'</div>';
    }
}

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.