Иногда при обработке запросов в web-приложениях возникает необходимость в кратковременном сохранении промежуточной информации. Для записи информации в браузер клиента используется механизм cookies, для сохранения данных в пределах одного запроса — реестр, для сохранения данных между запросами — сессии. Под катом — примеры для Magento 2.
Cookies
class CookieHandler
{
const COOKIE_REFERRAL = 'referral';
protected $_cookieManager;
public function __construct(
\Magento\Framework\Stdlib\CookieManagerInterface $cookieManager
) {
$this->_cookieManager = $cookieManager;
}
public function getCookie()
{
$result = $this->_cookieManager->getCookie(self::COOKIE_REFERRAL, 'default value');
return $result;
}
public function setCookie($value)
{
// set public cookie (can be accessed by JS)
$meta = new \Magento\Framework\Stdlib\Cookie\PublicCookieMetadata();
$meta->setPath('/'); // use meta to define cookie props: domain, duration, security, ...
$meta->setDurationOneYear();
$this->_cookieManager->setPublicCookie(self::COOKIE_REFERRAL, $value, $meta);
// or set HTTP only cookie (is not accessible from JavaScript )
/** @var \Magento\Framework\Stdlib\Cookie\SensitiveCookieMetadata $meta */
$meta = null; // use meta to define cookie props: domain, duration, security, ...
$this->_cookieManager->setSensitiveCookie(self::COOKIE_REFERRAL, $value, $meta);
}
}
Registry
Реестр дает возможность использовать "глобальные переменные" в Magento (хотя сами глобальные переменные не приветствуется современным программистским сообществом). Реестр выбрасывает исключение при попытке записать в него данные с уже существующим ключом (если параметр $graceful = false) или просто игнорирует перезапись (если $graceful = true):
class RegistryHandler
{
const REG_REFERRAL = 'referral';
protected $_registry;
public function __construct(
\Magento\Framework\Registry $registry
) {
$this->_registry = $registry;
}
public function process()
{
// save value into the registry
$value = 'u54321';
$graceful = true; // don't throw exception if variable with the same name exists
$this->_registry->register(self::REG_REFERRAL, $value, $graceful);
// get value from registry
$registered = $this->_registry->registry(self::REG_REFERRAL);
// replace value
if ($this->_registry->registry(static::REG_REFERRAL)) {
$this->_registry->unregister(static::REG_REFERRAL);
}
$this->_registry->register(static::REG_REFERRAL, $value);
}
}
Почему-то метода для перезаписи какого-либо значения в реестре Magento не предоставляет, хотя, на мой взгляд, эта функция — логичное продолжение пары "register/unregister".
Session
SessionManagerInterface позволяет записывать и считывать данные в/из хранилища (StorageInterface). Хранилище представляет из себя DataObject, поэтому для сессии работают акцессоры get/set (через "магический" метод __call):
class SessionHandler
{
protected $_sessionManager;
public function __construct(
\Magento\Framework\Session\SessionManagerInterface $sessionManager
) {
$this->_sessionManager = $sessionManager;
}
public function process()
{
// save variable with name 'referral_code' into the session (using 'magic' methods)
$this->_sessionManager->setReferralCode('u54321');
// restore saved value from the session
$saved = $this->_sessionManager->getReferralCode();
}
}
В данном примере используется default namespace для сохранения данных, поэтому возникает вероятность пересечения по именам с разработчиками других модулей. Для уменьшения этой вероятности можно использовать префиксы в именах переменных, создавая чудовые имена методов типа setYourCompanyNameReferralCode($data)
, или использовать собственные имплементации SessionManager'а и связанного с ним SessionStorage'а с отличным от других namespace'ом.
P.S.
Спасибо isxam за дополнения и уточнения.
Комментарии (4)
flancer
20.05.2016 14:53Спасибо за коммент. Данная статья задумывалась как краткая сводка доступных способов промежуточного сохранения информации не в БД. Да, имплементаций интерфейса SessionManagerInterface достаточно много (навскидку, штук 10), но полезных рекомендаций по их использованию я дать не могу — я так глубоко не копал. Могу только сказать, что такой механизм существует, что я и сделал (информация действительно сохраняется между запросами, я проверял).
А по регистру — я посмотрел, но не понял, что именно может быть "не так"? Регистр (реестр) позволяет сохранять данные на все время своей жизни (в пределах одного запроса). Через DI доступен практически в любом классе. Если в Magento 2 есть какой-то другой механизм для выполнения таких же задач, было бы интересно о нем узнать. Сообщите, пожалуйста, о нем, и я дополню статью.
isxam
20.05.2016 15:181. да, механизм безусловно работает, но данные сохраняются в дефолтном неймспейсе, из-за чего может быть конфликт с другими модулями
2. регистр очень близок к глобальным переменным и лучше избавляться от его использования, изменив архитектуру.
Например на контроллере вью какой-то энтити вместо того, чтобы в экшене ее загрузить, засеттать в регистр и вытащить из регистра в блоке (или темлейте) можно загрузить энтити, взять из лейаута блок для отогбаражения, засеттать в него эту энтити, не прибегая к регистру. Таким образом если у вас появится потребность вывести на странице 10 таких же блоков с разными сущностями, то вам не напо попеременно в регистр подсовывать разные сущности, а всего-то сетать разные сущности в один блок и его рендерить
isxam
В Вашем примере с сессиями данные засетаются в дефолтный неймспейс, что не совсем правильно.
Более прикладной пример был бы
— с использованием существующих менеджеров (Checkout, Customer...)
— либо декларацией виртуального типа стореджа черезе di.xml с кастомным неймспейсом и подкидывание этого стореджа вашему session Manager `у и уже использование его в коде
Например:
И по регистру, если вы его используете, то, возможно, стоит посмотреть на код и подумать «Возможно здесь что-то не так?»