Compare commits

...

6 Commits

Author SHA1 Message Date
Arsen Mirzaev Tatyano-Muradovich 5509400e3e Косметические изменения 2022-11-06 11:20:51 +10:00
Arsen Mirzaev Tatyano-Muradovich 74fc42f85d Смена пространства имён 2022-11-06 11:17:51 +10:00
Arsen Mirzaev Tatyano-Muradovich 2176827519 rename 2022-11-06 11:10:00 +10:00
Arsen Mirzaev Tatyano-Muradovich 935ac8611e transition from hood.su 2022-11-06 10:59:21 +10:00
Arsen Mirzaev Tatyano-Muradovich e709d3d914 Исправления 2021-03-29 10:19:31 +10:00
Arsen Mirzaev Tatyano-Muradovich 8809a05c1b Исправление зависимостей 2021-03-22 04:58:00 +10:00
5 changed files with 179 additions and 85 deletions

4
.gitignore vendored
View File

@ -1 +1,3 @@
/vendor/ !.gitignore
composer.phar
vendor

View File

@ -1,26 +1,36 @@
{ {
"name": "mirzaev/yii2-arangodb-sessions", "name": "mirzaev/yii2-sessions-arangodb",
"description": "Yii\\web\\DbSession implementation for use with ArangoDB", "description": "Module with yii\\web\\DbSession implementation for use with ArangoDB",
"keywords": [ "keywords": [
"Yii2", "Yii2",
"ArangoDB", "ArangoDB",
"DbSession" "DbSession"
], ],
"type": "yii2-extension", "type": "yii2-extension",
"license": "AGPL-3.0-or-later", "license": "WTFPL",
"homepage": "https://git.hood.su/mirzaev/yii2/arangodb/sessions", "homepage": "https://git.mirzaev.sexy/mirzaev/yii2-sessions-arangodb",
"authors": [ "authors": [
{ {
"name": "Arsen Mirzaev Tatyano-Muradovich", "name": "Arsen Mirzaev Tatyano-Muradovich",
"email": "red@hood.su", "email": "arsen@mirzaev.sexy",
"homepage": "https://hood.su/mirzaev", "homepage": "https://mirzaev.sexy",
"role": "Developer" "role": "Programmer"
}
],
"support": {
"email": "arsen@mirzaev.sexy",
"wiki": "https://git.mirzaev.sexy/mirzaev/yii2-sessions-arangodb/wiki",
"issues": "https://git.mirzaev.sexy/mirzaev/yii2-sessions-arangodb/issues"
},
"funding": [
{
"type": "funding",
"url": "https://fund.mirzaev.sexy"
} }
], ],
"require": { "require": {
"php": "^8.0.0", "php": "^8.0",
"yiisoft/yii2": "2.*", "yiisoft/yii2": "2.*",
"triagens/arangodb": "~3.2",
"mirzaev/yii2-arangodb": "~2.1.x-dev" "mirzaev/yii2-arangodb": "~2.1.x-dev"
}, },
"require-dev": { "require-dev": {
@ -28,12 +38,12 @@
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"mirzaev\\yii2\\arangodb\\sessions\\": "mirzaev/yii2/arangodb/sessions" "mirzaev\\yii2\\arangodb\\sessions\\": "mirzaev/yii2/sessions/arangodb/system"
} }
}, },
"autoload-dev": { "autoload-dev": {
"psr-4": { "psr-4": {
"mirzaev\\yii2\\arangodb\\sessions\\tests\\": "mirzaev/yii2/arangodb/sessions/tests" "mirzaev\\yii2\\arangodb\\sessions\\tests\\": "mirzaev/yii2/sessions/arangodb/tests"
} }
} }
} }

View File

