From cf778d46092d12d880b643de773fd19dd491d4e7 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 23 Jan 2014 14:40:59 +0100 Subject: [PATCH] Implement session namespaces refs #5510 --- library/Icinga/Session/PhpSession.php | 27 ++++- library/Icinga/Session/Session.php | 100 +++--------------- library/Icinga/Session/SessionNamespace.php | 97 +++++++++++++++++ library/Icinga/Web/Session.php | 19 ++++ .../Icinga/Authentication/SessionMock.php | 1 + .../PhpSessionTest.php | 19 ++++ 6 files changed, 175 insertions(+), 88 deletions(-) create mode 100644 library/Icinga/Session/SessionNamespace.php rename test/php/library/Icinga/{Authentication => Session}/PhpSessionTest.php (82%) diff --git a/library/Icinga/Session/PhpSession.php b/library/Icinga/Session/PhpSession.php index c6492f0c5..d3b08bd14 100644 --- a/library/Icinga/Session/PhpSession.php +++ b/library/Icinga/Session/PhpSession.php @@ -32,11 +32,19 @@ namespace Icinga\Session; use Icinga\Application\Logger; use \Icinga\Exception\ConfigurationError; + /** * Session implementation in PHP */ class PhpSession extends Session { + /** + * The namespace prefix + * + * Used to differentiate between standard session keys and namespace identifiers + */ + const NAMESPACE_PREFIX = 'ns.'; + /** * Name of the session * @@ -111,7 +119,17 @@ class PhpSession extends Session public function read() { $this->open(); - $this->setAll($_SESSION); + + foreach ($_SESSION as $key => $value) { + if (strpos($key, self::NAMESPACE_PREFIX) === 0) { + $namespace = new SessionNamespace(); + $namespace->setAll($value); + $this->namespaces[substr($key, strlen(self::NAMESPACE_PREFIX))] = $namespace; + } else { + $this->set($key, $value); + } + } + session_write_close(); } @@ -121,9 +139,14 @@ class PhpSession extends Session public function write() { $this->open(); - foreach ($this->getAll() as $key => $value) { + + foreach ($this->values as $key => $value) { $_SESSION[$key] = $value; } + foreach ($this->namespaces as $identifier => $namespace) { + $_SESSION[self::NAMESPACE_PREFIX . $identifier] = $namespace->getAll(); + } + session_write_close(); } diff --git a/library/Icinga/Session/Session.php b/library/Icinga/Session/Session.php index 3f96e5bd4..44e490571 100644 --- a/library/Icinga/Session/Session.php +++ b/library/Icinga/Session/Session.php @@ -29,17 +29,18 @@ namespace Icinga\Session; + /** * Base class for handling sessions */ -abstract class Session +abstract class Session extends SessionNamespace { /** - * Container for session values + * Container for session namespaces * * @var array */ - private $sessionValues = array(); + protected $namespaces = array(); /** * Read all values from the underlying session implementation @@ -57,100 +58,27 @@ abstract class Session abstract public function purge(); /** - * Setter for session values + * Get or create a new session namespace * - * Values need to be manually persisted with method write. + * @param string $identifier The namespace's identifier * - * @param string $key Name of value - * @param mixed $value Value to set - * @param string $namespace Namespace to use - * - * @return Session - * @see self::write + * @return SessionNamespace */ - public function set($key, $value, $namespace = null) + public function getNamespace($identifier) { - if ($namespace !== null) { - if (!isset($this->sessionValues[$namespace])) { - $this->sessionValues[$namespace] = array(); - } - $this->sessionValues[$namespace][$key] = $value; - } else { - $this->sessionValues[$key] = $value; + if (!isset($this->namespaces[$identifier])) { + $this->namespaces[$identifier] = new SessionNamespace(); } - return $this; + return $this->namespaces[$identifier]; } /** - * Getter for session values - * - * Values are available after populating the session with method read. - * - * @param string $key Name of the value to return - * @param mixed $defaultValue Default value to return - * @param string $namespace Namespace to use - * - * @return mixed - * @see self::read - */ - public function get($key, $defaultValue = null, $namespace = null) - { - if ($namespace !== null) { - if (isset($this->sessionValues[$namespace]) && isset($this->sessionValues[$namespace][$key])) { - return $this->sessionValues[$namespace][$key]; - } - return $defaultValue; - } - - return isset($this->sessionValues[$key]) ? $this->sessionValues[$key] : $defaultValue; - } - - /** - * Getter for all session values - * - * Values are available after populating the session with method read. - * - * @return array - */ - public function getAll() - { - return $this->sessionValues; - } - - /** - * Put an array into the session - * - * @param array $values Values to set - * @param bool $overwrite Overwrite existing values - * @param strign $namespace Namespace to use - */ - public function setAll(array $values, $overwrite = false, $namespace = null) - { - if ($namespace !== null && !isset($this->sessionValues[$namespace])) { - $this->sessionValues[$namespace] = array(); - } - - foreach ($values as $key => $value) { - if ($namespace !== null) { - if (isset($this->sessionValues[$namespace][$key]) && !overwrite) { - continue; - } - $this->sessionValues[$namespace][$key] = $value; - } else { - if (isset($this->sessionValues[$key]) && !$overwrite) { - continue; - } - $this->sessionValues[$key] = $value; - } - } - } - - /** - * Clear all values from the session cache + * Clear all values and namespaces from the session cache */ public function clear() { - $this->sessionValues = array(); + $this->values = array(); + $this->namespaces = array(); } } diff --git a/library/Icinga/Session/SessionNamespace.php b/library/Icinga/Session/SessionNamespace.php new file mode 100644 index 000000000..1485efb78 --- /dev/null +++ b/library/Icinga/Session/SessionNamespace.php @@ -0,0 +1,97 @@ + + * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2 + * @author Icinga Development Team + * + */ +// {{{ICINGA_LICENSE_HEADER}}} + +namespace Icinga\Session; + + +/** + * Container for session values + */ +class SessionNamespace +{ + /** + * The actual values stored in this container + * + * @var array + */ + protected $values = array(); + + /** + * Setter for session values + * + * @param string $key Name of value + * @param mixed $value Value to set + * + * @return self + */ + public function set($key, $value) + { + $this->values[$key] = $value; + return $this; + } + + /** + * Getter for session values + * + * @param string $key Name of the value to return + * @param mixed $default Default value to return + * + * @return mixed + */ + public function get($key, $default = null) + { + return isset($this->values[$key]) ? $this->values[$key] : $default; + } + + /** + * Getter for all session values + * + * @return array + */ + public function getAll() + { + return $this->values; + } + + /** + * Put an array into the session + * + * @param array $values Values to set + * @param bool $overwrite Overwrite existing values + */ + public function setAll(array $values, $overwrite = false) + { + foreach ($values as $key => $value) { + if (isset($this->values[$key]) && !$overwrite) { + continue; + } + $this->values[$key] = $value; + } + } +} diff --git a/library/Icinga/Web/Session.php b/library/Icinga/Web/Session.php index b441f24d8..1101e90d2 100644 --- a/library/Icinga/Web/Session.php +++ b/library/Icinga/Web/Session.php @@ -30,6 +30,7 @@ namespace Icinga\Web; use Icinga\Session\PhpSession; +use Icinga\Session\SessionNamespace; use Icinga\Session\Session as BaseSession; use Icinga\Exception\ProgrammingError; @@ -68,6 +69,7 @@ class Session * Return the current session * * @return BaseSession + * @throws ProgrammingError */ public static function getSession() { @@ -77,4 +79,21 @@ class Session return self::$session; } + + /** + * Get or create a new session namespace + * + * @param string $identifier The namespace's identifier + * + * @return SessionNamespace + * @throws ProgrammingError + */ + public static function getNamespace($identifier) + { + if (self::$session === null) { + throw new ProgrammingError('No session created yet'); + } + + return self::$session->getNamespace($identifier); + } } diff --git a/test/php/library/Icinga/Authentication/SessionMock.php b/test/php/library/Icinga/Authentication/SessionMock.php index b63e80025..5a3856bb9 100644 --- a/test/php/library/Icinga/Authentication/SessionMock.php +++ b/test/php/library/Icinga/Authentication/SessionMock.php @@ -29,6 +29,7 @@ namespace Tests\Icinga\Authentication; +require_once("../../library/Icinga/Session/SessionNamespace.php"); require_once("../../library/Icinga/Session/Session.php"); use Icinga\Session\Session; diff --git a/test/php/library/Icinga/Authentication/PhpSessionTest.php b/test/php/library/Icinga/Session/PhpSessionTest.php similarity index 82% rename from test/php/library/Icinga/Authentication/PhpSessionTest.php rename to test/php/library/Icinga/Session/PhpSessionTest.php index 9a9c9f721..4aefdf887 100644 --- a/test/php/library/Icinga/Authentication/PhpSessionTest.php +++ b/test/php/library/Icinga/Session/PhpSessionTest.php @@ -99,4 +99,23 @@ class PhpSessionTest extends BaseTestCase $session->read(); $this->assertEquals(null, $session->get('key2')); } + + /** + * Test whether session namespaces are properly written and loaded + * + * @runInSeparateProcess + */ + public function testNamespaceReadWrite() + { + $session = $this->getSession(); + $namespace = $session->getNamespace('test'); + $namespace->set('some_key', 'some_val'); + $namespace->set('an_array', array(1, 2, 3)); + $session->write(); + $session->clear(); + $session->read(); + $namespace = $session->getNamespace('test'); + $this->assertEquals($namespace->get('some_key'), 'some_val'); + $this->assertEquals($namespace->get('an_array'), array(1, 2, 3)); + } }