Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move SessionTrait from atk4/core and separate handler #1733

Merged
merged 7 commits into from
Feb 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion demos/_includes/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,19 @@

namespace Atk4\Ui\Demos;

use Atk4\Core\AppScopeTrait;
use Atk4\Core\NameTrait;
use Atk4\Core\SessionTrait;
use Atk4\Ui\App;
use Atk4\Ui\SessionTrait;

class Session
{
use AppScopeTrait;
use NameTrait;
use SessionTrait;

public function __construct(App $app)
{
$this->setApp($app);
}
}
2 changes: 1 addition & 1 deletion demos/interactive/modal.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

\Atk4\Ui\Header::addTo($app, ['Modal View']);

$session = new Session();
$session = new Session($app);
// Re-usable component implementing counter

\Atk4\Ui\Header::addTo($app, ['Static Modal Dialog']);
Expand Down
3 changes: 2 additions & 1 deletion demos/interactive/popup.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@

/** @var \Atk4\Ui\Lister $cartClass */
$cartClass = AnonymousClassNameCache::get_class(fn () => new class() extends \Atk4\Ui\Lister {
use \Atk4\Core\SessionTrait;
use \Atk4\Ui\SessionTrait;

public $items = [];

public $defaultTemplate = 'lister.html';
Expand Down
62 changes: 62 additions & 0 deletions docs/session.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
=============
Session Trait
=============

.. php:trait:: SessionTrait


Introduction
============

SessionTrait is a simple way to let object store relevant data in the session. Specifically used in ATK UI
some objects want to memorize data. (see https://github.com/atk4/ui/blob/develop/src/Wizard.php#L12)

You would need 3 things. First make use of session trait::

use \Atk4\Ui\SessionTrait;

next you may memorize any value, which will be stored independently from any other object (even of a same class)::

$this->memorize('dsn', $dsn);

Later when you need the value, you can simply recall it::

$dsn = $this->recall('dsn');


Properties
==========

.. php:attr:: session_key

Internal property to make sure that all session data will be stored in one
"container" (array key).

Methods
=======

.. php:method:: startSession($options = [])

Create new session.

.. php:method:: destroySession()

Destroy existing session.

.. php:method:: memorize($key, $value)

Remember data in object-relevant session data.

.. php:method:: learn($key, $default = null)

Similar to memorize, but if value for key exist, will return it.

.. php:method:: recall($key, $default = null)

Returns session data for this object. If not previously set, then $default
is returned.

.. php:method:: forget($key = null)

Forget session data for arg $key. If $key is omitted will forget all
associated session data.
4 changes: 4 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@ parameters:
-
path: 'src/Panel/Right.php'
message: '~^Call to an undefined method Atk4\\Ui\\JsExpression::addPanel\(\)\.$~'
-
path: 'src/SessionTrait.php'
count: 4
message: '~^Access to an undefined property Atk4\\Ui\\Tests\\SessionAbstractMock::\$name\.$~'
-
path: 'src/Table/Column.php'
message: '~^Call to an undefined method Atk4\\Ui\\AbstractView::setHoverable\(\)\.$~'
Expand Down
1 change: 1 addition & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<groups>
<exclude>
<group>demos_http</group>
<group>require_session</group>
</exclude>
</groups>
<listeners>
Expand Down
38 changes: 8 additions & 30 deletions src/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ class App
/** @var Persistence|Persistence\Sql */
public $db;

/** @var App\Session */
public $session;

/** @var string[] Extra HTTP headers to send on exit. */
protected $response_headers = [
self::HEADER_STATUS_CODE => '200',
Expand Down Expand Up @@ -136,39 +139,11 @@ class App

public $templateClass = HtmlTemplate::class;

/**
* @param array $defaults
*/
public function __construct($defaults = [])
public function __construct(array $defaults = [])
{
$this->setApp($this);

// Process defaults
if (is_string($defaults)) {
$defaults = ['title' => $defaults];
}

if (isset($defaults[0])) {
$defaults['title'] = $defaults[0];
unset($defaults[0]);
}

/*
if (is_array($defaults)) {
throw (new Exception('Constructor requires array argument'))
->addMoreInfo('arg', $defaults);
}*/
$this->setDefaults($defaults);
/*

foreach ($defaults as $key => $val) {
if (is_array($val)) {
$this->{$key} = array_merge(is_array($this->{$key} ?? null) ? $this->{$key} : [], $val);
} elseif ($val !== null) {
$this->{$key} = $val;
}
}
*/

$this->setupTemplateDirs();

Expand Down Expand Up @@ -208,11 +183,14 @@ static function (int $severity, string $msg, string $file, int $line): bool {
$this->setupAlwaysRun();
}

// Set up UI persistence
if ($this->ui_persistence === null) {
$this->ui_persistence = new UiPersistence();
}

if ($this->session === null) {
$this->session = new App\Session();
}

// setting up default executor factory.
$this->executorFactory = Factory::factory([ExecutorFactory::class]);
}
Expand Down
121 changes: 121 additions & 0 deletions src/App/Session.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

declare(strict_types=1);

namespace Atk4\Ui\App;

use Atk4\Ui\Exception;

class Session
{
/** @var string Session container key. */
protected $session_key = '__atk_session';

/**
* Create new session.
*
* @param array $options Options for session_start()
*/
public function startSession(array $options = []): void
{
switch (session_status()) {
case \PHP_SESSION_DISABLED:
// @codeCoverageIgnoreStart - impossible to test
throw new Exception('Sessions are disabled on server');
// @codeCoverageIgnoreEnd
case \PHP_SESSION_NONE:
session_start($options);

break;
}
}

/**
* Destroy existing session.
*/
public function destroySession(): void
{
if (session_status() === \PHP_SESSION_ACTIVE) {
session_destroy();
unset($_SESSION);
}
}

/**
* Remember data in object-relevant session data.
*
* @param mixed $value
*
* @return mixed $value
*/
public function memorize(string $namespace, string $key, $value)
{
$this->startSession();

$_SESSION[$this->session_key][$namespace][$key] = $value;

return $value;
}

/**
* Similar to memorize, but if value for key exist, will return it.
*
* @param mixed $default
*
* @return mixed Previously memorized data or $default
*/
public function learn(string $namespace, string $key, $default = null)
{
$this->startSession();

if (!isset($_SESSION[$this->session_key][$namespace][$key])) {
if ($default instanceof \Closure) {
$default = $default($key);
}

return $this->memorize($namespace, $key, $default);
}

return $this->recall($namespace, $key);
}

/**
* Returns session data for this object. If not previously set, then
* $default is returned.
*
* @param mixed $default
*
* @return mixed Previously memorized data or $default
*/
public function recall(string $namespace, string $key, $default = null)
{
$this->startSession();

if (!isset($_SESSION[$this->session_key][$namespace][$key])) {
if ($default instanceof \Closure) {
$default = $default($key);
}

return $default;
}

return $_SESSION[$this->session_key][$namespace][$key];
}

/**
* Forget session data for $key. If $key is omitted will forget all
* associated session data.
*
* @param string $key Optional key of data to forget
*/
public function forget(string $namespace, string $key = null): void
{
$this->startSession();

if ($key === null) {
unset($_SESSION[$this->session_key][$namespace]);
} else {
unset($_SESSION[$this->session_key][$namespace][$key]);
}
}
}
72 changes: 72 additions & 0 deletions src/SessionTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

declare(strict_types=1);

namespace Atk4\Ui;

use Atk4\Core\TraitUtil;

trait SessionTrait
{
private function getSession(): App\Session
{
// all methods use this method, so we better check NameTrait existence here in one place
if (!TraitUtil::hasNameTrait($this)) {
throw new Exception('Object should have NameTrait applied to use session');
}

return $this->getApp()->session;
}

/**
* Remember data in object-relevant session data.
*
* @param mixed $value
*
* @return mixed $value
*/
public function memorize(string $key, $value)
{
return $this->getSession()->memorize($this->name, $key, $value);
}

/**
* Similar to memorize, but if value for key exist, will return it.
*
* @param mixed $default
*
* @return mixed Previously memorized data or $default
*/
public function learn(string $key, $default = null)
{
return $this->getSession()->learn($this->name, $key, $default);
}

/**
* Returns session data for this object. If not previously set, then
* $default is returned.
*
* @param mixed $default
*
* @return mixed Previously memorized data or $default
*/
public function recall(string $key, $default = null)
{
return $this->getSession()->recall($this->name, $key, $default);
}

/**
* Forget session data for $key. If $key is omitted will forget all
* associated session data.
*
* @param string $key Optional key of data to forget
*
* @return $this
*/
public function forget(string $key = null)
{
$this->getSession()->forget($this->name, $key);

return $this;
}
}
Loading