Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Cache: Added session storage adapter

  • Loading branch information...
commit b4844a1017fc995b2f99e309c54fbbccdafc9db1 1 parent 8943900
@marc-mabe authored
View
548 library/Zend/Cache/Storage/Adapter/Session.php
@@ -0,0 +1,548 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_Cache
+ */
+
+namespace Zend\Cache\Storage\Adapter;
+
+use stdClass;
+use Zend\Cache\Exception;
+use Zend\Cache\Storage\Capabilities;
+use Zend\Cache\Storage\ClearByPrefixInterface;
+use Zend\Cache\Storage\FlushableInterface;
+use Zend\Cache\Storage\IterableInterface;
+use Zend\Session\Container as SessionContainer;
+
+/**
+ * @category Zend
+ * @package Zend_Cache
+ * @subpackage Storage
+ */
+class Session extends AbstractAdapter implements
+ ClearByPrefixInterface,
+ FlushableInterface,
+ IterableInterface
+{
+
+ /**
+ * Set options.
+ *
+ * @param array|\Traversable|SessionOptions $options
+ * @return Memory
+ * @see getOptions()
+ */
+ public function setOptions($options)
+ {
+ if (!$options instanceof SessionOptions) {
+ $options = new SessionOptions($options);
+ }
+
+ return parent::setOptions($options);
+ }
+
+ /**
+ * Get options.
+ *
+ * @return SessionOptions
+ * @see setOptions()
+ */
+ public function getOptions()
+ {
+ if (!$this->options) {
+ $this->setOptions(new SessionOptions());
+ }
+ return $this->options;
+ }
+
+ /**
+ * Get the session container
+ *
+ * @return SessionContainer
+ */
+ protected function getSessionContainer()
+ {
+ $sessionContainer = $this->getOptions()->getSessionContainer();
+ if (!$sessionContainer) {
+ throw new Exception\RuntimeException("No session container configured");
+ }
+ return $sessionContainer;
+ }
+
+ /* IterableInterface */
+
+ /**
+ * Get the storage iterator
+ *
+ * @return KeyListIterator
+ */
+ public function getIterator()
+ {
+ $cntr = $this->getSessionContainer();
+ $ns = $this->getOptions()->getNamespace();
+
+ if ($cntr->offsetExists($ns)) {
+ $keys = array_keys($cntr->offsetGet($ns));
+ } else {
+ $keys = array();
+ }
+
+ return new KeyListIterator($this, $keys);
+ }
+
+ /* FlushableInterface */
+
+ /**
+ * Flush the whole session container
+ *
+ * @return boolean
+ */
+ public function flush()
+ {
+ $this->getSessionContainer()->exchangeArray(array());
+ return true;
+ }
+
+ /* ClearByPrefixInterface */
+
+ /**
+ * Remove items matching given prefix
+ *
+ * @param string $prefix
+ * @return boolean
+ */
+ public function clearByPrefix($prefix)
+ {
+ $cntr = $this->getSessionContainer();
+ $ns = $this->getOptions()->getNamespace();
+
+ if (!$cntr->offsetExists($ns)) {
+ return true;
+ }
+
+ $data = $cntr->offsetGet($ns);
+ $prefixL = strlen($prefix);
+ foreach ($data as $key => & $item) {
+ if (substr($key, 0, $prefixL) === $prefix) {
+ unset($data[$key]);
+ }
+ }
+ $cntr->offsetSet($ns, $data);
+
+ return true;
+ }
+
+ /* reading */
+
+ /**
+ * Internal method to get an item.
+ *
+ * @param string $normalizedKey
+ * @param boolean $success
+ * @param mixed $casToken
+ * @return mixed Data on success, null on failure
+ * @throws Exception\ExceptionInterface
+ */
+ protected function internalGetItem(& $normalizedKey, & $success = null, & $casToken = null)
+ {
+ $cntr = $this->getSessionContainer();
+ $ns = $this->getOptions()->getNamespace();
+
+ if (!$cntr->offsetExists($ns)) {
+ $success = false;
+ return null;
+ }
+
+ $data = $cntr->offsetGet($ns);
+ $success = array_key_exists($normalizedKey, $data);
+ if (!$success) {
+ return null;
+ }
+
+ $casToken = $value = $data[$normalizedKey];
+ return $value;
+ }
+
+ /**
+ * Internal method to get multiple items.
+ *
+ * @param array $normalizedKeys
+ * @return array Associative array of keys and values
+ * @throws Exception\ExceptionInterface
+ */
+ protected function internalGetItems(array & $normalizedKeys)
+ {
+ $cntr = $this->getSessionContainer();
+ $ns = $this->getOptions()->getNamespace();
+
+ if (!$cntr->offsetExists($ns)) {
+ return array();
+ }
+
+ $data = $cntr->offsetGet($ns);
+ $result = array();
+ foreach ($normalizedKeys as $normalizedKey) {
+ if (array_key_exists($normalizedKey, $data)) {
+ $result[$normalizedKey] = $data[$normalizedKey];
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Internal method to test if an item exists.
+ *
+ * @param string $normalizedKey
+ * @return boolean
+ */
+ protected function internalHasItem(& $normalizedKey)
+ {
+ $cntr = $this->getSessionContainer();
+ $ns = $this->getOptions()->getNamespace();
+
+ if (!$cntr->offsetExists($ns)) {
+ return false;
+ }
+
+ $data = $cntr->offsetGet($ns);
+ return array_key_exists($normalizedKey, $data);
+ }
+
+ /**
+ * Internal method to test multiple items.
+ *
+ * @param array $normalizedKeys
+ * @return array Array of found keys
+ */
+ protected function internalHasItems(array & $normalizedKeys)
+ {
+ $cntr = $this->getSessionContainer();
+ $ns = $this->getOptions()->getNamespace();
+
+ if (!$cntr->offsetExists($ns)) {
+ return array();
+ }
+
+ $data = $cntr->offsetGet($ns);
+ $result = array();
+ foreach ($normalizedKeys as $normalizedKey) {
+ if (array_key_exists($normalizedKey, $data)) {
+ $result[] = $normalizedKey;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Get metadata of an item.
+ *
+ * @param string $normalizedKey
+ * @return array|boolean Metadata on success, false on failure
+ * @throws Exception\ExceptionInterface
+ *
+ * @triggers getMetadata.pre(PreEvent)
+ * @triggers getMetadata.post(PostEvent)
+ * @triggers getMetadata.exception(ExceptionEvent)
+ */
+ protected function internalGetMetadata(& $normalizedKey)
+ {
+ return $this->internalHasItem($normalizedKey) ? array() : false;
+ }
+
+ /* writing */
+
+ /**
+ * Internal method to store an item.
+ *
+ * @param string $normalizedKey
+ * @param mixed $value
+ * @return boolean
+ * @throws Exception\ExceptionInterface
+ */
+ protected function internalSetItem(& $normalizedKey, & $value)
+ {
+ $cntr = $this->getSessionContainer();
+ $ns = $this->getOptions()->getNamespace();
+ $data = $cntr->offsetExists($ns) ? $cntr->offsetGet($ns) : array();
+ $data[$normalizedKey] = $value;
+ $cntr->offsetSet($ns, $data);
+ return true;
+ }
+
+ /**
+ * Internal method to store multiple items.
+ *
+ * @param array $normalizedKeyValuePairs
+ * @return array Array of not stored keys
+ * @throws Exception\ExceptionInterface
+ */
+ protected function internalSetItems(array & $normalizedKeyValuePairs)
+ {
+ $cntr = $this->getSessionContainer();
+ $ns = $this->getOptions()->getNamespace();
+
+ if ($cntr->offsetExists($ns)) {
+ $data = array_merge($cntr->offsetGet($ns), $normalizedKeyValuePairs);
+ } else {
+ $data = $normalizedKeyValuePairs;
+ }
+ $cntr->offsetSet($ns, $data);
+
+ return array();
+ }
+
+ /**
+ * Add an item.
+ *
+ * @param string $normalizedKey
+ * @param mixed $value
+ * @return boolean
+ * @throws Exception\ExceptionInterface
+ */
+ protected function internalAddItem(& $normalizedKey, & $value)
+ {
+ $cntr = $this->getSessionContainer();
+ $ns = $this->getOptions()->getNamespace();
+
+ if ($cntr->offsetExists($ns)) {
+ $data = $cntr->offsetGet($ns);
+
+ if (array_key_exists($normalizedKey, $data)) {
+ return false;
+ }
+
+ $data[$normalizedKey] = $value;
+ } else {
+ $data = array($normalizedKey => $value);
+ }
+
+ $cntr->offsetSet($ns, $data);
+ return true;
+ }
+
+ /**
+ * Internal method to add multiple items.
+ *
+ * @param array $normalizedKeyValuePairs
+ * @return array Array of not stored keys
+ * @throws Exception\ExceptionInterface
+ */
+ protected function internalAddItems(array & $normalizedKeyValuePairs)
+ {
+ $cntr = $this->getSessionContainer();
+ $ns = $this->getOptions()->getNamespace();
+
+ $result = array();
+ if ($cntr->offsetExists($ns)) {
+ $data = $cntr->offsetGet($ns);
+
+ foreach ($normalizedKeyValuePairs as $normalizedKey => $value) {
+ if (array_key_exists($normalizedKey, $data)) {
+ $result[] = $normalizedKey;
+ } else {
+ $data[$normalizedKey] = $value;
+ }
+ }
+ } else {
+ $data = $normalizedKeyValuePairs;
+ }
+
+ $cntr->offsetSet($ns, $data);
+ return $result;
+ }
+
+ /**
+ * Internal method to replace an existing item.
+ *
+ * @param string $normalizedKey
+ * @param mixed $value
+ * @return boolean
+ * @throws Exception\ExceptionInterface
+ */
+ protected function internalReplaceItem(& $normalizedKey, & $value)
+ {
+ $cntr = $this->getSessionContainer();
+ $ns = $this->getOptions()->getNamespace();
+
+ if (!$cntr->offsetExists($ns)) {
+ return false;
+ }
+
+ $data = $cntr->offsetGet($ns);
+ if (!array_key_exists($normalizedKey, $data)) {
+ return false;
+ }
+ $data[$normalizedKey] = $value;
+ $cntr->offsetSet($ns, $data);
+
+ return true;
+ }
+
+ /**
+ * Internal method to replace multiple existing items.
+ *
+ * @param array $normalizedKeyValuePairs
+ * @return array Array of not stored keys
+ * @throws Exception\ExceptionInterface
+ */
+ protected function internalReplaceItems(array & $normalizedKeyValuePairs)
+ {
+ $cntr = $this->getSessionContainer();
+ $ns = $this->getOptions()->getNamespace();
+ if (!$cntr->offsetExists($ns)) {
+ return array_keys($normalizedKeyValuePairs);
+ }
+
+ $data = $cntr->offsetGet($ns);
+ $result = array();
+ foreach ($normalizedKeyValuePairs as $normalizedKey => $value) {
+ if (!array_key_exists($normalizedKey, $data)) {
+ $result[] = $normalizedKey;
+ } else {
+ $data[$normalizedKey] = $value;
+ }
+ }
+ $cntr->offsetSet($ns, $data);
+
+ return $result;
+ }
+
+ /**
+ * Internal method to remove an item.
+ *
+ * @param string $normalizedKey
+ * @return boolean
+ * @throws Exception\ExceptionInterface
+ */
+ protected function internalRemoveItem(& $normalizedKey)
+ {
+ $cntr = $this->getSessionContainer();
+ $ns = $this->getOptions()->getNamespace();
+
+ if (!$cntr->offsetExists($ns)) {
+ return false;
+ }
+
+ $data = $cntr->offsetGet($ns);
+ if (!array_key_exists($normalizedKey, $data)) {
+ return false;
+ }
+
+ unset($data[$normalizedKey]);
+
+ if (!$data) {
+ $cntr->offsetUnset($ns);
+ } else {
+ $cntr->offsetSet($ns, $data);
+ }
+
+ return true;
+ }
+
+ /**
+ * Internal method to increment an item.
+ *
+ * @param string $normalizedKey
+ * @param int $value
+ * @return int|boolean The new value on success, false on failure
+ * @throws Exception\ExceptionInterface
+ */
+ protected function internalIncrementItem(& $normalizedKey, & $value)
+ {
+ $cntr = $this->getSessionContainer();
+ $ns = $this->getOptions()->getNamespace();
+
+ if ($cntr->offsetExists($ns)) {
+ $data = $cntr->offsetGet($ns);
+ } else {
+ $data = array();
+ }
+
+ if (array_key_exists($normalizedKey, $data)) {
+ $data[$normalizedKey]+= $value;
+ $newValue = $data[$normalizedKey];
+ } else {
+ // initial value
+ $newValue = $value;
+ $data[$normalizedKey] = $newValue;
+ }
+
+ $cntr->offsetSet($ns, $data);
+ return $newValue;
+ }
+
+ /**
+ * Internal method to decrement an item.
+ *
+ * @param string $normalizedKey
+ * @param int $value
+ * @return int|boolean The new value on success, false on failure
+ * @throws Exception\ExceptionInterface
+ */
+ protected function internalDecrementItem(& $normalizedKey, & $value)
+ {
+ $cntr = $this->getSessionContainer();
+ $ns = $this->getOptions()->getNamespace();
+
+ if ($cntr->offsetExists($ns)) {
+ $data = $cntr->offsetGet($ns);
+ } else {
+ $data = array();
+ }
+
+ if (array_key_exists($normalizedKey, $data)) {
+ $data[$normalizedKey]-= $value;
+ $newValue = $data[$normalizedKey];
+ } else {
+ // initial value
+ $newValue = -$value;
+ $data[$normalizedKey] = $newValue;
+ }
+
+ $cntr->offsetSet($ns, $data);
+ return $newValue;
+ }
+
+ /* status */
+
+ /**
+ * Internal method to get capabilities of this adapter
+ *
+ * @return Capabilities
+ */
+ protected function internalGetCapabilities()
+ {
+ if ($this->capabilities === null) {
+ $this->capabilityMarker = new stdClass();
+ $this->capabilities = new Capabilities(
+ $this,
+ $this->capabilityMarker,
+ array(
+ 'supportedDatatypes' => array(
+ 'NULL' => true,
+ 'boolean' => true,
+ 'integer' => true,
+ 'double' => true,
+ 'string' => true,
+ 'array' => 'array',
+ 'object' => 'object',
+ 'resource' => false,
+ ),
+ 'supportedMetadata' => array(),
+ 'minTtl' => 0,
+ 'maxKeyLength' => 0,
+ 'namespaceIsPrefix' => false,
+ 'namespaceSeparator' => '',
+ )
+ );
+ }
+
+ return $this->capabilities;
+ }
+}
View
57 library/Zend/Cache/Storage/Adapter/SessionOptions.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_Cache
+ */
+
+namespace Zend\Cache\Storage\Adapter;
+
+use Zend\Cache\Exception;
+use Zend\Session\Container as SessionContainer;
+
+/**
+ * These are options specific to the APC adapter
+ *
+ * @category Zend
+ * @package Zend_Cache
+ * @subpackage Storage
+ */
+class SessionOptions extends AdapterOptions
+{
+ /**
+ * The session container
+ *
+ * @var null|SessionContainer
+ */
+ protected $sessionContainer = null;
+
+ /**
+ * Set the session container
+ *
+ * @param null|SessionContainer $memoryLimit
+ * @return SessionOptions
+ */
+ public function setSessionContainer(SessionContainer $sessionContainer = null)
+ {
+ if ($this->sessionContainer != $sessionContainer) {
+ $this->triggerOptionEvent('session_container', $sessionContainer);
+ $this->sessionContainer = $sessionContainer;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the session container
+ *
+ * @return null|SessionContainer
+ */
+ public function getSessionContainer()
+ {
+ return $this->sessionContainer;
+ }
+}
View
1  library/Zend/Cache/Storage/AdapterPluginManager.php
@@ -37,6 +37,7 @@ class AdapterPluginManager extends AbstractPluginManager
'filesystem' => 'Zend\Cache\Storage\Adapter\Filesystem',
'memcached' => 'Zend\Cache\Storage\Adapter\Memcached',
'memory' => 'Zend\Cache\Storage\Adapter\Memory',
+ 'session' => 'Zend\Cache\Storage\Adapter\Session',
'xcache' => 'Zend\Cache\Storage\Adapter\XCache',
'wincache' => 'Zend\Cache\Storage\Adapter\WinCache',
'zendserverdisk' => 'Zend\Cache\Storage\Adapter\ZendServerDisk',
View
1  library/Zend/Cache/composer.json
@@ -23,6 +23,7 @@
},
"suggest": {
"zendframework/zend-serializer": "Zend\\Serializer component",
+ "zendframework/zend-session": "Zend\\Session component",
"ext-apc": "APC >= 3.1.6 to use the APC storage adapter",
"ext-dba": "DBA, to use the DBA storage adapter",
"ext-memcached": "Memcached >= 1.0.0 to use the Memcached storage adapter",
View
49 tests/ZendTest/Cache/Storage/Adapter/SessionTest.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_Cache
+ */
+
+namespace ZendTest\Cache\Storage\Adapter;
+
+use Zend\Cache;
+use Zend\Session\Container as SessionContainer;
+use Zend\Session\Config\StandardConfig as SessionConfig;
+use ZendTest\Session\TestAsset\TestManager as TestSessionManager;
+
+/**
+ * @category Zend
+ * @package Zend_Cache
+ * @subpackage UnitTests
+ * @group Zend_Cache
+ */
+class SessionTest extends CommonAdapterTest
+{
+
+ public function setUp()
+ {
+ $_SESSION = array();
+ SessionContainer::setDefaultManager(null);
+ $sessionConfig = new SessionConfig(array('storage' => 'Zend\Session\Storage\ArrayStorage'));
+ $sessionManager = $manager = new TestSessionManager($sessionConfig);
+ $sessionContainer = new SessionContainer('Default', $manager);
+
+ $this->_options = new Cache\Storage\Adapter\SessionOptions(array(
+ 'session_container' => $sessionContainer
+ ));
+ $this->_storage = new Cache\Storage\Adapter\Session();
+ $this->_storage->setOptions($this->_options);
+
+ parent::setUp();
+ }
+
+ public function tearDown()
+ {
+ $_SESSION = array();
+ SessionContainer::setDefaultManager(null);
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.