Skip to content

Commit

Permalink
Move SessionTrait from atk4/core and separate handler (#1733)
Browse files Browse the repository at this point in the history
  • Loading branch information
mvorisek authored Feb 8, 2022
1 parent 306916d commit 863f697
Show file tree
Hide file tree
Showing 13 changed files with 458 additions and 45 deletions.
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

0 comments on commit 863f697

Please sign in to comment.