@ -2,21 +2,24 @@
declare(strict_types=1); declare(strict_types=1);
namespace mirzaev\yii2\arangodb\sessions; namespace mirzaev\yii2\sessions\arangodb;
// Фреймворк Yii
use yii; use yii;
use yii\di\Instance; use yii\di\Instance;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use mirzaev\yii2\arangodb\Connection; // Модуль ArangoDB для фреймворка Yii
use mirzaev\yii2\arangodb\Query; use mirzaev\yii2\arangodb\Connection,
mirzaev\yii2\arangodb\Query;
// Встроенные библиотеки
use Exception; use Exception;
/** /**
* Реализация DbSession под ArangoDB * Реализация DbSession под ArangoDB
* *
* @property Connection|array|string $database Идентификатор компонента (Component ID) * @property Connection|array|string $database Идентификатор компонента с базой данных (Component ID)
* @property string $document Название документа для хранения данных сеанса (Document name for storing session data) * @property string $document Название документа для хранения данных сеанса (Document name for storing session data)
* @property array $buffer Буфер данных для записи в документ сессии (Data buffer for write to session document) * @property array $buffer Буфер данных для записи в документ сессии (Data buffer for write to session document)
* *
@ -31,6 +34,7 @@ use Exception;
* @method public destroySession() Удалить сессию (Delete session) * @method public destroySession() Удалить сессию (Delete session)
* @method public gcSession() Удалить неиспользуемые данные (Delete garbage) * @method public gcSession() Удалить неиспользуемые данные (Delete garbage)
* @method protected getReadQuery() Генерация запроса для чтения сеанса (Generating a query to read a session) * @method protected getReadQuery() Генерация запроса для чтения сеанса (Generating a query to read a session)
* @method protected genBuffer() Генерация массива данных для записи (Generating an array of data to writing)
* @method protected typecastFields() Конвертация для отправки в PDO (Convertation for sending to PDO) * @method protected typecastFields() Конвертация для отправки в PDO (Convertation for sending to PDO)
* *
* @example ./Migrations/create_sessions_collection.php * @example ./Migrations/create_sessions_collection.php
@ -43,14 +47,16 @@ use Exception;
* *
* @see yii\web\DbSession Наследует, копирует (Inherit, copy) * @see yii\web\DbSession Наследует, копирует (Inherit, copy)
* *
* @package yii2\ArangoDB * @package mirzaev\yii2\sessions\arangodb
* @author Arsen Mirzaev Tatyano-Muradovich <red@hood.su> * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*
* @since 2.0
*/ */
final class ArangoDbSession extends MultiFieldSession final class ArangoDbSession extends MultiFieldSession
{ {
/** /**
* Идентификатор компонента (Component ID) * Идентификатор компонента с базой данных (Component ID)
*/ */
public Connection|array|string $database = 'arangodb'; public Connection|array|string $database = 'arangodb';
@ -141,7 +147,7 @@ final class ArangoDbSession extends MultiFieldSession
return; return;
} }
// parent::regenerateID(false); parent::regenerateID(false);
$newID = session_id(); $newID = session_id();
@ -153,9 +159,9 @@ final class ArangoDbSession extends MultiFieldSession
} }
$row = (new Query()) $row = (new Query())
->in($this->document) ->in($this->document)
->where(['hash' => $oldID]) ->where(['hash' => $oldID])
->one($this->database); ->one($this->database);
if ($row) { if ($row) {
if ($rewrite) { if ($rewrite) {
@ -163,20 +169,28 @@ final class ArangoDbSession extends MultiFieldSession
(new Query()) (new Query())
->in($this->document) ->in($this->document)
->where(['hash' => $newID]) ->where(['hash' => $oldID])
->update(['hash' => $oldID], db: $this->database); ->update($this->genBuffer($newID), db: $this->database);
} else { } else {
// Создать // Создать
// Инициализация
$new = $row;
$new['id'] = $newID;
(new Query()) (new Query())
->in($this->document) ->in($this->document)
->insert(['hash' => $newID], db: $this->database); ->insert($new, db: $this->database);
} }
} else { } else {
// shouldn't reach here normally // shouldn't reach here normally
(new Query()) (new Query())
->in($this->document) ->in($this->document)
->insert($this->composeFields($newID, ''), db: $this->database); ->insert($this->genBuffer($newID), db: $this->database);
// (new Query())
// ->in($this->document)
// ->insert($this->composeFields($newID, ''), db: $this->database); !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
} }
} }
@ -187,11 +201,10 @@ final class ArangoDbSession extends MultiFieldSession
* *
* @return string Данные сессии (The session data) * @return string Данные сессии (The session data)
*/ */
public function readSession($id): string public function readSession($hash): string
// public function readSession(string $id): string // public function readSession(string $hash): string
{ {
$query = $this->getReadQuery($id); $query = $this->getReadQuery($hash);
if ($this->readCallback !== null) { if ($this->readCallback !== null) {
$data = $query->one($this->database); $data = $query->one($this->database);
@ -207,15 +220,22 @@ final class ArangoDbSession extends MultiFieldSession
/** /**
* Найти сессию (Search session) * Найти сессию (Search session)
* *
* @param string $id Идентификатор сессии (Session ID) * @param string $hash Идентификатор сессии (Session ID)
* *
* @return array|null Сессия, если найдена (Session, if founded) * @return array|null Сессия, если найдена (Session, if founded)
*/ */
public function searchSession(string $id): ?array public function searchSession(string $hash): ?array
{ {
if (empty($hash)) {
return false;
}
$session = (new Query()) $session = (new Query())
->in($this->document) ->in($this->document)
->where(['hash' => $id]) ->where([
'hash' => $hash,
'status' => 'active'
])
->one($this->database); ->one($this->database);
return $session ? $session : null; return $session ? $session : null;
@ -224,15 +244,35 @@ final class ArangoDbSession extends MultiFieldSession
/** /**
* Инициализировать сессию (Initialize session) * Инициализировать сессию (Initialize session)
* *
* @param string $id Идентификатор сессии (Session ID) * @param string $hash Идентификатор сессии (Session ID)
* @param string|null $data Данные сессии (Session data)
* *
* @return array Сессия (Session) * @return array Сессия или статус обновления (Session or update status)
*/ */
public function initSession(string $id): array public function initSession(string $hash, string|null $data = null): array|bool|null
{ {
return $this->searchSession($id) ?? (new Query()) if (empty($hash)) {
return null;
}
if ($session = $this->searchSession($hash)) {
if (isset($data, $session['data']) && $session['data'] !== $data) {
// Необходима синхронизация (данные не идентичны)
return (new Query())
->in($this->document)
->where(['hash' => $session['hash']])
->update(['data' => $data], db: $this->database);
}
return $session;
}
$query = (new Query())
->in($this->document) ->in($this->document)
->insert($this->buffer, db: $this->database); ->insert($this->genBuffer($hash, $data), db: $this->database);
return $query ? $query : null;
} }
/** /**
@ -248,6 +288,7 @@ final class ArangoDbSession extends MultiFieldSession
{ {
if ($this->getUseStrictMode() && $id === $this->_forceRegenerateId) { if ($this->getUseStrictMode() && $id === $this->_forceRegenerateId) {
//Ignore write when forceRegenerate is active for this id //Ignore write when forceRegenerate is active for this id
return true; return true;
} }
@ -261,25 +302,20 @@ final class ArangoDbSession extends MultiFieldSession
// ensure data consistency // ensure data consistency
if (isset($this->buffer['data'])) { if (isset($this->buffer['data'])) {
$_SESSION = $this->buffer['data']; $_SESSION = $this->buffer['data'];
} else { } else {
$this->buffer['data'] = $data; $this->buffer['data'] = $data;
} }
$this->buffer = array_merge($this->buffer, [ $this->genBuffer($id, $data);
'hash' => $id,
'from' => time(),
'to' => time() + $this->getTimeout(),
]);
// Конвертация или сериализация, не пойму // Конвертация или сериализация, не пойму
$this->buffer = $this->typecastFields($this->buffer); $this->buffer = $this->typecastFields($this->buffer);
// Инициализация сессии // Инициализация сессии
$this->initSession($id); $this->initSession($id, $data);
// Деинициализация буфера данных сессии
$this->buffer = [];
} catch (Exception $e) { } catch (Exception $e) {
yii::$app->errorHandler->handleException($e); yii::$app->errorHandler->handleException($e);
@ -289,21 +325,45 @@ final class ArangoDbSession extends MultiFieldSession
return true; return true;
} }
/**
* Закрыть сессию (Close session)
*
* @return bool Статус закрытия сессии (Session closing status)
*
* @todo Разобраться почему вызывается destroySession и избавиться от перезаписи (сделать обновление существующей)
*/
public function closeSession(): bool
{
// try {
// $this->buffer['status'] = 'inactive';
// (new Query())
// ->in($this->document)
// ->insert($this->buffer, db: $this->database);
// } catch (Exception $e) {
// yii::$app->errorHandler->handleException($e);
// return false;
// }
return true;
}
/** /**
* Удалить сессию (Delete session) * Удалить сессию (Delete session)
* *
* @param string $id Идентификатор сессии (Session ID) * @param string $hash Идентификатор сессии (Session ID)
* *
* @return bool Статус удаления сессии (Session deleting status) * @return bool Статус удаления сессии (Session deleting status)
*/ */
public function destroySession($id): bool public function destroySession($hash): bool
// public function destroySession(string $id): bool // public function destroySession(string $hash): bool
{ {
return (new Query()) return (new Query())
->in($this->document) ->in($this->document)
->where([ ->where(['hash' => $hash])
'hash' => $id
])
->remove(db: $this->database); ->remove(db: $this->database);
} }
@ -327,20 +387,20 @@ final class ArangoDbSession extends MultiFieldSession
[ [
'to' => time() 'to' => time()
], ],
'operator' => '>=' 'operator' => '<='
] ]
]) ])
->remove(db: $this->database); ->remove(db: $this->database);
} }
/** /**
* Генерация запроса для чтения сеанса (Generating a query to read a session) * Генерация запроса для чтения сессии (Generating a query to read a session)
* *
* @param string $id Идентификатор сессии (Session ID) * @param string $hash Идентификатор сессии (Session ID)
* *
* @return Query Инстанция запроса на чтение (Read query instance) * @return Query Инстанция запроса на чтение (Read query instance)
*/ */
protected function getReadQuery(string $id): Query protected function getReadQuery(string $hash): Query
{ {
return (new Query()) return (new Query())
->in($this->document) ->in($this->document)
@ -349,21 +409,40 @@ final class ArangoDbSession extends MultiFieldSession
[ [
'to' => time() 'to' => time()
], ],
'operator' => '<=' 'operator' => '>='
]
])
->where([
[
'to' => null
]
], 'OR')
->where([
[
'hash' => $id,
], ],
[
[
'hash' => $hash,
],
[
'status' => 'active'
]
]
]); ]);
} }
/**
* Генерация массива данных для записи (Generating an array of data to writing)
*
* @param string $hash Идентификатор сессии (Session ID)
* @param string $data Данные сессии (Session data)
*
* @return array Обработанный буфер (Handled buffer)
*/
protected function genBuffer(string $hash, string|null $data = null): array
{
return $this->buffer = array_merge(
$this->buffer,
$this->composeFields($hash, $data),
[
'from' => time(),
'to' => time() + $this->getTimeout(),
'status' => 'active'
]
);
}
/** /**
* Конвертация для отправки в PDO (Convertation for sending to PDO) * Конвертация для отправки в PDO (Convertation for sending to PDO)
* *

View File

@ -1,7 +1,14 @@
<?php <?php
// Модуль ArangoDB для фреймворка Yii
use mirzaev\yii2\arangodb\Migration; use mirzaev\yii2\arangodb\Migration;
/**
* Создание коллекции для хранения сессий
*
* @package mirzaev\yii2\sessions\arangodb
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
class create_sessions_collection extends Migration class create_sessions_collection extends Migration
{ {
public function up() public function up()

View File

@ -2,11 +2,11 @@
declare(strict_types=1); declare(strict_types=1);
namespace mirzaev\yii2\arangodb\sessions; namespace mirzaev\yii2\sessions\arangodb;
use yii; // Фреймворк Yii
use yii,
use yii\web\Session; yii\web\Session;
/** /**
* Базовый класс для реализации хранилища сессий * Базовый класс для реализации хранилища сессий
@ -15,7 +15,8 @@ use yii\web\Session;
* *
* @property-read bool $useCustomStorage Разрешение использовать своё хранилища (Whether to use custom storage) * @property-read bool $useCustomStorage Разрешение использовать своё хранилища (Whether to use custom storage)
* *
* @author Arsen Mirzaev Tatyano-Muradovich <red@hood.su> * @package mirzaev\yii2\sessions\arangodb
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
* @author Paul Klimov <klimov.paul@gmail.com> * @author Paul Klimov <klimov.paul@gmail.com>
*/ */
abstract class MultiFieldSession extends Session abstract class MultiFieldSession extends Session
@ -82,22 +83,17 @@ abstract class MultiFieldSession extends Session
/** /**
* Composes storage field set for session writing. * Composes storage field set for session writing.
* *
* @param string $id Optional session id * @param string $hash Session id
* @param string $data Optional session data * @param string $data Session data
* *
* @return array storage fields * @return array storage fields
*/ */
protected function composeFields($id = null, $data = null): array protected function composeFields($hash = null, $data = null): array
{ {
$buffer = $this->writeCallback ? call_user_func($this->writeCallback, $this) : []; $buffer = $this->writeCallback ? call_user_func($this->writeCallback, $this) : [];
if ($id !== null) { isset($hash) and $buffer['hash'] = $hash;
$buffer['hash'] = $id; isset($data) and $buffer['data'] = $data;
}
if ($data !== null) {
$buffer['data'] = $data;
}
return $buffer; return $buffer;
} }