From bb30a447c5c067d6b2b59cc31452bf1ce403d319 Mon Sep 17 00:00:00 2001 From: Drak Date: Sat, 3 Mar 2012 08:28:48 +0545 Subject: [PATCH 01/18] [HttpFoundation] Prepare to split out session handler callback from session storage. --- .../Storage/Handler/NativeSessionHandler.php | 24 +++++ .../Session/Storage/Proxy/AbstractProxy.php | 80 ++++++++++++++++ .../Session/Storage/Proxy/NativeProxy.php | 45 +++++++++ .../Storage/Proxy/SessionHandlerProxy.php | 93 +++++++++++++++++++ 4 files changed, 242 insertions(+) create mode 100644 src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeSessionHandler.php create mode 100644 src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php create mode 100644 src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/NativeProxy.php create mode 100644 src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeSessionHandler.php new file mode 100644 index 0000000000000..a5338d2da2c01 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeSessionHandler.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; + +/** + * Adds SessionHandler functionality if available. + * + * @see http://php.net/sessionhandler + */ + +if (version_compare(phpversion(), '5.4.0', '>=')) { + class NativeSessionHandler extends \SessionHandler {} +} else { + class NativeSessionHandler {} +} \ No newline at end of file diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php new file mode 100644 index 0000000000000..41cd49cb1eaf8 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy; + +/** + * AbstractProxy. + */ +abstract class AbstractProxy +{ + /** + * Flag if handler wraps an internal PHP session handler (using \SessionHandler). + * + * @var boolean + */ + protected $wrapper = false; + + /** + * @var boolean + */ + protected $active = false; + + /** + * @var string + */ + protected $saveHandlerName; + + /** + * Gets the session.save_handler name. + * + * @return string + */ + public function getSaveHandlerName() + { + return $this->saveHandlerName; + } + + public function isSessionHandlerInterface() + { + return (bool)($this instanceof \SessionHandlerInterface); + } + + /** + * Returns true if this handler wraps an internal PHP session save handler using \SessionHandler. + * + * @return bool + */ + public function isWrapper() + { + return $this->wrapper; + } + + /** + * Has a session started? + * + * @return bool + */ + public function isActive() + { + return $this->active; + } + + /** + * Sets the active flag. + * + * @param bool $flag + */ + public function setActive($flag) + { + $this->active = (bool)$flag; + } +} diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/NativeProxy.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/NativeProxy.php new file mode 100644 index 0000000000000..952c7105cdf68 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/NativeProxy.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy; + +/** + * NativeProxy. + * + * This proxy is built-in session handlers in PHP 5.3.x + */ +class NativeProxy extends AbstractProxy +{ + /** + * Constructor. + * + * @param $handler + */ + public function __construct($handler) + { + if (version_compare(phpversion(), '5.4.0', '>=') && $handler instanceof \SessionHandlerInterface) { + throw new \InvalidArgumentException('This proxy is only for PHP 5.3 and not for instances of \SessionHandler or \SessionHandlerInterface'); + } + + $this->handler = $handler; + $this->saveHandlerName = ini_get('session.save_handler'); + } + + /** + * Returns true if this handler wraps an internal PHP session save handler using \SessionHandler. + * + * @return bool False. + */ + public function isWrapper() + { + return false; + } +} diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php new file mode 100644 index 0000000000000..93a1010a73b96 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy; + +/** + * SessionHandler proxy. + */ +class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterface +{ + /** + * @var \SessionHandlerInterface + */ + protected $handler; + + /** + * Constructor. + * + * @param \SessionHandlerInterface $handler + */ + public function __construct(\SessionHandlerInterface $handler) + { + $this->handler = $handler; + $this->wrapper = (bool)(class_exists('SessionHandler') && $handler instanceof \SessionHandler); + $this->saveHandlerName = $this->wrapper ? ini_get('session.save_handler') : 'user'; + } + + // \SessionHandlerInterface + + /** + * {@inheritdoc} + */ + function open($savePath, $sessionName) + { + $return = (bool)$this->handler->open($savePath, $sessionName); + + if (true === $return) { + $this->active = true; + } + + return $return; + } + + /** + * {@inheritdoc} + */ + function close() + { + $this->active = false; + + return (bool)$this->handler->close(); + } + + /** + * {@inheritdoc} + */ + function read($id) + { + return (string)$this->handler->read($id); + } + + /** + * {@inheritdoc} + */ + function write($id, $data) + { + return (bool)$this->handler->write($id, $data); + } + + /** + * {@inheritdoc} + */ + function destroy($id) + { + return (bool)$this->handler->destroy($id); + } + + /** + * {@inheritdoc} + */ + function gc($maxlifetime) + { + return (bool)$this->handler->gc($maxlifetime); + } +} From 23267077ff3c9f85e21bf972b7e84d0bfa91357b Mon Sep 17 00:00:00 2001 From: Drak Date: Sat, 3 Mar 2012 08:39:20 +0545 Subject: [PATCH 02/18] [HttpFoundation] Split session handler callbacks to separate object. --- .../PdoSessionHandler.php} | 6 +- .../Storage/MockArraySessionStorage.php | 14 ++- .../Storage/MockFileSessionStorage.php | 2 +- ...tSessionStorage.php => SessionStorage.php} | 99 ++++++++++++------- 4 files changed, 77 insertions(+), 44 deletions(-) rename src/Symfony/Component/HttpFoundation/Session/Storage/{PdoSessionStorage.php => Handler/PdoSessionHandler.php} (97%) rename src/Symfony/Component/HttpFoundation/Session/Storage/{AbstractSessionStorage.php => SessionStorage.php} (75%) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/PdoSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php similarity index 97% rename from src/Symfony/Component/HttpFoundation/Session/Storage/PdoSessionStorage.php rename to src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php index 6465231912e9a..8175090da0b32 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/PdoSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\HttpFoundation\Session\Storage; +namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; /** * PdoSessionStorage. @@ -17,7 +17,7 @@ * @author Fabien Potencier * @author Michael Williams */ -class PdoSessionStorage extends AbstractSessionStorage implements \SessionHandlerInterface +class PdoSessionHandler implements \SessionHandlerInterface { /** * PDO instance. @@ -58,8 +58,6 @@ public function __construct(\PDO $pdo, array $dbOptions = array(), array $option 'db_data_col' => 'sess_data', 'db_time_col' => 'sess_time', ), $dbOptions); - - parent::__construct($options); } /** diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php index 2447418c84393..077fa0f14ef06 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php @@ -11,6 +11,8 @@ namespace Symfony\Component\HttpFoundation\Session\Storage; +use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler; + /** * MockArraySessionStorage mocks the session for unit tests. * @@ -23,7 +25,7 @@ * @author Bulat Shakirzyanov * @author Drak */ -class MockArraySessionStorage extends AbstractSessionStorage +class MockArraySessionStorage extends SessionStorage { /** * @var string @@ -35,6 +37,16 @@ class MockArraySessionStorage extends AbstractSessionStorage */ protected $sessionData = array(); + public function __construct(array $options = array()) + { + parent::__construct($options, new NullSessionHandler()); + } + + /** + * Sets the session data. + * + * @param array $array + */ public function setSessionData(array $array) { $this->sessionData = $array; diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php index c7c74ddd998ba..184f76e747cff 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php @@ -33,7 +33,7 @@ class MockFileSessionStorage extends MockArraySessionStorage * @param string $savePath Path of directory to save session files. * @param array $options Session options. * - * @see AbstractSessionStorage::__construct() + * @see SessionStorage::__construct() */ public function __construct($savePath = null, array $options = array()) { diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/AbstractSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php similarity index 75% rename from src/Symfony/Component/HttpFoundation/Session/Storage/AbstractSessionStorage.php rename to src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php index 4f8fde308f630..f34f5bccf07cf 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/AbstractSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php @@ -12,20 +12,16 @@ namespace Symfony\Component\HttpFoundation\Session\Storage; use Symfony\Component\HttpFoundation\Session\SessionBagInterface; +use Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy; +use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy; +use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy; /** * This provides a base class for session attribute storage. * - * This can be used to implement internal PHP session handlers - * provided by PHP extensions or custom session save handlers - * implementing the \SessionHandlerInterface - * - * @see http://php.net/session.customhandler - * @see http://php.net/sessionhandlerinterface - * * @author Drak */ -abstract class AbstractSessionStorage implements SessionStorageInterface +class SessionStorage implements SessionStorageInterface { /** * Array of SessionBagInterface @@ -49,6 +45,11 @@ abstract class AbstractSessionStorage implements SessionStorageInterface */ protected $closed = false; + /** + * @var AbstractProxy + */ + protected $saveHandler; + /** * Constructor. * @@ -75,7 +76,6 @@ abstract class AbstractSessionStorage implements SessionStorageInterface * hash_function, "0" * name, "PHPSESSID" * referer_check, "" - * save_path, "" * serialize_handler, "php" * use_cookies, "1" * use_only_cookies, "1" @@ -89,12 +89,23 @@ abstract class AbstractSessionStorage implements SessionStorageInterface * url_rewriter.tags, "a=href,area=href,frame=src,form=,fieldset=" * * @param array $options Session configuration options. + * @param $handler SessionHandlerInterface. */ - public function __construct(array $options = array()) + public function __construct(array $options = array(), $handler = null) { $this->setOptions($options); - $this->registerSaveHandlers(); - $this->registerShutdownFunction(); + + $this->setSaveHandler($handler); + } + + /** + * Gets the save handler instance. + * + * @return AbstractProxy + */ + public function getSaveHandler() + { + return $this->saveHandler; } /** @@ -117,6 +128,10 @@ public function start() $this->loadSession(); + if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) { + $this->saveHandler->setActive(false); + } + $this->started = true; $this->closed = false; @@ -149,6 +164,11 @@ public function regenerate($destroy = false) public function save() { session_write_close(); + + if (!$this->saveHandler->isWrapper() && !$this->getSaveHandler()->isSessionHandlerInterface()) { + $this->saveHandler->setActive(false); + } + $this->closed = true; } @@ -230,7 +250,7 @@ protected function setOptions(array $options) 'entropy_file', 'entropy_length', 'gc_divisor', 'gc_maxlifetime', 'gc_probability', 'hash_bits_per_character', 'hash_function', 'name', 'referer_check', - 'save_path', 'serialize_handler', 'use_cookies', + 'serialize_handler', 'use_cookies', 'use_only_cookies', 'use_trans_sid', 'upload_progress.enabled', 'upload_progress.cleanup', 'upload_progress.prefix', 'upload_progress.name', 'upload_progress.freq', 'upload_progress.min-freq', 'url_rewriter.tags'))) { @@ -240,7 +260,7 @@ protected function setOptions(array $options) } /** - * Registers this storage device as a PHP session handler. + * Registers save handler as a PHP session handler. * * To use internal PHP session save handlers, override this method using ini_set with * session.save_handlers and session.save_path e.g. @@ -250,34 +270,37 @@ protected function setOptions(array $options) * * @see http://php.net/session-set-save-handler * @see http://php.net/sessionhandlerinterface + * @see http://php.net/sessionhandler + * + * @param object $saveHandler */ - protected function registerSaveHandlers() + public function setSaveHandler($saveHandler) { - // note this can be reset to PHP's control using ini_set('session.save_handler', 'files'); - // so long as ini_set() is called before the session is started. - if ($this instanceof \SessionHandlerInterface) { - session_set_save_handler( - array($this, 'open'), - array($this, 'close'), - array($this, 'read'), - array($this, 'write'), - array($this, 'destroy'), - array($this, 'gc') - ); + // Wrap $saveHandler in proxy + if (!$saveHandler instanceof AbstractProxy && $saveHandler instanceof \SessionHandlerInterface) { + $saveHandler = new SessionHandlerProxy($saveHandler); + } else { + $saveHandler = new NativeProxy($saveHandler); } - } - /** - * Registers PHP shutdown function. - * - * This method is required to avoid strange issues when using PHP objects as - * session save handlers. - * - * @see http://php.net/register-shutdown-function - */ - protected function registerShutdownFunction() - { - register_shutdown_function('session_write_close'); + $this->saveHandler = $saveHandler; + + if ($this->saveHandler instanceof \SessionHandlerInterface) { + if (version_compare(phpversion(), '5.4.0', '>=')) { + session_set_save_handler($this->saveHandler, true); + } else { + session_set_save_handler( + array($this->saveHandler, 'open'), + array($this->saveHandler, 'close'), + array($this->saveHandler, 'read'), + array($this->saveHandler, 'write'), + array($this->saveHandler, 'destroy'), + array($this->saveHandler, 'gc') + ); + + register_shutdown_function('session_write_close'); + } + } } /** From 0a064d8aa1432e6fd0539591fe6b151305f6970e Mon Sep 17 00:00:00 2001 From: Drak Date: Sat, 3 Mar 2012 08:44:34 +0545 Subject: [PATCH 03/18] [HttpFoundation] Refactor session handlers. --- .../Storage/MemcachedSessionStorage.php | 6 ++-- .../Storage/NativeFileSessionStorage.php | 34 +++++-------------- .../Storage/NativeMemcacheSessionStorage.php | 26 +++++--------- .../Storage/NativeMemcachedSessionStorage.php | 27 +++++---------- .../Storage/NativeSqliteSessionStorage.php | 32 ++++++----------- .../Session/Storage/NullSessionStorage.php | 4 +-- 6 files changed, 40 insertions(+), 89 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MemcachedSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MemcachedSessionStorage.php index 366d815013756..bc642cb082869 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/MemcachedSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MemcachedSessionStorage.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\HttpFoundation\Session\Storage; +namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; /** * MemcachedSessionStorage. @@ -21,7 +21,7 @@ * * @author Drak */ -class MemcachedSessionStorage extends AbstractSessionStorage implements \SessionHandlerInterface +class MemcachedSessionHandler implements \SessionHandlerInterface { /** * Memcached driver. @@ -63,8 +63,6 @@ public function __construct(\Memcached $memcached, array $memcachedOptions = arr $this->memcached->setOption(\Memcached::OPT_PREFIX_KEY, isset($memcachedOptions['prefix']) ? $memcachedOptions['prefix'] : 'sf2s'); $this->memcachedOptions = $memcachedOptions; - - parent::__construct($options); } /** diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeFileSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeFileSessionStorage.php index eca342ec372ee..5acf004d15020 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeFileSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeFileSessionStorage.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\HttpFoundation\Session\Storage; +namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; /** * NativeFileSessionStorage. @@ -18,42 +18,24 @@ * * @author Drak */ -class NativeFileSessionStorage extends AbstractSessionStorage +class NativeFileSessionHandler extends NativeSessionHandler { - /** - * @var string - */ - private $savePath; - /** * Constructor. * - * @param string $savePath Path of directory to save session files. - * @param array $options Session configuration options. - * - * @see AbstractSessionStorage::__construct() + * @param string $savePath Path of directory to save session files. Default null will leave setting as defined by PHP. */ - public function __construct($savePath = null, array $options = array()) + public function __construct($savePath = null) { if (null === $savePath) { - $savePath = sys_get_temp_dir(); + $savePath = ini_get('session.save_path'); } - if (!is_dir($savePath)) { + if ($savePath && !is_dir($savePath)) { mkdir($savePath, 0777, true); } - $this->savePath = $savePath; - - parent::__construct($options); - } - - /** - * {@inheritdoc} - */ - protected function registerSaveHandlers() - { ini_set('session.save_handler', 'files'); - ini_set('session.save_path', $this->savePath); + ini_set('session.save_path', $savePath); } -} +} \ No newline at end of file diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorage.php index ec34ead6d8694..beef87e965ddf 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorage.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\HttpFoundation\Session\Storage; +namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; /** * NativeMemcacheSessionStorage. @@ -20,13 +20,8 @@ * * @author Drak */ -class NativeMemcacheSessionStorage extends AbstractSessionStorage +class NativeMemcacheSessionHandler extends NativeSessionHandler { - /** - * @var string - */ - private $savePath; - /** * Constructor. * @@ -41,17 +36,14 @@ public function __construct($savePath = 'tcp://127.0.0.1:11211?persistent=0', ar throw new \RuntimeException('PHP does not have "memcache" session module registered'); } - $this->savePath = $savePath; - parent::__construct($options); - } + if (null === $savePath) { + $savePath = ini_get('session.save_path'); + } - /** - * {@inheritdoc} - */ - protected function registerSaveHandlers() - { ini_set('session.save_handler', 'memcache'); - ini_set('session.save_path', $this->savePath); + ini_set('session.save_path', $savePath); + + $this->setOptions($options); } /** @@ -73,7 +65,5 @@ protected function setOptions(array $options) ini_set($key, $value); } } - - parent::setOptions($options); } } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorage.php index e923f34030d54..11f6790aefbaa 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorage.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\HttpFoundation\Session\Storage; +namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; /** * NativeMemcachedSessionStorage. @@ -20,13 +20,8 @@ * * @author Drak */ -class NativeMemcachedSessionStorage extends AbstractSessionStorage +class NativeMemcachedSessionHandler extends NativeSessionHandler { - /** - * @var string - */ - private $savePath; - /** * Constructor. * @@ -41,17 +36,14 @@ public function __construct($savePath = '127.0.0.1:11211', array $options = arra throw new \RuntimeException('PHP does not have "memcached" session module registered'); } - $this->savePath = $savePath; - parent::__construct($options); - } + if (null === $savePath) { + $savePath = ini_get('session.save_path'); + } - /** - * {@inheritdoc} - */ - protected function registerSaveHandlers() - { ini_set('session.save_handler', 'memcached'); - ini_set('session.save_path', $this->savePath); + ini_set('session.save_path', $savePath); + + $this->setOptions($options); } /** @@ -72,7 +64,6 @@ protected function setOptions(array $options) ini_set($key, $value); } } - - parent::setOptions($options); } + } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorage.php index 4c528b0dd7459..4f383efb054d7 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorage.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\HttpFoundation\Session\Storage; +namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; /** * NativeSqliteSessionStorage. @@ -18,38 +18,30 @@ * * @author Drak */ -class NativeSqliteSessionStorage extends AbstractSessionStorage +class NativeSqliteSessionHandler extends NativeSessionHandler { - /** - * @var string - */ - private $dbPath; - /** * Constructor. * - * @param string $dbPath Path to SQLite database file. - * @param array $options Session configuration options. + * @param string $savePath Path to SQLite database file itself. + * @param array $options Session configuration options. * * @see AbstractSessionStorage::__construct() */ - public function __construct($dbPath, array $options = array()) + public function __construct($savePath, array $options = array()) { if (!extension_loaded('sqlite')) { throw new \RuntimeException('PHP does not have "sqlite" session module registered'); } - $this->dbPath = $dbPath; - parent::__construct($options); - } + if (null === $savePath) { + $savePath = ini_get('session.save_path'); + } - /** - * {@inheritdoc} - */ - protected function registerSaveHandlers() - { ini_set('session.save_handler', 'sqlite'); - ini_set('session.save_path', $this->dbPath); + ini_set('session.save_path', $savePath); + + $this->setOptions($options); } /** @@ -66,7 +58,5 @@ protected function setOptions(array $options) ini_set($key, $value); } } - - parent::setOptions($options); } } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NullSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NullSessionStorage.php index 8f45a6eff2779..0839622aeaa7c 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/NullSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NullSessionStorage.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\HttpFoundation\Session\Storage; +namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; /** * NullSessionStorage. @@ -20,7 +20,7 @@ * * @api */ -class NullSessionStorage extends AbstractSessionStorage implements \SessionHandlerInterface +class NullSessionHandler implements \SessionHandlerInterface { /** * {@inheritdoc} From 2257a3d4d6a5fe2b5046ecef45ac0ec3433c2461 Mon Sep 17 00:00:00 2001 From: Drak Date: Sat, 3 Mar 2012 08:46:53 +0545 Subject: [PATCH 04/18] [HttpFoundation] Move session handler classes. --- .../MemcacheSessionHandler.php} | 6 ++---- .../MemcachedSessionHandler.php} | 0 .../NativeFileSessionHandler.php} | 0 .../NativeMemcacheSessionHandler.php} | 0 .../NativeMemcachedSessionHandler.php} | 0 .../NativeSqliteSessionHandler.php} | 0 .../NullSessionHandler.php} | 0 7 files changed, 2 insertions(+), 4 deletions(-) rename src/Symfony/Component/HttpFoundation/Session/Storage/{MemcacheSessionStorage.php => Handler/MemcacheSessionHandler.php} (94%) rename src/Symfony/Component/HttpFoundation/Session/Storage/{MemcachedSessionStorage.php => Handler/MemcachedSessionHandler.php} (100%) rename src/Symfony/Component/HttpFoundation/Session/Storage/{NativeFileSessionStorage.php => Handler/NativeFileSessionHandler.php} (100%) rename src/Symfony/Component/HttpFoundation/Session/Storage/{NativeMemcacheSessionStorage.php => Handler/NativeMemcacheSessionHandler.php} (100%) rename src/Symfony/Component/HttpFoundation/Session/Storage/{NativeMemcachedSessionStorage.php => Handler/NativeMemcachedSessionHandler.php} (100%) rename src/Symfony/Component/HttpFoundation/Session/Storage/{NativeSqliteSessionStorage.php => Handler/NativeSqliteSessionHandler.php} (100%) rename src/Symfony/Component/HttpFoundation/Session/Storage/{NullSessionStorage.php => Handler/NullSessionHandler.php} (100%) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MemcacheSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php similarity index 94% rename from src/Symfony/Component/HttpFoundation/Session/Storage/MemcacheSessionStorage.php rename to src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php index 68218e86b32e9..72ecac5550780 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/MemcacheSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php @@ -9,14 +9,14 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\HttpFoundation\Session\Storage; +namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; /** * MemcacheSessionStorage. * * @author Drak */ -class MemcacheSessionStorage extends AbstractSessionStorage implements \SessionHandlerInterface +class MemcacheSessionHandler implements \SessionHandlerInterface { /** * Memcache driver. @@ -68,8 +68,6 @@ public function __construct(\Memcache $memcache, array $memcacheOptions = array( $this->prefix = isset($memcacheOptions['prefix']) ? $memcacheOptions['prefix'] : 'sf2s'; $this->memcacheOptions = $memcacheOptions; - - parent::__construct($options); } protected function addServer(array $server) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MemcachedSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php similarity index 100% rename from src/Symfony/Component/HttpFoundation/Session/Storage/MemcachedSessionStorage.php rename to src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeFileSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandler.php similarity index 100% rename from src/Symfony/Component/HttpFoundation/Session/Storage/NativeFileSessionStorage.php rename to src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandler.php diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeMemcacheSessionHandler.php similarity index 100% rename from src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorage.php rename to src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeMemcacheSessionHandler.php diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeMemcachedSessionHandler.php similarity index 100% rename from src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorage.php rename to src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeMemcachedSessionHandler.php diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeSqliteSessionHandler.php similarity index 100% rename from src/Symfony/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorage.php rename to src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeSqliteSessionHandler.php diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NullSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandler.php similarity index 100% rename from src/Symfony/Component/HttpFoundation/Session/Storage/NullSessionStorage.php rename to src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandler.php From 88b117035662ae840a0dfea083d7359b96f8d64d Mon Sep 17 00:00:00 2001 From: Drak Date: Sat, 3 Mar 2012 08:47:45 +0545 Subject: [PATCH 05/18] [HttpFoundation] Refactor tests. --- .../Storage/AbstractSessionStorageTest.php | 91 ++++++++----------- .../Storage/MemcacheSessionStorageTest.php | 10 +- .../Storage/MemcachedSessionStorageTest.php | 10 +- .../Storage/NativeFileSessionStorageTest.php | 29 ++++-- .../NativeMemcacheSessionStorageTest.php | 21 +++-- .../NativeMemcachedSessionStorageTest.php | 20 ++-- .../NativeSqliteSessionStorageTest.php | 20 +++- .../Storage/NullSessionStorageTest.php | 18 ++-- 8 files changed, 126 insertions(+), 93 deletions(-) diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/AbstractSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/AbstractSessionStorageTest.php index 8d53002c8d0fb..c05d5730fffcc 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/AbstractSessionStorageTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/AbstractSessionStorageTest.php @@ -2,46 +2,12 @@ namespace Symfony\Tests\Component\HttpFoundation\Session\Storage; -use Symfony\Component\HttpFoundation\Session\Storage\AbstractSessionStorage; +use Symfony\Component\HttpFoundation\Session\Storage\SessionStorage; +use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler; +use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler; use Symfony\Component\HttpFoundation\Session\Flash\FlashBag; use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag; -/** - * Turn AbstractSessionStorage into something concrete because - * certain mocking features are broken in PHPUnit-Mock-Objects < 1.1.2 - * @see https://github.com/sebastianbergmann/phpunit-mock-objects/issues/73 - */ -class ConcreteSessionStorage extends AbstractSessionStorage -{ -} - -class CustomHandlerSessionStorage extends AbstractSessionStorage implements \SessionHandlerInterface -{ - public function open($path, $id) - { - } - - public function close() - { - } - - public function read($id) - { - } - - public function write($id, $data) - { - } - - public function destroy($id) - { - } - - public function gc($lifetime) - { - } -} - /** * Test class for AbstractSessionStorage. * @@ -51,14 +17,14 @@ public function gc($lifetime) * * @runTestsInSeparateProcesses */ -class AbstractSessionStorageTest extends \PHPUnit_Framework_TestCase +class SessionStorageTest extends \PHPUnit_Framework_TestCase { /** * @return AbstractSessionStorage */ - protected function getStorage($options = array()) + protected function getStorage(array $options = array()) { - $storage = new CustomHandlerSessionStorage($options); + $storage = new SessionStorage($options); $storage->registerBag(new AttributeBag); return $storage; @@ -112,23 +78,11 @@ public function testRegenerateDestroy() $this->assertEquals(11, $storage->getBag('attributes')->get('legs')); } - public function testCustomSaveHandlers() - { - $storage = new CustomHandlerSessionStorage(); - $this->assertEquals('user', ini_get('session.save_handler')); - } - - public function testNativeSaveHandlers() - { - $storage = new ConcreteSessionStorage(); - $this->assertNotEquals('user', ini_get('session.save_handler')); - } - public function testDefaultSessionCacheLimiter() { ini_set('session.cache_limiter', 'nocache'); - $storage = new ConcreteSessionStorage(); + $storage = new SessionStorage(); $this->assertEquals('', ini_get('session.cache_limiter')); } @@ -136,7 +90,7 @@ public function testExplicitSessionCacheLimiter() { ini_set('session.cache_limiter', 'nocache'); - $storage = new ConcreteSessionStorage(array('cache_limiter' => 'public')); + $storage = new SessionStorage(array('cache_limiter' => 'public')); $this->assertEquals('public', ini_get('session.cache_limiter')); } @@ -160,4 +114,33 @@ public function testCookieOptions() $this->assertEquals($options, $gco); } + + public function testSetSaveHandler() + { + $storage = $this->getStorage(); + $storage->setSaveHandler(new \StdClass()); + $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy', $storage->getSaveHandler()); + } + + public function testSetSaveHandlerPHP53() + { + if (version_compare(phpversion(), '5.4.0', '>=')) { + $this->markTestSkipped('Test skipped, for PHP 5.3 only.'); + } + + $storage = $this->getStorage(); + $storage->setSaveHandler(new NativeFileSessionHandler()); + $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy', $storage->getSaveHandler()); + } + + public function testSetSaveHandlerPHP54() + { + if (version_compare(phpversion(), '5.4.0', '<')) { + $this->markTestSkipped('Test skipped, for PHP 5.4+ only.'); + } + + $storage = $this->getStorage(); + $storage->setSaveHandler(new NullSessionHandler()); + $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler()); + } } diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MemcacheSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MemcacheSessionStorageTest.php index 1cdbe2a3a9a16..3d4adfab47f64 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MemcacheSessionStorageTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MemcacheSessionStorageTest.php @@ -1,10 +1,10 @@ memcache = $this->getMock('Memcache'); - $this->storage = new MemcacheSessionStorage($this->memcache); + $this->storage = new MemcacheSessionHandler($this->memcache); } protected function tearDown() @@ -42,7 +42,7 @@ public function testConstructingWithServerPool() { $mock = $this->getMock('Memcache'); - $storage = new MemcacheSessionStorage($mock, array( + $storage = new MemcacheSessionHandler($mock, array( 'serverpool' => array( array('host' => '127.0.0.2'), array('host' => '127.0.0.3', diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MemcachedSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MemcachedSessionStorageTest.php index cc8d0bee3554b..1fca44445e1a0 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MemcachedSessionStorageTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MemcachedSessionStorageTest.php @@ -1,13 +1,13 @@ memcached = $this->getMock('Memcached'); - $this->storage = new MemcachedSessionStorage($this->memcached); + $this->storage = new MemcachedSessionHandler($this->memcached); } protected function tearDown() diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeFileSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeFileSessionStorageTest.php index df3ef95cbf799..08b8644ebfd76 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeFileSessionStorageTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeFileSessionStorageTest.php @@ -1,8 +1,9 @@ 'TESTING')); - $this->assertEquals('files', ini_get('session.save_handler')); + $storage = new SessionStorage(array('name' => 'TESTING'), new NativeFileSessionHandler(sys_get_temp_dir())); + + if (version_compare(phpversion(), '5.4.0', '<')) { + $this->assertEquals('files', $storage->getSaveHandler()->getSaveHandlerName()); + $this->assertEquals('files', ini_get('session.save_handler')); + } else { + $this->assertEquals('files', $storage->getSaveHandler()->getSaveHandlerName()); + $this->assertEquals('user', ini_get('session.save_handler')); + } + $this->assertEquals(sys_get_temp_dir(), ini_get('session.save_path')); $this->assertEquals('TESTING', ini_get('session.name')); } + + public function testConstructDefault() + { + $path = ini_get('session.save_path'); + $storage = new SessionStorage(array('name' => 'TESTING'), new NativeFileSessionHandler()); + + $this->assertEquals($path, ini_get('session.save_path')); + } } diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorageTest.php index 4274ed5bd1496..377fe1754c625 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorageTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorageTest.php @@ -1,17 +1,18 @@ * * @runTestsInSeparateProcesses */ -class NativeMemcacheSessionStorageTest extends \PHPUnit_Framework_TestCase +class NativeMemcacheSessionHandlerTest extends \PHPUnit_Framework_TestCase { public function testSaveHandlers() { @@ -19,8 +20,16 @@ public function testSaveHandlers() $this->markTestSkipped('Skipped tests SQLite extension is not present'); } - $storage = new NativeMemcacheSessionStorage('tcp://127.0.0.1:11211?persistent=0', array('name' => 'TESTING')); - $this->assertEquals('memcache', ini_get('session.save_handler')); + $storage = new SessionStorage(array('name' => 'TESTING'), new NativeMemcacheSessionHandler('tcp://127.0.0.1:11211?persistent=0')); + + if (version_compare(phpversion(), '5.4.0', '<')) { + $this->assertEquals('memcache', $storage->getSaveHandler()->getSaveHandlerName()); + $this->assertEquals('memcache', ini_get('session.save_handler')); + } else { + $this->assertEquals('memcache', $storage->getSaveHandler()->getSaveHandlerName()); + $this->assertEquals('user', ini_get('session.save_handler')); + } + $this->assertEquals('tcp://127.0.0.1:11211?persistent=0', ini_get('session.save_path')); $this->assertEquals('TESTING', ini_get('session.name')); } diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorageTest.php index c0a12aa2b4d15..f4ae96c6e2d0e 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorageTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorageTest.php @@ -1,17 +1,18 @@ * * @runTestsInSeparateProcesses */ -class NativeMemcachedSessionStorageTest extends \PHPUnit_Framework_TestCase +class NativeMemcachedSessionHandlerTest extends \PHPUnit_Framework_TestCase { public function testSaveHandlers() { @@ -22,9 +23,16 @@ public function testSaveHandlers() // test takes too long if memcached server is not running ini_set('memcached.sess_locking', '0'); - $storage = new NativeMemcachedSessionStorage('127.0.0.1:11211', array('name' => 'TESTING')); + $storage = new SessionStorage(array('name' => 'TESTING'), new NativeMemcachedSessionHandler('127.0.0.1:11211')); + + if (version_compare(phpversion(), '5.4.0', '<')) { + $this->assertEquals('memcached', $storage->getSaveHandler()->getSaveHandlerName()); + $this->assertEquals('memcached', ini_get('session.save_handler')); + } else { + $this->assertEquals('memcached', $storage->getSaveHandler()->getSaveHandlerName()); + $this->assertEquals('user', ini_get('session.save_handler')); + } - $this->assertEquals('memcached', ini_get('session.save_handler')); $this->assertEquals('127.0.0.1:11211', ini_get('session.save_path')); $this->assertEquals('TESTING', ini_get('session.name')); } diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorageTest.php index b1700326b1d8a..373b0e8a491c8 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorageTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorageTest.php @@ -1,8 +1,9 @@ markTestSkipped('Skipped tests SQLite extension is not present'); } - $storage = new NativeSqliteSessionStorage(sys_get_temp_dir().'/sqlite.db', array('name' => 'TESTING')); - $this->assertEquals('sqlite', ini_get('session.save_handler')); + $storage = new SessionStorage(array('name' => 'TESTING'), new NativeSqliteSessionHandler(sys_get_temp_dir().'/sqlite.db')); + + if (version_compare(phpversion(), '5.4.0', '<')) { + $this->assertEquals('sqlite', $storage->getSaveHandler()->getSaveHandlerName()); + $this->assertEquals('sqlite', ini_get('session.save_handler')); + } else { + $this->assertEquals('sqlite', $storage->getSaveHandler()->getSaveHandlerName()); + $this->assertEquals('user', ini_get('session.save_handler')); + } + + $this->assertEquals(sys_get_temp_dir().'/sqlite.db', ini_get('session.save_path')); $this->assertEquals('TESTING', ini_get('session.name')); } diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NullSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NullSessionStorageTest.php index 66599f68b3cef..289aa9c85cd13 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NullSessionStorageTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NullSessionStorageTest.php @@ -1,11 +1,12 @@ * @@ -15,14 +16,14 @@ class NullSessionStorageTest extends \PHPUnit_Framework_TestCase { public function testSaveHandlers() { - $storage = new NullSessionStorage(); + $storage = $this->getStorage(); $this->assertEquals('user', ini_get('session.save_handler')); } public function testSession() { session_id('nullsessionstorage'); - $storage = new NullSessionStorage(); + $storage = $this->getStorage(); $session = new Session($storage); $this->assertNull($session->get('something')); $session->set('something', 'unique'); @@ -32,11 +33,16 @@ public function testSession() public function testNothingIsPersisted() { session_id('nullsessionstorage'); - $storage = new NullSessionStorage(); + $storage = $this->getStorage(); $session = new Session($storage); $session->start(); $this->assertEquals('nullsessionstorage', $session->getId()); $this->assertNull($session->get('something')); } + + public function getStorage() + { + return new SessionStorage(array(), new NullSessionHandler()); + } } From 130831248deb5e0a18666bfc04e9498388498c5b Mon Sep 17 00:00:00 2001 From: Drak Date: Sat, 3 Mar 2012 08:49:40 +0545 Subject: [PATCH 06/18] [HttpFoundation] Add and relocate tests. --- .../MemcacheSessionHandlerTest.php} | 0 .../MemcachedSessionHandlerTest.php} | 0 .../NativeFileSessionHandlerTest.php} | 0 .../NativeMemcacheSessionHandlerTest.php} | 0 .../NativeMemcachedSessionHandlerTest.php} | 0 .../NativeSqliteSessionHandlerTest.php} | 0 .../NullSessionHandlerTest.php} | 0 .../Storage/Proxy/AbstractProxyTest.php | 69 ++++++++++++++++++ .../Storage/Proxy/NativeProxyPHP53Test.php | 34 +++++++++ .../Storage/Proxy/NativeProxyPHP54Test.php | 30 ++++++++ .../Storage/Proxy/SessionHandlerProxyTest.php | 70 +++++++++++++++++++ ...StorageTest.php => SessionStorageTest.php} | 0 12 files changed, 203 insertions(+) rename tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/{MemcacheSessionStorageTest.php => Handler/MemcacheSessionHandlerTest.php} (100%) rename tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/{MemcachedSessionStorageTest.php => Handler/MemcachedSessionHandlerTest.php} (100%) rename tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/{NativeFileSessionStorageTest.php => Handler/NativeFileSessionHandlerTest.php} (100%) rename tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/{NativeMemcacheSessionStorageTest.php => Handler/NativeMemcacheSessionHandlerTest.php} (100%) rename tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/{NativeMemcachedSessionStorageTest.php => Handler/NativeMemcachedSessionHandlerTest.php} (100%) rename tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/{NativeSqliteSessionStorageTest.php => Handler/NativeSqliteSessionHandlerTest.php} (100%) rename tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/{NullSessionStorageTest.php => Handler/NullSessionHandlerTest.php} (100%) create mode 100644 tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxyTest.php create mode 100644 tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyPHP53Test.php create mode 100644 tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyPHP54Test.php create mode 100644 tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxyTest.php rename tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/{AbstractSessionStorageTest.php => SessionStorageTest.php} (100%) diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MemcacheSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandlerTest.php similarity index 100% rename from tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MemcacheSessionStorageTest.php rename to tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandlerTest.php diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MemcachedSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandlerTest.php similarity index 100% rename from tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MemcachedSessionStorageTest.php rename to tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandlerTest.php diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeFileSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandlerTest.php similarity index 100% rename from tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeFileSessionStorageTest.php rename to tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandlerTest.php diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeMemcacheSessionHandlerTest.php similarity index 100% rename from tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorageTest.php rename to tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeMemcacheSessionHandlerTest.php diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeMemcachedSessionHandlerTest.php similarity index 100% rename from tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorageTest.php rename to tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeMemcachedSessionHandlerTest.php diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeSqliteSessionHandlerTest.php similarity index 100% rename from tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorageTest.php rename to tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeSqliteSessionHandlerTest.php diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NullSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandlerTest.php similarity index 100% rename from tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NullSessionStorageTest.php rename to tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandlerTest.php diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxyTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxyTest.php new file mode 100644 index 0000000000000..a968e2e0a34dc --- /dev/null +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxyTest.php @@ -0,0 +1,69 @@ +proxy = new ConcreteProxy; + } + + protected function tearDown() + { + $this->proxy = null; + } + + public function testGetSaveHandlerName() + { + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + public function testIsSessionHandlerInterface() + { + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + public function testIsWrapper() + { + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + public function testIsActive() + { + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + public function testSetActive() + { + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + +} diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyPHP53Test.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyPHP53Test.php new file mode 100644 index 0000000000000..b62ce8192bf42 --- /dev/null +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyPHP53Test.php @@ -0,0 +1,34 @@ +=')) { + $this->markTestSkipped('Test skipped, only for PHP 5.3'); + } + } + + public function testIsWrapper() + { + $proxy = new NativeProxy(new NativeFileSessionHandler()); + $this->assertFalse($proxy->isWrapper()); + } + + public function testGetSaveHandlerName() + { + $name = ini_get('session.save_handler'); + $proxy = new NativeProxy(new NativeFileSessionHandler()); + $this->assertEquals($name, $proxy->getSaveHandlerName()); + } +} diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyPHP54Test.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyPHP54Test.php new file mode 100644 index 0000000000000..f6c3d7aa755cd --- /dev/null +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyPHP54Test.php @@ -0,0 +1,30 @@ +markTestSkipped('Test skipped, only for PHP 5.4'); + } + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testConstructor() + { + $proxy = new NativeProxy(new NativeFileSessionHandler()); + $this->assertTrue($proxy->isWrapper()); + } +} diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxyTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxyTest.php new file mode 100644 index 0000000000000..fb7d36addaf36 --- /dev/null +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxyTest.php @@ -0,0 +1,70 @@ +proxy = new SessionHandlerProxy(new NullSessionHandler()); + } + + protected function tearDown() + { + $this->proxy = null; + } + + public function testOpen() + { + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + public function testClose() + { + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + public function testRead() + { + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + public function testWrite() + { + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + public function testDestroy() + { + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + public function testGc() + { + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + +} diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/AbstractSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/SessionStorageTest.php similarity index 100% rename from tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/AbstractSessionStorageTest.php rename to tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/SessionStorageTest.php From a1c678ecd7cfeff4230281bcb497d48233cffba9 Mon Sep 17 00:00:00 2001 From: Drak Date: Sat, 3 Mar 2012 14:48:04 +0545 Subject: [PATCH 07/18] [FrameworkBundle] Add session.handler service and handler_id configuration property. Revert service back to session.storage.native Rename session.storage.native_file to session.handler.native_file (which is the default so no BC break from 2.0) --- .../DependencyInjection/Configuration.php | 3 ++- .../DependencyInjection/FrameworkExtension.php | 8 +++++++- .../Resources/config/schema/symfony-1.0.xsd | 1 + .../FrameworkBundle/Resources/config/session.xml | 13 ++++++++----- .../Fixtures/php/deprecated_merge_full.php | 3 ++- .../Fixtures/php/deprecated_merge_partial.php | 3 ++- .../Tests/DependencyInjection/Fixtures/php/full.php | 3 ++- .../Fixtures/xml/deprecated_merge_full.xml | 2 +- .../Fixtures/xml/deprecated_merge_partial.xml | 2 +- .../Tests/DependencyInjection/Fixtures/xml/full.xml | 2 +- .../Fixtures/yml/deprecated_merge_full.yml | 3 ++- .../Fixtures/yml/deprecated_merge_partial.yml | 3 ++- .../Tests/DependencyInjection/Fixtures/yml/full.yml | 3 ++- .../DependencyInjection/FrameworkExtensionTest.php | 3 ++- 14 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index ca63874b0f9db..652531d613300 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -167,7 +167,8 @@ private function addSessionSection(ArrayNodeDefinition $rootNode) ->canBeUnset() ->children() ->booleanNode('auto_start')->defaultFalse()->end() - ->scalarNode('storage_id')->defaultValue('session.storage.native_file')->end() + ->scalarNode('storage_id')->defaultValue('session.storage.native')->end() + ->scalarNode('handler_id')->defaultValue('session.handler.native_file')->end() ->scalarNode('name')->end() ->scalarNode('cookie_lifetime')->end() ->scalarNode('cookie_path')->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 5a76df3b492ab..7a7999d4a2f04 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -310,10 +310,16 @@ private function registerSessionConfiguration(array $config, ContainerBuilder $c } $container->setParameter('session.storage.options', $options); + // session handler (the internal callback registered with PHP session management) + $container->setAlias('session.handler', $config['handler_id']); + $this->addClassesToCompile(array( 'Symfony\\Bundle\\FrameworkBundle\\EventListener\\SessionListener', 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorageInterface', - 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\AbstractSessionStorage', + 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorage', + 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\NativeSessionHandler', + 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\Proxy\AbstractProxy', + 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\Proxy\SessionHandlerProxy', $container->getDefinition('session')->getClass(), )); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 535c455b0c370..8b7c264ce218d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -74,6 +74,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml index 31d374aa6b22c..3b985be216685 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml @@ -8,8 +8,9 @@ Symfony\Component\HttpFoundation\Session\Session Symfony\Component\HttpFoundation\Session\Flash\AutoExpireFlashBag Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag - Symfony\Component\HttpFoundation\Session\Storage\NativeFileSessionStorage + Symfony\Component\HttpFoundation\Session\Storage\SessionStorage Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage + Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler Symfony\Bundle\FrameworkBundle\EventListener\SessionListener @@ -20,18 +21,21 @@ + + %session.storage.options% + + + %kernel.cache_dir%/sessions - %session.storage.options% - + %kernel.cache_dir%/sessions - %session.storage.options% @@ -40,7 +44,6 @@ - diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/deprecated_merge_full.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/deprecated_merge_full.php index 219644b563ae3..5119fbdbabae6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/deprecated_merge_full.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/deprecated_merge_full.php @@ -4,7 +4,8 @@ 'secret' => 's3cr3t', 'session' => array( 'auto_start' => true, - 'storage_id' => 'session.storage.native_file', + 'storage_id' => 'session.storage.native', + 'handler_id' => 'session.handler.native_file', 'name' => '_SYMFONY', 'lifetime' => 2012, 'path' => '/sf2', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/deprecated_merge_partial.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/deprecated_merge_partial.php index deadfe4b88159..b15ea893f02ff 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/deprecated_merge_partial.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/deprecated_merge_partial.php @@ -4,7 +4,8 @@ 'secret' => 's3cr3t', 'session' => array( 'auto_start' => true, - 'storage_id' => 'session.storage.native_file', + 'storage_id' => 'session.storage.native', + 'handler_id' => 'session.handler.native_file', 'name' => '_SYMFONY', 'lifetime' => 2012, 'path' => '/sf2', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php index 3ab6488493024..32fa1812fa83c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php @@ -20,7 +20,8 @@ ), 'session' => array( 'auto_start' => true, - 'storage_id' => 'session.storage.native_file', + 'storage_id' => 'session.storage.native', + 'handler_id' => 'session.handler.native_file', 'name' => '_SYMFONY', 'lifetime' => 86400, 'path' => '/', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/deprecated_merge_full.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/deprecated_merge_full.xml index 283fb3190cba9..7b95b4200240c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/deprecated_merge_full.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/deprecated_merge_full.xml @@ -7,6 +7,6 @@ http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/deprecated_merge_partial.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/deprecated_merge_partial.xml index 07df1182cfd9b..701bae53bd75b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/deprecated_merge_partial.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/deprecated_merge_partial.xml @@ -7,6 +7,6 @@ http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml index d91825bd20c05..5ee785070ea69 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml @@ -12,7 +12,7 @@ - + loader.foo loader.bar diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/deprecated_merge_full.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/deprecated_merge_full.yml index fdc61fd93748a..e5ec05fbf6322 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/deprecated_merge_full.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/deprecated_merge_full.yml @@ -2,7 +2,8 @@ framework: secret: s3cr3t session: auto_start: true - storage_id: session.storage.native_file + storage_id: session.storage.native + handler_id: session.handler.native_file name: _SYMFONY lifetime: 2012 path: /sf2 diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/deprecated_merge_partial.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/deprecated_merge_partial.yml index e61808b8f2af4..67ea8bc44ba08 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/deprecated_merge_partial.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/deprecated_merge_partial.yml @@ -2,7 +2,8 @@ framework: secret: s3cr3t session: auto_start: true - storage_id: session.storage.native_file + storage_id: session.storage.native + handler_id: session.handler.native_file name: _SYMFONY lifetime: 2012 path: /sf2 diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml index 126baf2d4e90b..dd459e784fc3a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml @@ -14,7 +14,8 @@ framework: type: xml session: auto_start: true - storage_id: session.storage.native_file + storage_id: session.storage.native + handler_id: session.handler.native_file name: _SYMFONY lifetime: 86400 path: / diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index eac0395dbdb80..43ae49a016e6b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -78,7 +78,8 @@ public function testSession() $this->assertTrue($container->hasDefinition('session'), '->registerSessionConfiguration() loads session.xml'); $this->assertEquals('fr', $container->getParameter('kernel.default_locale')); $this->assertTrue($container->getDefinition('session_listener')->getArgument(1)); - $this->assertEquals('session.storage.native_file', (string) $container->getAlias('session.storage')); + $this->assertEquals('session.storage.native', (string) $container->getAlias('session.storage')); + $this->assertEquals('session.handler.native_file', (string) $container->getAlias('session.handler')); $options = $container->getParameter('session.storage.options'); $this->assertEquals('_SYMFONY', $options['name']); From a6a9280a3b43209f977f6a89c62c6bf6acc195a8 Mon Sep 17 00:00:00 2001 From: Drak Date: Sun, 4 Mar 2012 16:45:42 +0545 Subject: [PATCH 08/18] [DoctrineBridge] Refactor session storage to handler. --- ...sionStorage.php => DbalSessionHandler.php} | 66 ++++++------------- ...chema.php => DbalSessionHandlerSchema.php} | 11 +++- 2 files changed, 30 insertions(+), 47 deletions(-) rename src/Symfony/Bridge/Doctrine/HttpFoundation/{DbalSessionStorage.php => DbalSessionHandler.php} (69%) rename src/Symfony/Bridge/Doctrine/HttpFoundation/{DbalSessionStorageSchema.php => DbalSessionHandlerSchema.php} (76%) diff --git a/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionStorage.php b/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandler.php similarity index 69% rename from src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionStorage.php rename to src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandler.php index a260c3a14974a..cef6cec860f4b 100644 --- a/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionStorage.php +++ b/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandler.php @@ -1,9 +1,17 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Symfony\Bridge\Doctrine\HttpFoundation; use Doctrine\DBAL\Platforms\MySqlPlatform; -use Symfony\Component\HttpFoundation\Session\Storage\AbstractSessionStorage; use Doctrine\DBAL\Driver\Connection; /** @@ -12,7 +20,7 @@ * @author Fabien Potencier * @author Johannes M. Schmitt */ -class DbalSessionStorage extends AbstractSessionStorage implements \SessionHandlerInterface +class DbalSessionHandler implements \SessionHandlerInterface { /** * @var Connection @@ -25,26 +33,19 @@ class DbalSessionStorage extends AbstractSessionStorage implements \SessionHandl private $tableName; /** + * Constructor. * - * @param Connection $con An instance of Connection. - * @param string $tableName Table name. - * @param array $options Session configuration options + * @param Connection $con An instance of Connection. + * @param string $tableName Table name. */ - public function __construct(Connection $con, $tableName = 'sessions', array $options = array()) + public function __construct(Connection $con, $tableName = 'sessions') { $this->con = $con; $this->tableName = $tableName; - - parent::__construct($options); } /** - * Opens a session. - * - * @param string $path (ignored) - * @param string $name (ignored) - * - * @return Boolean true, if the session was opened, otherwise an exception is thrown + * {@inheritdoc} */ public function open($path = null, $name = null) { @@ -52,9 +53,7 @@ public function open($path = null, $name = null) } /** - * Closes a session. - * - * @return Boolean true, if the session was closed, otherwise false + * {@inheritdoc} */ public function close() { @@ -63,13 +62,7 @@ public function close() } /** - * Destroys a session. - * - * @param string $id A session ID - * - * @return Boolean true, if the session was destroyed, otherwise an exception is thrown - * - * @throws \RuntimeException If the session cannot be destroyed + * {@inheritdoc} */ public function destroy($id) { @@ -85,13 +78,7 @@ public function destroy($id) } /** - * Cleans up old sessions. - * - * @param int $lifetime The lifetime of a session - * - * @return Boolean true, if old sessions have been cleaned, otherwise an exception is thrown - * - * @throws \RuntimeException If any old sessions cannot be cleaned + * {@inheritdoc} */ public function gc($lifetime) { @@ -107,13 +94,7 @@ public function gc($lifetime) } /** - * Reads a session. - * - * @param string $id A session ID - * - * @return string The session data if the session was read or created, otherwise an exception is thrown - * - * @throws \RuntimeException If the session cannot be read + * {@inheritdoc} */ public function read($id) { @@ -136,14 +117,7 @@ public function read($id) } /** - * Writes session data. - * - * @param string $id A session ID - * @param string $data A serialized chunk of session data - * - * @return Boolean true, if the session was written, otherwise an exception is thrown - * - * @throws \RuntimeException If the session data cannot be written + * {@inheritdoc} */ public function write($id, $data) { diff --git a/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionStorageSchema.php b/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandlerSchema.php similarity index 76% rename from src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionStorageSchema.php rename to src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandlerSchema.php index b33862588c9c0..b7b4b91a7a74b 100644 --- a/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionStorageSchema.php +++ b/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandlerSchema.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Symfony\Bridge\Doctrine\HttpFoundation; use Doctrine\DBAL\Schema\Schema; @@ -9,7 +18,7 @@ * * @author Johannes M. Schmitt */ -final class DbalSessionStorageSchema extends Schema +final class DbalSessionHandlerSchema extends Schema { private $tableName; From cb873b250b231f74b9542f7497679b07f80e7242 Mon Sep 17 00:00:00 2001 From: Drak Date: Sun, 4 Mar 2012 16:49:40 +0545 Subject: [PATCH 09/18] [HttpFoundation] Add tests and some CS/docblocks. --- .../HttpFoundation/Session/Session.php | 6 +- .../Handler/NativeMemcachedSessionHandler.php | 1 - .../Session/Storage/Proxy/AbstractProxy.php | 11 ++- .../Session/Storage/Proxy/NativeProxy.php | 12 +-- .../Storage/Proxy/SessionHandlerProxy.php | 26 +++--- .../Session/Storage/SessionStorage.php | 16 ++-- .../Storage/Proxy/AbstractProxyTest.php | 59 +++++++++---- .../Storage/Proxy/NativeProxyPHP54Test.php | 30 ------- ...ProxyPHP53Test.php => NativeProxyTest.php} | 15 +--- .../Storage/Proxy/SessionHandlerProxyTest.php | 87 ++++++++++++++----- 10 files changed, 147 insertions(+), 116 deletions(-) delete mode 100644 tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyPHP54Test.php rename tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/{NativeProxyPHP53Test.php => NativeProxyTest.php} (57%) diff --git a/src/Symfony/Component/HttpFoundation/Session/Session.php b/src/Symfony/Component/HttpFoundation/Session/Session.php index 63dda8d6bdbc6..6f2c6a4262a02 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Session.php +++ b/src/Symfony/Component/HttpFoundation/Session/Session.php @@ -38,13 +38,13 @@ class Session implements SessionInterface /** * Constructor. * - * @param SessionStorageInterface $storage A SessionStorageInterface instance. + * @param SessionStorageInterface $storage A SessionStorageInterface instance. * @param AttributeBagInterface $attributes An AttributeBagInterface instance, (defaults null for default AttributeBag) * @param FlashBagInterface $flashes A FlashBagInterface instance (defaults null for default FlashBag) */ - public function __construct(SessionStorageInterface $storage, AttributeBagInterface $attributes = null, FlashBagInterface $flashes = null) + public function __construct(SessionStorageInterface $storage = null, AttributeBagInterface $attributes = null, FlashBagInterface $flashes = null) { - $this->storage = $storage; + $this->storage = $storage ?: new SessionStorage(); $this->registerBag($attributes ?: new AttributeBag()); $this->registerBag($flashes ?: new FlashBag()); } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeMemcachedSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeMemcachedSessionHandler.php index 11f6790aefbaa..d66dc953d6d45 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeMemcachedSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeMemcachedSessionHandler.php @@ -65,5 +65,4 @@ protected function setOptions(array $options) } } } - } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php index 41cd49cb1eaf8..0cd4d73d96a58 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php @@ -13,6 +13,8 @@ /** * AbstractProxy. + * + * @author Drak */ abstract class AbstractProxy { @@ -43,9 +45,14 @@ public function getSaveHandlerName() return $this->saveHandlerName; } + /** + * Is this proxy handler and instance of \SessionHandlerInterface. + * + * @return boolean + */ public function isSessionHandlerInterface() { - return (bool)($this instanceof \SessionHandlerInterface); + return ($this instanceof \SessionHandlerInterface); } /** @@ -75,6 +82,6 @@ public function isActive() */ public function setActive($flag) { - $this->active = (bool)$flag; + $this->active = (bool) $flag; } } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/NativeProxy.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/NativeProxy.php index 952c7105cdf68..5bb2c712e32ae 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/NativeProxy.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/NativeProxy.php @@ -15,21 +15,17 @@ * NativeProxy. * * This proxy is built-in session handlers in PHP 5.3.x + * + * @author Drak */ class NativeProxy extends AbstractProxy { /** * Constructor. - * - * @param $handler */ - public function __construct($handler) + public function __construct() { - if (version_compare(phpversion(), '5.4.0', '>=') && $handler instanceof \SessionHandlerInterface) { - throw new \InvalidArgumentException('This proxy is only for PHP 5.3 and not for instances of \SessionHandler or \SessionHandlerInterface'); - } - - $this->handler = $handler; + // this makes an educated guess as to what the handler is since it should already be set. $this->saveHandlerName = ini_get('session.save_handler'); } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php index 93a1010a73b96..e925d628df4a7 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php @@ -13,6 +13,8 @@ /** * SessionHandler proxy. + * + * @author Drak */ class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterface { @@ -29,7 +31,7 @@ class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterf public function __construct(\SessionHandlerInterface $handler) { $this->handler = $handler; - $this->wrapper = (bool)(class_exists('SessionHandler') && $handler instanceof \SessionHandler); + $this->wrapper = ($handler instanceof \SessionHandler); $this->saveHandlerName = $this->wrapper ? ini_get('session.save_handler') : 'user'; } @@ -38,7 +40,7 @@ public function __construct(\SessionHandlerInterface $handler) /** * {@inheritdoc} */ - function open($savePath, $sessionName) + public function open($savePath, $sessionName) { $return = (bool)$this->handler->open($savePath, $sessionName); @@ -52,42 +54,42 @@ function open($savePath, $sessionName) /** * {@inheritdoc} */ - function close() + public function close() { $this->active = false; - return (bool)$this->handler->close(); + return (bool) $this->handler->close(); } /** * {@inheritdoc} */ - function read($id) + public function read($id) { - return (string)$this->handler->read($id); + return (string) $this->handler->read($id); } /** * {@inheritdoc} */ - function write($id, $data) + public function write($id, $data) { - return (bool)$this->handler->write($id, $data); + return (bool) $this->handler->write($id, $data); } /** * {@inheritdoc} */ - function destroy($id) + public function destroy($id) { - return (bool)$this->handler->destroy($id); + return (bool) $this->handler->destroy($id); } /** * {@inheritdoc} */ - function gc($maxlifetime) + public function gc($maxlifetime) { - return (bool)$this->handler->gc($maxlifetime); + return (bool) $this->handler->gc($maxlifetime); } } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php index f34f5bccf07cf..f5a1578767f91 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php @@ -88,13 +88,12 @@ class SessionStorage implements SessionStorageInterface * upload_progress.min-freq, "1" * url_rewriter.tags, "a=href,area=href,frame=src,form=,fieldset=" * - * @param array $options Session configuration options. - * @param $handler SessionHandlerInterface. + * @param array $options Session configuration options. + * @param object $handler SessionHandlerInterface. */ public function __construct(array $options = array(), $handler = null) { $this->setOptions($options); - $this->setSaveHandler($handler); } @@ -118,7 +117,7 @@ public function start() } if ($this->options['use_cookies'] && headers_sent()) { - throw new \RuntimeException('Failed to start the session because header have already been sent.'); + throw new \RuntimeException('Failed to start the session because headers have already been sent.'); } // start the session @@ -225,7 +224,7 @@ public function getBag($name) * * @see http://php.net/session.configuration */ - protected function setOptions(array $options) + public function setOptions(array $options) { $this->options = $options; @@ -234,7 +233,6 @@ protected function setOptions(array $options) 'cache_limiter' => '', // disable by default because it's managed by HeaderBag (if used) 'auto_start' => false, 'use_cookies' => true, - 'cookie_httponly' => true, ); foreach ($defaults as $key => $value) { @@ -272,14 +270,14 @@ protected function setOptions(array $options) * @see http://php.net/sessionhandlerinterface * @see http://php.net/sessionhandler * - * @param object $saveHandler + * @param object $saveHandler Default null means NativeProxy. */ - public function setSaveHandler($saveHandler) + public function setSaveHandler($saveHandler = null) { // Wrap $saveHandler in proxy if (!$saveHandler instanceof AbstractProxy && $saveHandler instanceof \SessionHandlerInterface) { $saveHandler = new SessionHandlerProxy($saveHandler); - } else { + } elseif (!$saveHandler instanceof AbstractProxy) { $saveHandler = new NativeProxy($saveHandler); } diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxyTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxyTest.php index a968e2e0a34dc..efa9f75e646fd 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxyTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxyTest.php @@ -4,15 +4,44 @@ use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy; +// Note until PHPUnit_Mock_Objects 1.2 is released you cannot mock abstracts due to +// https://github.com/sebastianbergmann/phpunit-mock-objects/issues/73 class ConcreteProxy extends AbstractProxy { } +class ConcreteSessionHandlerInterfaceProxy extends AbstractProxy implements \SessionHandlerInterface +{ + public function open($savePath, $sessionName) + { + } + + public function close() + { + } + + public function read($id) + { + } + + public function write($id, $data) + { + } + + public function destroy($id) + { + } + + public function gc($maxlifetime) + { + } +} + /** * Test class for AbstractProxy. * - * @runTestsInSeparateProcesses + * @author Drak */ class AbstractProxyTest extends \PHPUnit_Framework_TestCase { @@ -23,7 +52,7 @@ class AbstractProxyTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $this->proxy = new ConcreteProxy; + $this->proxy = new ConcreteProxy(); } protected function tearDown() @@ -33,37 +62,31 @@ protected function tearDown() public function testGetSaveHandlerName() { - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + $this->assertNull($this->proxy->getSaveHandlerName()); } public function testIsSessionHandlerInterface() { - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + $this->assertFalse($this->proxy->isSessionHandlerInterface()); + $sh = new ConcreteSessionHandlerInterfaceProxy(); + $this->assertTrue($sh->isSessionHandlerInterface()); } public function testIsWrapper() { - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + $this->assertFalse($this->proxy->isWrapper()); } public function testIsActive() { - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + $this->assertFalse($this->proxy->isActive()); } public function testSetActive() { - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + $this->proxy->setActive(true); + $this->assertTrue($this->proxy->isActive()); + $this->proxy->setActive(false); + $this->assertFalse($this->proxy->isActive()); } - } diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyPHP54Test.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyPHP54Test.php deleted file mode 100644 index f6c3d7aa755cd..0000000000000 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyPHP54Test.php +++ /dev/null @@ -1,30 +0,0 @@ -markTestSkipped('Test skipped, only for PHP 5.4'); - } - } - - /** - * @expectedException \InvalidArgumentException - */ - public function testConstructor() - { - $proxy = new NativeProxy(new NativeFileSessionHandler()); - $this->assertTrue($proxy->isWrapper()); - } -} diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyPHP53Test.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyTest.php similarity index 57% rename from tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyPHP53Test.php rename to tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyTest.php index b62ce8192bf42..0dc0ce92a3a56 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyPHP53Test.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/NativeProxyTest.php @@ -8,27 +8,20 @@ /** * Test class for NativeProxy. * - * @runTestsInSeparateProcesses + * @author Drak */ -class NativeProxyPHP53Test extends \PHPUnit_Framework_TestCase +class NativeProxyTest extends \PHPUnit_Framework_TestCase { - protected function setUp() - { - if (version_compare(phpversion(), '5.4.0', '>=')) { - $this->markTestSkipped('Test skipped, only for PHP 5.3'); - } - } - public function testIsWrapper() { - $proxy = new NativeProxy(new NativeFileSessionHandler()); + $proxy = new NativeProxy(); $this->assertFalse($proxy->isWrapper()); } public function testGetSaveHandlerName() { $name = ini_get('session.save_handler'); - $proxy = new NativeProxy(new NativeFileSessionHandler()); + $proxy = new NativeProxy(); $this->assertEquals($name, $proxy->getSaveHandlerName()); } } diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxyTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxyTest.php index fb7d36addaf36..61393f3102e0b 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxyTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxyTest.php @@ -3,68 +3,111 @@ namespace Symfony\Tests\Component\HttpFoundation\Session\Storage\Proxy; use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler; /** + * Tests for SessionHandlerProxy class. + * + * @author Drak + * * @runTestsInSeparateProcesses */ class SessionHandlerProxyTest extends \PHPUnit_Framework_TestCase { + /** + * @var PHPUnit_Framework_MockObject_Matcher + */ + private $mock; + /** * @var SessionHandlerProxy */ - protected $proxy; + private $proxy; protected function setUp() { - $this->proxy = new SessionHandlerProxy(new NullSessionHandler()); + $this->mock = $this->getMock('SessionHandlerInterface'); + $this->proxy = new SessionHandlerProxy($this->mock); } protected function tearDown() { + $this->mock = null; $this->proxy = null; } public function testOpen() { - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + $this->mock->expects($this->once()) + ->method('open') + ->will($this->returnValue(true)); + + $this->assertFalse($this->proxy->isActive()); + $this->proxy->open('name', 'id'); + $this->assertTrue($this->proxy->isActive()); + } + + public function testOpenFalse() + { + $this->mock->expects($this->once()) + ->method('open') + ->will($this->returnValue(false)); + + $this->assertFalse($this->proxy->isActive()); + $this->proxy->open('name', 'id'); + $this->assertFalse($this->proxy->isActive()); } public function testClose() { - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + $this->mock->expects($this->once()) + ->method('close') + ->will($this->returnValue(true)); + + $this->assertFalse($this->proxy->isActive()); + $this->proxy->close(); + $this->assertFalse($this->proxy->isActive()); + } + + public function testCloseFalse() + { + $this->mock->expects($this->once()) + ->method('close') + ->will($this->returnValue(false)); + + $this->assertFalse($this->proxy->isActive()); + $this->proxy->close(); + $this->assertFalse($this->proxy->isActive()); } public function testRead() { - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + $this->mock->expects($this->once()) + ->method('read'); + + $this->proxy->read('id'); } public function testWrite() { - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + $this->mock->expects($this->once()) + ->method('write'); + + $this->proxy->write('id', 'data'); } public function testDestroy() { - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + $this->mock->expects($this->once()) + ->method('destroy'); + + $this->proxy->destroy('id'); } public function testGc() { - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); - } + $this->mock->expects($this->once()) + ->method('gc'); + $this->proxy->gc(86400); + } } From 21221f7cf69cbeb2f42ffc16e6c07ea1e09a0a74 Mon Sep 17 00:00:00 2001 From: Drak Date: Wed, 7 Mar 2012 01:41:46 +0545 Subject: [PATCH 10/18] [FrameworkBundle] Make use of session API. --- .../FrameworkBundle/EventListener/TestSessionListener.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/EventListener/TestSessionListener.php b/src/Symfony/Bundle/FrameworkBundle/EventListener/TestSessionListener.php index d335758b70662..9010342d94ebe 100644 --- a/src/Symfony/Bundle/FrameworkBundle/EventListener/TestSessionListener.php +++ b/src/Symfony/Bundle/FrameworkBundle/EventListener/TestSessionListener.php @@ -72,7 +72,7 @@ public function onKernelResponse(FilterResponseEvent $event) $params = session_get_cookie_params(); - $event->getResponse()->headers->setCookie(new Cookie(session_name(), session_id(), 0 === $params['lifetime'] ? 0 : time() + $params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly'])); + $event->getResponse()->headers->setCookie(new Cookie(session_name(), $session->getId(), 0 === $params['lifetime'] ? 0 : time() + $params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly'])); } } From 39526df67c4bd8afe199a301734e556c8aa26b6b Mon Sep 17 00:00:00 2001 From: Drak Date: Thu, 8 Mar 2012 15:11:10 +0545 Subject: [PATCH 11/18] [HttpFoundation] Refactor away options property. It does not make sense to try and store session ini directives since they can be changes outside of the class as they are part of the global state. Coding stan --- .../Storage/MockArraySessionStorage.php | 18 ++++++- .../Session/Storage/SessionStorage.php | 51 ++++++++----------- 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php index 077fa0f14ef06..482f3b6c20737 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php @@ -76,7 +76,7 @@ public function start() */ public function regenerate($destroy = false) { - if ($this->options['auto_start'] && !$this->started) { + if (!$this->started) { $this->start(); } @@ -124,6 +124,22 @@ public function clear() $this->loadSession($this->sessionData); } + /** + * {@inheritdoc} + */ + public function getBag($name) + { + if (!isset($this->bags[$name])) { + throw new \InvalidArgumentException(sprintf('The SessionBagInterface %s is not registered.', $name)); + } + + if (!$this->started) { + $this->start(); + } + + return $this->bags[$name]; + } + /** * Generates a session ID. * diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php index f5a1578767f91..47a6044e87481 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php @@ -30,11 +30,6 @@ class SessionStorage implements SessionStorageInterface */ protected $bags; - /** - * @var array - */ - protected $options = array(); - /** * @var boolean */ @@ -93,6 +88,11 @@ class SessionStorage implements SessionStorageInterface */ public function __construct(array $options = array(), $handler = null) { + // sensible defaults + ini_set('session.auto_start', 0); // by default we prefer to explicitly start the session using the class. + ini_set('session.cache_limiter', ''); // disable by default because it's managed by HeaderBag (if used) + ini_set('session.use_cookies', 1); + $this->setOptions($options); $this->setSaveHandler($handler); } @@ -116,7 +116,15 @@ public function start() return true; } - if ($this->options['use_cookies'] && headers_sent()) { + // catch condition where session was started automatically by PHP + if (!$this->started && !$this->closed && $this->saveHandler->isActive() + && $this->saveHandler->isSessionHandlerInterface()) { + $this->loadSession(); + + return true; + } + + if (ini_get('session.use_cookies') && headers_sent()) { throw new \RuntimeException('Failed to start the session because headers have already been sent.'); } @@ -131,9 +139,6 @@ public function start() $this->saveHandler->setActive(false); } - $this->started = true; - $this->closed = false; - return true; } @@ -205,8 +210,10 @@ public function getBag($name) throw new \InvalidArgumentException(sprintf('The SessionBagInterface %s is not registered.', $name)); } - if ($this->options['auto_start'] && !$this->started) { + if (ini_get('session.auto_start') && !$this->started) { $this->start(); + } else if ($this->saveHandler->isActive() && !$this->started) { + $this->loadSession(); } return $this->bags[$name]; @@ -218,30 +225,13 @@ public function getBag($name) * For convenience we omit 'session.' from the beginning of the keys. * Explicitly ignores other ini keys. * - * session_get_cookie_params() overrides values. - * - * @param array $options + * @param array $options Session ini directives array(key => value). * * @see http://php.net/session.configuration */ public function setOptions(array $options) { - $this->options = $options; - - // set defaults for certain values - $defaults = array( - 'cache_limiter' => '', // disable by default because it's managed by HeaderBag (if used) - 'auto_start' => false, - 'use_cookies' => true, - ); - - foreach ($defaults as $key => $value) { - if (!isset($this->options[$key])) { - $this->options[$key] = $value; - } - } - - foreach ($this->options as $key => $value) { + foreach ($options as $key => $value) { if (in_array($key, array( 'auto_start', 'cache_limiter', 'cookie_domain', 'cookie_httponly', 'cookie_lifetime', 'cookie_path', 'cookie_secure', @@ -322,5 +312,8 @@ protected function loadSession(array &$session = null) $session[$key] = isset($session[$key]) ? $session[$key] : array(); $bag->initialize($session[$key]); } + + $this->started = true; + $this->closed = false; } } From 7b36d0cc2b4a91dc624fadad96ee7f51a9a921e9 Mon Sep 17 00:00:00 2001 From: Drak Date: Fri, 9 Mar 2012 13:31:44 +0545 Subject: [PATCH 12/18] [DoctrineBridge][HttpFoundation] Refactored tests. --- ...nStorageTest.php => DbalSessionHandlerTest.php} | 6 +++--- .../PdoSessionHandlerTest.php} | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) rename tests/Symfony/Tests/Bridge/Doctrine/HttpFoundation/{DbalSessionStorageTest.php => DbalSessionHandlerTest.php} (80%) rename tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/{PdoSessionStorageTest.php => Handler/PdoSessionHandlerTest.php} (79%) diff --git a/tests/Symfony/Tests/Bridge/Doctrine/HttpFoundation/DbalSessionStorageTest.php b/tests/Symfony/Tests/Bridge/Doctrine/HttpFoundation/DbalSessionHandlerTest.php similarity index 80% rename from tests/Symfony/Tests/Bridge/Doctrine/HttpFoundation/DbalSessionStorageTest.php rename to tests/Symfony/Tests/Bridge/Doctrine/HttpFoundation/DbalSessionHandlerTest.php index 428f065c1a2c5..eda2dac30d196 100644 --- a/tests/Symfony/Tests/Bridge/Doctrine/HttpFoundation/DbalSessionStorageTest.php +++ b/tests/Symfony/Tests/Bridge/Doctrine/HttpFoundation/DbalSessionHandlerTest.php @@ -11,19 +11,19 @@ namespace Symfony\Bridge\Doctrine\HttpFoundation; -use Symfony\Bridge\Doctrine\HttpFoundation\DbalSessionStorage; +use Symfony\Bridge\Doctrine\HttpFoundation\DbalSessionHandler; /** * Test class for DbalSessionStorage. * * @author Drak */ -class DbalSessionStorageTest extends \PHPUnit_Framework_TestCase +class DbalSessionHandlerTest extends \PHPUnit_Framework_TestCase { public function test__Construct() { $this->connection = $this->getMock('Doctrine\DBAL\Driver\Connection'); - $mock = $this->getMockBuilder('Symfony\Bridge\Doctrine\HttpFoundation\DbalSessionStorage'); + $mock = $this->getMockBuilder('Symfony\Bridge\Doctrine\HttpFoundation\DbalSessionHandler'); $mock->setConstructorArgs(array($this->connection)); $this->driver = $mock->getMock(); } diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/PdoSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandlerTest.php similarity index 79% rename from tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/PdoSessionStorageTest.php rename to tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandlerTest.php index 6a6fd6760a8ed..8f921334ae52c 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/PdoSessionStorageTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandlerTest.php @@ -9,11 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\Tests\Component\HttpFoundation\Session\Storage; +namespace Symfony\Tests\Component\HttpFoundation\Session\Storage\Handler; -use Symfony\Component\HttpFoundation\Session\Storage\PdoSessionStorage; +use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; -class PdoSessionStorageTest extends \PHPUnit_Framework_TestCase +class PdoSessionHandlerTest extends \PHPUnit_Framework_TestCase { private $pdo; @@ -26,16 +26,16 @@ protected function setUp() public function testMultipleInstances() { - $storage1 = new PdoSessionStorage($this->pdo, array('db_table' => 'sessions'), array()); + $storage1 = new PdoSessionHandler($this->pdo, array('db_table' => 'sessions'), array()); $storage1->write('foo', 'bar'); - $storage2 = new PdoSessionStorage($this->pdo, array('db_table' => 'sessions'), array()); + $storage2 = new PdoSessionHandler($this->pdo, array('db_table' => 'sessions'), array()); $this->assertEquals('bar', $storage2->read('foo'), 'values persist between instances'); } public function testSessionDestroy() { - $storage = new PdoSessionStorage($this->pdo, array('db_table' => 'sessions'), array()); + $storage = new PdoSessionHandler($this->pdo, array('db_table' => 'sessions'), array()); $storage->write('foo', 'bar'); $this->assertEquals(1, count($this->pdo->query('SELECT * FROM sessions')->fetchAll())); @@ -46,7 +46,7 @@ public function testSessionDestroy() public function testSessionGC() { - $storage = new PdoSessionStorage($this->pdo, array('db_table' => 'sessions'), array()); + $storage = new PdoSessionHandler($this->pdo, array('db_table' => 'sessions'), array()); $storage->write('foo', 'bar'); $storage->write('baz', 'bar'); From d6878011420e36d299bd4fc365c135ff67a2fcbe Mon Sep 17 00:00:00 2001 From: Drak Date: Wed, 14 Mar 2012 17:40:25 +0545 Subject: [PATCH 13/18] [HttpKernel] Mock must invoke constructor. --- .../Component/HttpKernel/EventListener/LocaleListenerTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Symfony/Tests/Component/HttpKernel/EventListener/LocaleListenerTest.php b/tests/Symfony/Tests/Component/HttpKernel/EventListener/LocaleListenerTest.php index ecce76ec5eef4..d8cac3857c896 100644 --- a/tests/Symfony/Tests/Component/HttpKernel/EventListener/LocaleListenerTest.php +++ b/tests/Symfony/Tests/Component/HttpKernel/EventListener/LocaleListenerTest.php @@ -33,7 +33,7 @@ public function testDefaultLocaleWithSession() session_name('foo'); $request->cookies->set('foo', 'value'); - $session = $this->getMock('Symfony\Component\HttpFoundation\Session\Session', array('get'), array(), '', false); + $session = $this->getMock('Symfony\Component\HttpFoundation\Session\Session', array('get'), array(), '', true); $session->expects($this->once())->method('get')->will($this->returnValue('es')); $request->setSession($session); @@ -55,7 +55,7 @@ public function testLocaleFromRequestAttribute() $event = $this->getEvent($request); // also updates the session _locale value - $session = $this->getMock('Symfony\Component\HttpFoundation\Session\Session', array('set', 'get'), array(), '', false); + $session = $this->getMock('Symfony\Component\HttpFoundation\Session\Session', array('set', 'get'), array(), '', true); $session->expects($this->once())->method('set')->with('_locale', 'es'); $session->expects($this->once())->method('get')->with('_locale')->will($this->returnValue('es')); $request->setSession($session); From b12ece0ff715a423e0f293f2648f3aa4bc55e445 Mon Sep 17 00:00:00 2001 From: Drak Date: Wed, 14 Mar 2012 17:38:34 +0545 Subject: [PATCH 14/18] [HttpFoundation][FrameworkBundle] Separate out mock session storage and stop polluting global namespace. This makes mock sessions truly mock and not to interfere with global namespace. Add getters and setters for session name and ID. --- .../EventListener/SessionListener.php | 7 ++ .../EventListener/TestSessionListener.php | 13 ++- .../EventListener/TestSessionListenerTest.php | 7 +- .../Component/HttpFoundation/Request.php | 3 +- .../HttpFoundation/Session/Session.php | 33 +++++- .../Session/SessionInterface.php | 36 ++++++ .../Handler/NativeFileSessionHandler.php | 2 +- .../Storage/MockArraySessionStorage.php | 106 ++++++++++++++---- .../Storage/MockFileSessionStorage.php | 50 ++++----- .../Session/Storage/Proxy/AbstractProxy.php | 48 ++++++++ .../Session/Storage/SessionStorage.php | 36 +++++- .../Storage/SessionStorageInterface.php | 32 +++++- .../Component/HttpFoundation/RequestTest.php | 6 +- .../Handler/NativeFileSessionHandlerTest.php | 2 +- .../Storage/MockFileSessionStorageTest.php | 7 +- 15 files changed, 312 insertions(+), 76 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/EventListener/SessionListener.php b/src/Symfony/Bundle/FrameworkBundle/EventListener/SessionListener.php index 83fdec4b7400a..ad396347d51e5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/EventListener/SessionListener.php +++ b/src/Symfony/Bundle/FrameworkBundle/EventListener/SessionListener.php @@ -28,7 +28,14 @@ */ class SessionListener implements EventSubscriberInterface { + /** + * @var ContainerInterface + */ private $container; + + /** + * @var boolean + */ private $autoStart; public function __construct(ContainerInterface $container, $autoStart = false) diff --git a/src/Symfony/Bundle/FrameworkBundle/EventListener/TestSessionListener.php b/src/Symfony/Bundle/FrameworkBundle/EventListener/TestSessionListener.php index 9010342d94ebe..8f4536de8e9b5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/EventListener/TestSessionListener.php +++ b/src/Symfony/Bundle/FrameworkBundle/EventListener/TestSessionListener.php @@ -43,15 +43,16 @@ public function onKernelRequest(GetResponseEvent $event) } // bootstrap the session - if ($this->container->has('session')) { - $this->container->get('session'); + if (!$this->container->has('session')) { + return; } + $session = $this->container->get('session'); $cookies = $event->getRequest()->cookies; - if ($cookies->has(session_name())) { - session_id($cookies->get(session_name())); + if ($cookies->has($session->getName())) { + $session->setId($cookies->get($session->getName())); } else { - session_id(''); + $session->setId(''); } } @@ -72,7 +73,7 @@ public function onKernelResponse(FilterResponseEvent $event) $params = session_get_cookie_params(); - $event->getResponse()->headers->setCookie(new Cookie(session_name(), $session->getId(), 0 === $params['lifetime'] ? 0 : time() + $params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly'])); + $event->getResponse()->headers->setCookie(new Cookie($session->getName(), $session->getId(), 0 === $params['lifetime'] ? 0 : time() + $params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly'])); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/EventListener/TestSessionListenerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/EventListener/TestSessionListenerTest.php index fe551ba360aa7..4c577f292f21e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/EventListener/TestSessionListenerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/EventListener/TestSessionListenerTest.php @@ -94,8 +94,13 @@ private function sessionMustBeSaved() private function getSession() { - return $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\Session') + $mock = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\Session') ->disableOriginalConstructor() ->getMock(); + + // set return value for getName() + $mock->expects($this->any())->method('getName')->will($this->returnValue('MOCKSESSID')); + + return $mock; } } diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index f38b1e7d0f084..eaa453e1b472e 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -496,7 +496,8 @@ public function getSession() public function hasPreviousSession() { // the check for $this->session avoids malicious users trying to fake a session cookie with proper name - return $this->cookies->has(session_name()) && null !== $this->session; + $sessionName = $this->hasSession() ? $this->session->getName() : null; + return $this->cookies->has($sessionName) && $this->hasSession(); } /** diff --git a/src/Symfony/Component/HttpFoundation/Session/Session.php b/src/Symfony/Component/HttpFoundation/Session/Session.php index 6f2c6a4262a02..9f2e3326e8a79 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Session.php +++ b/src/Symfony/Component/HttpFoundation/Session/Session.php @@ -17,6 +17,7 @@ use Symfony\Component\HttpFoundation\Session\Flash\FlashBag; use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; use Symfony\Component\HttpFoundation\Session\SessionBagInterface; +use Symfony\Component\HttpFoundation\Session\Storage\SessionStorage; /** * Session. @@ -140,11 +141,7 @@ public function save() } /** - * Returns the session ID - * - * @return mixed The session ID - * - * @api + * {@inheritdoc} */ public function getId() { @@ -152,7 +149,31 @@ public function getId() } /** - * Registers a SessionBagInterface with the sessio. + * {@inheritdoc} + */ + public function setId($id) + { + $this->storage->setId($id); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return $this->storage->getName(); + } + + /** + * {@inheritdoc} + */ + public function setName($name) + { + $this->storage->setName($name); + } + + /** + * Registers a SessionBagInterface with the session. * * @param SessionBagInterface $bag */ diff --git a/src/Symfony/Component/HttpFoundation/Session/SessionInterface.php b/src/Symfony/Component/HttpFoundation/Session/SessionInterface.php index 741969b10ec84..4e4962de4ee39 100644 --- a/src/Symfony/Component/HttpFoundation/Session/SessionInterface.php +++ b/src/Symfony/Component/HttpFoundation/Session/SessionInterface.php @@ -29,6 +29,42 @@ interface SessionInterface */ function start(); + /** + * Returns the session ID. + * + * @return string The session ID. + * + * @api + */ + function getId(); + + /** + * Sets the session ID + * + * @param string $id + * + * @api + */ + function setId($id); + + /** + * Returns the session name. + * + * @return mixed The session name. + * + * @api + */ + function getName(); + + /** + * Sets the session name. + * + * @param string $name + * + * @api + */ + function setName($name); + /** * Invalidates the current session. * diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandler.php index 5acf004d15020..202d8d0f900ee 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandler.php @@ -12,7 +12,7 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; /** - * NativeFileSessionStorage. + * NativeFileSessionHandler. * * Native session handler using PHP's built in file storage. * diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php index 482f3b6c20737..6f1e279f41654 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php @@ -11,7 +11,7 @@ namespace Symfony\Component\HttpFoundation\Session\Storage; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler; +use Symfony\Component\HttpFoundation\Session\SessionBagInterface; /** * MockArraySessionStorage mocks the session for unit tests. @@ -25,21 +25,41 @@ * @author Bulat Shakirzyanov * @author Drak */ -class MockArraySessionStorage extends SessionStorage +class MockArraySessionStorage implements SessionStorageInterface { /** * @var string */ - protected $sessionId; + protected $id = ''; + + /** + * @var string + */ + protected $name; + + /** + * @var boolean + */ + protected $started = false; + + /** + * @var boolean + */ + protected $closed = false; /** * @var array */ - protected $sessionData = array(); + protected $data = array(); - public function __construct(array $options = array()) + /** + * Constructor. + * + * @param string $name Session name + */ + public function __construct($name = 'MOCKSESSID') { - parent::__construct($options, new NullSessionHandler()); + $this->name = $name; } /** @@ -49,7 +69,7 @@ public function __construct(array $options = array()) */ public function setSessionData(array $array) { - $this->sessionData = $array; + $this->data = $array; } /** @@ -61,11 +81,11 @@ public function start() return true; } - $this->started = true; - $this->loadSession($this->sessionData); + if (empty($this->id)) { + $this->id = $this->generateId(); + } - $this->sessionId = $this->generateSessionId(); - session_id($this->sessionId); + $this->loadSession(); return true; } @@ -80,8 +100,7 @@ public function regenerate($destroy = false) $this->start(); } - $this->sessionId = $this->generateSessionId(); - session_id($this->sessionId); + $this->id = $this->generateId(); return true; } @@ -91,11 +110,35 @@ public function regenerate($destroy = false) */ public function getId() { - if (!$this->started) { - return ''; + return $this->id; + } + + /** + * {@inheritdoc} + */ + public function setId($id) + { + if ($this->started) { + throw new \LogicException('Cannot set session ID after the session has started.'); } - return $this->sessionId; + $this->id = $id; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return $this->name; + } + + /** + * {@inheritdoc} + */ + public function setName($name) + { + $this->name = $name; } /** @@ -118,10 +161,18 @@ public function clear() } // clear out the session - $this->sessionData = array(); + $this->data = array(); // reconnect the bags to the session - $this->loadSession($this->sessionData); + $this->loadSession(); + } + + /** + * {@inheritdoc} + */ + public function registerBag(SessionBagInterface $bag) + { + $this->bags[$bag->getName()] = $bag; } /** @@ -143,10 +194,25 @@ public function getBag($name) /** * Generates a session ID. * + * This doesn't need to be particularly cryptographically secure since this is just + * a mock. + * * @return string */ - protected function generateSessionId() + protected function generateId() + { + return sha1(uniqid(mt_rand())); + } + + protected function loadSession() { - return sha1(uniqid(mt_rand(), true)); + foreach ($this->bags as $bag) { + $key = $bag->getStorageKey(); + $this->data[$key] = isset($this->data[$key]) ? $this->data[$key] : array(); + $bag->initialize($this->data[$key]); + } + + $this->started = true; + $this->closed = false; } } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php index 184f76e747cff..24457319f9d62 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php @@ -16,7 +16,9 @@ * functional testing when done in a single PHP process. * * No PHP session is actually started since a session can be initialized - * and shutdown only once per PHP execution cycle. + * and shutdown only once per PHP execution cycle and this class does + * not pollute any session related globals, including session_*() functions + * or session.* PHP ini directives. * * @author Drak */ @@ -31,11 +33,9 @@ class MockFileSessionStorage extends MockArraySessionStorage * Constructor. * * @param string $savePath Path of directory to save session files. - * @param array $options Session options. - * - * @see SessionStorage::__construct() + * @param string $name Session name. */ - public function __construct($savePath = null, array $options = array()) + public function __construct($savePath = null, $name = 'MOCKSESSID') { if (null === $savePath) { $savePath = sys_get_temp_dir(); @@ -47,7 +47,7 @@ public function __construct($savePath = null, array $options = array()) $this->savePath = $savePath; - parent::__construct($options); + parent::__construct($name); } /** @@ -59,12 +59,10 @@ public function start() return true; } - if (!session_id()) { - session_id($this->generateSessionId()); + if (!$this->id) { + $this->id = $this->generateId(); } - $this->sessionId = session_id(); - $this->read(); $this->started = true; @@ -81,10 +79,7 @@ public function regenerate($destroy = false) $this->destroy(); } - session_id($this->generateSessionId()); - $this->sessionId = session_id(); - - $this->save(); + $this->id = $this->generateId(); return true; } @@ -92,23 +87,15 @@ public function regenerate($destroy = false) /** * {@inheritdoc} */ - public function getId() + public function save() { - if (!$this->started) { - return ''; - } - - return $this->sessionId; + file_put_contents($this->getFilePath(), serialize($this->data)); } /** - * {@inheritdoc} + * Deletes a session from persistent storage. + * Deliberately leaves session data in memory intact. */ - public function save() - { - file_put_contents($this->getFilePath(), serialize($this->sessionData)); - } - private function destroy() { if (is_file($this->getFilePath())) { @@ -121,16 +108,19 @@ private function destroy() * * @return string File path */ - public function getFilePath() + private function getFilePath() { - return $this->savePath.'/'.$this->sessionId.'.sess'; + return $this->savePath.'/'.$this->id.'.mocksess'; } + /** + * Reads session from storage and loads session. + */ private function read() { $filePath = $this->getFilePath(); - $this->sessionData = is_readable($filePath) && is_file($filePath) ? unserialize(file_get_contents($filePath)) : array(); + $this->data = is_readable($filePath) && is_file($filePath) ? unserialize(file_get_contents($filePath)) : array(); - $this->loadSession($this->sessionData); + $this->loadSession(); } } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php index 0cd4d73d96a58..09f9efa091dc7 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php @@ -84,4 +84,52 @@ public function setActive($flag) { $this->active = (bool) $flag; } + + /** + * Gets the session ID. + * + * @return string + */ + public function getId() + { + return session_id(); + } + + /** + * Sets the session ID. + * + * @param string $id + */ + public function setId($id) + { + if ($this->isActive()) { + throw new \LogicException('Cannot change the ID of an active session'); + } + + session_id($id); + } + + /** + * Gets the session name. + * + * @return string + */ + public function getName() + { + return session_name(); + } + + /** + * Sets the session name. + * + * @param string $name + */ + public function setName($name) + { + if ($this->isActive()) { + throw new \LogicException('Cannot change the name of an active session'); + } + + session_name($name); + } } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php index 47a6044e87481..194318aa2ec16 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php @@ -93,6 +93,12 @@ public function __construct(array $options = array(), $handler = null) ini_set('session.cache_limiter', ''); // disable by default because it's managed by HeaderBag (if used) ini_set('session.use_cookies', 1); + if (version_compare(phpversion(), '5.4.0', '>=')) { + session_register_shutdown(); + } else { + register_shutdown_function('session_write_close'); + } + $this->setOptions($options); $this->setSaveHandler($handler); } @@ -151,7 +157,31 @@ public function getId() return ''; // returning empty is consistent with session_id() behaviour } - return session_id(); + return $this->saveHandler->getId(); + } + + /** + * {@inheritdoc} + */ + public function setId($id) + { + return $this->saveHandler->setId($id); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return $this->saveHandler->getName(); + } + + /** + * {@inheritdoc} + */ + public function setName($name) + { + $this->saveHandler->setName($name); } /** @@ -275,7 +305,7 @@ public function setSaveHandler($saveHandler = null) if ($this->saveHandler instanceof \SessionHandlerInterface) { if (version_compare(phpversion(), '5.4.0', '>=')) { - session_set_save_handler($this->saveHandler, true); + session_set_save_handler($this->saveHandler, false); } else { session_set_save_handler( array($this->saveHandler, 'open'), @@ -285,8 +315,6 @@ public function setSaveHandler($saveHandler = null) array($this->saveHandler, 'destroy'), array($this->saveHandler, 'gc') ); - - register_shutdown_function('session_write_close'); } } } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorageInterface.php b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorageInterface.php index 6065a550dc8c3..8bf2e5d32ad02 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorageInterface.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorageInterface.php @@ -37,12 +37,39 @@ function start(); /** * Returns the session ID * - * @return mixed The session ID or false if the session has not started. + * @return string The session ID or empty. * * @api */ function getId(); + /** + * Sets the session ID + * + * @param string $id + * + * @api + */ + function setId($id); + + /** + * Returns the session name + * + * @return mixed The session name. + * + * @api + */ + function getName(); + + /** + * Sets the session name + * + * @param string $name + * + * @api + */ + function setName($name); + /** * Regenerates id that represents this storage. * @@ -51,6 +78,9 @@ function getId(); * or functional testing where a real PHP session would interfere * with testing. * + * Note regenerate+destroy should not clear the session data in memory + * only delete the session data from persistent storage. + * * @param Boolean $destroy Destroy session when regenerating? * * @return Boolean True if session regenerated, false if error diff --git a/tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php b/tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php index 3e672da273dde..136b8fc95be65 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php @@ -866,7 +866,7 @@ public function testForwardedSecure() public function testHasSession() { - $request = new Request; + $request = new Request(); $this->assertFalse($request->hasSession()); $request->setSession(new Session(new MockArraySessionStorage())); @@ -875,10 +875,10 @@ public function testHasSession() public function testHasPreviousSession() { - $request = new Request; + $request = new Request(); $this->assertFalse($request->hasPreviousSession()); - $request->cookies->set(session_name(), 'foo'); + $request->cookies->set('MOCKSESSID', 'foo'); $this->assertFalse($request->hasPreviousSession()); $request->setSession(new Session(new MockArraySessionStorage())); $this->assertTrue($request->hasPreviousSession()); diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandlerTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandlerTest.php index 08b8644ebfd76..37eb40cbe9c08 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandlerTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandlerTest.php @@ -6,7 +6,7 @@ use Symfony\Component\HttpFoundation\Session\Storage\SessionStorage; /** - * Test class for NativeFileSessionStorage. + * Test class for NativeFileSessionHandler. * * @author Drak * diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MockFileSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MockFileSessionStorageTest.php index 770bcda8f00ec..c0453df9779c4 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MockFileSessionStorageTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MockFileSessionStorageTest.php @@ -69,6 +69,7 @@ public function testGetId() public function testSave() { $this->storage->start(); + $id = $this->storage->getId(); $this->assertNotEquals('108', $this->storage->getBag('attributes')->get('new')); $this->assertFalse($this->storage->getBag('flashes')->has('newkey')); $this->storage->getBag('attributes')->set('new', '108'); @@ -76,6 +77,7 @@ public function testSave() $this->storage->save(); $storage = $this->getStorage(); + $storage->setId($id); $storage->start(); $this->assertEquals('108', $storage->getBag('attributes')->get('new')); $this->assertTrue($storage->getBag('flashes')->has('newkey')); @@ -90,13 +92,14 @@ public function testMultipleInstances() $storage1->save(); $storage2 = $this->getStorage(); + $storage2->setId($storage1->getId()); $storage2->start(); $this->assertEquals('bar', $storage2->getBag('attributes')->get('foo'), 'values persist between instances'); } - private function getStorage(array $options = array()) + private function getStorage() { - $storage = new MockFileSessionStorage($this->sessionDir, $options); + $storage = new MockFileSessionStorage($this->sessionDir); $storage->registerBag(new FlashBag); $storage->registerBag(new AttributeBag); From 7f33b33aa6abcc1c1cdeb3aff3d9d368b2eef5e6 Mon Sep 17 00:00:00 2001 From: Drak Date: Wed, 14 Mar 2012 20:59:09 +0545 Subject: [PATCH 15/18] Refactor SessionStorage to NativeSessionStorage. Native here refers to the fact the session storage interacts with real PHP sessions. --- .../DependencyInjection/FrameworkExtension.php | 2 +- .../FrameworkBundle/Resources/config/session.xml | 2 +- .../Component/HttpFoundation/Session/Session.php | 4 ++-- .../{SessionStorage.php => NativeSessionStorage.php} | 2 +- .../Storage/Handler/NativeFileSessionHandlerTest.php | 6 +++--- .../Handler/NativeMemcacheSessionHandlerTest.php | 4 ++-- .../Handler/NativeMemcachedSessionHandlerTest.php | 4 ++-- .../Handler/NativeSqliteSessionHandlerTest.php | 4 ++-- .../Storage/Handler/NullSessionHandlerTest.php | 4 ++-- ...nStorageTest.php => NativeSessionStorageTest.php} | 12 ++++++------ 10 files changed, 22 insertions(+), 22 deletions(-) rename src/Symfony/Component/HttpFoundation/Session/Storage/{SessionStorage.php => NativeSessionStorage.php} (99%) rename tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/{SessionStorageTest.php => NativeSessionStorageTest.php} (92%) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 7a7999d4a2f04..8c91c37a4e3b4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -316,7 +316,7 @@ private function registerSessionConfiguration(array $config, ContainerBuilder $c $this->addClassesToCompile(array( 'Symfony\\Bundle\\FrameworkBundle\\EventListener\\SessionListener', 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorageInterface', - 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorage', + 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorage', 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\NativeSessionHandler', 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\Proxy\AbstractProxy', 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\Proxy\SessionHandlerProxy', diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml index 3b985be216685..7392d26a1734c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml @@ -8,7 +8,7 @@ Symfony\Component\HttpFoundation\Session\Session Symfony\Component\HttpFoundation\Session\Flash\AutoExpireFlashBag Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag - Symfony\Component\HttpFoundation\Session\Storage\SessionStorage + Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler Symfony\Bundle\FrameworkBundle\EventListener\SessionListener diff --git a/src/Symfony/Component/HttpFoundation/Session/Session.php b/src/Symfony/Component/HttpFoundation/Session/Session.php index 9f2e3326e8a79..0f507fc4ce424 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Session.php +++ b/src/Symfony/Component/HttpFoundation/Session/Session.php @@ -17,7 +17,7 @@ use Symfony\Component\HttpFoundation\Session\Flash\FlashBag; use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; use Symfony\Component\HttpFoundation\Session\SessionBagInterface; -use Symfony\Component\HttpFoundation\Session\Storage\SessionStorage; +use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; /** * Session. @@ -45,7 +45,7 @@ class Session implements SessionInterface */ public function __construct(SessionStorageInterface $storage = null, AttributeBagInterface $attributes = null, FlashBagInterface $flashes = null) { - $this->storage = $storage ?: new SessionStorage(); + $this->storage = $storage ?: new NativeSessionStorage(); $this->registerBag($attributes ?: new AttributeBag()); $this->registerBag($flashes ?: new FlashBag()); } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php similarity index 99% rename from src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php rename to src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php index 194318aa2ec16..be6904ed66acb 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php @@ -21,7 +21,7 @@ * * @author Drak */ -class SessionStorage implements SessionStorageInterface +class NativeSessionStorage implements SessionStorageInterface { /** * Array of SessionBagInterface diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandlerTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandlerTest.php index 37eb40cbe9c08..c6a4495225d3b 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandlerTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandlerTest.php @@ -3,7 +3,7 @@ namespace Symfony\Tests\Component\HttpFoundation\Session\Storage\Handler; use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler; -use Symfony\Component\HttpFoundation\Session\Storage\SessionStorage; +use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; /** * Test class for NativeFileSessionHandler. @@ -16,7 +16,7 @@ class NativeFileSessionHandlerTest extends \PHPUnit_Framework_TestCase { public function testConstruct() { - $storage = new SessionStorage(array('name' => 'TESTING'), new NativeFileSessionHandler(sys_get_temp_dir())); + $storage = new NativeSessionStorage(array('name' => 'TESTING'), new NativeFileSessionHandler(sys_get_temp_dir())); if (version_compare(phpversion(), '5.4.0', '<')) { $this->assertEquals('files', $storage->getSaveHandler()->getSaveHandlerName()); @@ -33,7 +33,7 @@ public function testConstruct() public function testConstructDefault() { $path = ini_get('session.save_path'); - $storage = new SessionStorage(array('name' => 'TESTING'), new NativeFileSessionHandler()); + $storage = new NativeSessionStorage(array('name' => 'TESTING'), new NativeFileSessionHandler()); $this->assertEquals($path, ini_get('session.save_path')); } diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeMemcacheSessionHandlerTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeMemcacheSessionHandlerTest.php index 377fe1754c625..3dbcb4f7f81ba 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeMemcacheSessionHandlerTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeMemcacheSessionHandlerTest.php @@ -3,7 +3,7 @@ namespace Symfony\Tests\Component\HttpFoundation\Session\Storage\Handler; use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeMemcacheSessionHandler; -use Symfony\Component\HttpFoundation\Session\Storage\SessionStorage; +use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; /** * Test class for NativeMemcacheSessionHandler. @@ -20,7 +20,7 @@ public function testSaveHandlers() $this->markTestSkipped('Skipped tests SQLite extension is not present'); } - $storage = new SessionStorage(array('name' => 'TESTING'), new NativeMemcacheSessionHandler('tcp://127.0.0.1:11211?persistent=0')); + $storage = new NativeSessionStorage(array('name' => 'TESTING'), new NativeMemcacheSessionHandler('tcp://127.0.0.1:11211?persistent=0')); if (version_compare(phpversion(), '5.4.0', '<')) { $this->assertEquals('memcache', $storage->getSaveHandler()->getSaveHandlerName()); diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeMemcachedSessionHandlerTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeMemcachedSessionHandlerTest.php index f4ae96c6e2d0e..a85fbdd056f4c 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeMemcachedSessionHandlerTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeMemcachedSessionHandlerTest.php @@ -3,7 +3,7 @@ namespace Symfony\Tests\Component\HttpFoundation\Session\Storage\Handler; use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeMemcachedSessionHandler; -use Symfony\Component\HttpFoundation\Session\Storage\SessionStorage; +use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; /** * Test class for NativeMemcachedSessionHandler. @@ -23,7 +23,7 @@ public function testSaveHandlers() // test takes too long if memcached server is not running ini_set('memcached.sess_locking', '0'); - $storage = new SessionStorage(array('name' => 'TESTING'), new NativeMemcachedSessionHandler('127.0.0.1:11211')); + $storage = new NativeSessionStorage(array('name' => 'TESTING'), new NativeMemcachedSessionHandler('127.0.0.1:11211')); if (version_compare(phpversion(), '5.4.0', '<')) { $this->assertEquals('memcached', $storage->getSaveHandler()->getSaveHandlerName()); diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeSqliteSessionHandlerTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeSqliteSessionHandlerTest.php index 373b0e8a491c8..9867e49590edd 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeSqliteSessionHandlerTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NativeSqliteSessionHandlerTest.php @@ -3,7 +3,7 @@ namespace Symfony\Tests\Component\HttpFoundation\Session\Storage\Handler; use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSqliteSessionHandler; -use Symfony\Component\HttpFoundation\Session\Storage\SessionStorage; +use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; /** * Test class for NativeSqliteSessionStorage. @@ -20,7 +20,7 @@ public function testSaveHandlers() $this->markTestSkipped('Skipped tests SQLite extension is not present'); } - $storage = new SessionStorage(array('name' => 'TESTING'), new NativeSqliteSessionHandler(sys_get_temp_dir().'/sqlite.db')); + $storage = new NativeSessionStorage(array('name' => 'TESTING'), new NativeSqliteSessionHandler(sys_get_temp_dir().'/sqlite.db')); if (version_compare(phpversion(), '5.4.0', '<')) { $this->assertEquals('sqlite', $storage->getSaveHandler()->getSaveHandlerName()); diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandlerTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandlerTest.php index 289aa9c85cd13..e0c883e7c3f40 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandlerTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandlerTest.php @@ -2,7 +2,7 @@ namespace Symfony\Tests\Component\HttpFoundation\Session\Storage\Handler; use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler; -use Symfony\Component\HttpFoundation\Session\Storage\SessionStorage; +use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; use Symfony\Component\HttpFoundation\Session\Session; /** @@ -42,7 +42,7 @@ public function testNothingIsPersisted() public function getStorage() { - return new SessionStorage(array(), new NullSessionHandler()); + return new NativeSessionStorage(array(), new NullSessionHandler()); } } diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/SessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeSessionStorageTest.php similarity index 92% rename from tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/SessionStorageTest.php rename to tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeSessionStorageTest.php index c05d5730fffcc..26f6113448011 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/SessionStorageTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeSessionStorageTest.php @@ -2,7 +2,7 @@ namespace Symfony\Tests\Component\HttpFoundation\Session\Storage; -use Symfony\Component\HttpFoundation\Session\Storage\SessionStorage; +use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler; use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler; use Symfony\Component\HttpFoundation\Session\Flash\FlashBag; @@ -17,14 +17,14 @@ * * @runTestsInSeparateProcesses */ -class SessionStorageTest extends \PHPUnit_Framework_TestCase +class NativeSessionStorageTest extends \PHPUnit_Framework_TestCase { /** - * @return AbstractSessionStorage + * @return NativeSessionStorage */ protected function getStorage(array $options = array()) { - $storage = new SessionStorage($options); + $storage = new NativeSessionStorage($options); $storage->registerBag(new AttributeBag); return $storage; @@ -82,7 +82,7 @@ public function testDefaultSessionCacheLimiter() { ini_set('session.cache_limiter', 'nocache'); - $storage = new SessionStorage(); + $storage = new NativeSessionStorage(); $this->assertEquals('', ini_get('session.cache_limiter')); } @@ -90,7 +90,7 @@ public function testExplicitSessionCacheLimiter() { ini_set('session.cache_limiter', 'nocache'); - $storage = new SessionStorage(array('cache_limiter' => 'public')); + $storage = new NativeSessionStorage(array('cache_limiter' => 'public')); $this->assertEquals('public', ini_get('session.cache_limiter')); } From 68074a2be07f0c6ed38f71e40558266a6ae2bd98 Mon Sep 17 00:00:00 2001 From: Drak Date: Wed, 7 Mar 2012 01:26:09 +0545 Subject: [PATCH 16/18] Changelog and upgrading changes. --- CHANGELOG-2.1.md | 83 ++++++++++++++++++++++++++++++------------------ UPGRADE-2.1.md | 27 ++++++++++++---- 2 files changed, 73 insertions(+), 37 deletions(-) diff --git a/CHANGELOG-2.1.md b/CHANGELOG-2.1.md index 5214648ee2358..cf9c8c20a7edf 100644 --- a/CHANGELOG-2.1.md +++ b/CHANGELOG-2.1.md @@ -27,8 +27,10 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c ### DoctrineBundle * This bundle has been moved to the Doctrine organization - * added optional `group_by` property to `EntityType` that supports either a `PropertyPath` or a `\Closure` that is evaluated on the entity choices - * The `em` option for the `UniqueEntity` constraint is now optional (and should probably not be used anymore). + * added optional `group_by` property to `EntityType` that supports either a + `PropertyPath` or a `\Closure` that is evaluated on the entity choices + * The `em` option for the `UniqueEntity` constraint is now optional (and should + probably not be used anymore). ### FrameworkBundle @@ -39,13 +41,17 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c * added Controller::getUser() * [BC BREAK] assets_base_urls and base_urls merging strategy has changed * changed the default profiler storage to use the filesystem instead of SQLite - * added support for placeholders in route defaults and requirements (replaced by the value set in the service container) + * added support for placeholders in route defaults and requirements (replaced + by the value set in the service container) * added Filesystem component as a dependency * added support for hinclude (use ``standalone: 'js'`` in render tag) * session options: lifetime, path, domain, secure, httponly were deprecated. - Prefixed versions should now be used instead: cookie_lifetime, cookie_path, cookie_domain, cookie_secure, cookie_httponly - * [BC BREAK] following session options: 'lifetime', 'path', 'domain', 'secure', 'httponly' - are now prefixed with cookie_ when dumped to the container + Prefixed versions should now be used instead: cookie_lifetime, cookie_path, + cookie_domain, cookie_secure, cookie_httponly + * [BC BREAK] following session options: 'lifetime', 'path', 'domain', 'secure', + 'httponly' are now prefixed with cookie_ when dumped to the container + * Added `handler_id` configuration under `session` key to represent `session.handler` + service, defaults to `session.handler.native_file`. ### MonologBundle @@ -257,32 +263,47 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c * made mimetype to extension conversion configurable * [BC BREAK] Moved all session related classes and interfaces into own namespace, as `Symfony\Component\HttpFoudation\Session` and renamed classes accordingly. - * Added `FlashBag`. Flashes expire when retrieved by `get()` or `all()`. - This makes the implementation ESI compatible. - * Added `AutoExpireFlashBag` (default) to replicate Symfony 2.0.x auto expire behaviour of messages auto expiring - after one page page load. Messages must be retrived by `get()` or `all()`. - * [BC BREAK] Removed the `close()` method from the Session class + Session handlers are located in the subnamespace `Symfony\Component\HttpFoudation\Session\Handler`. + * SessionHandlers must implement `\SessionHandlerInterface` or extend from the + `Symfony\Component\HttpFoundation\Storage\Handler\NativeSessionHandler` base class. + * Added internal storage driver proxy mechanism for forward compatibility with + PHP 5.4 `\SessionHandler` class. + * Added session handlers for PHP native Memcache, Memcached and SQLite session + save handlers. + * Added session handlers for custom Memcache, Memcached and Null session save handlers. + * [BC BREAK] Removed `NativeSessionStorage` and replaced with `NativeFileSessionHandler`. + * [BC BREAK] `SessionStorageInterface` methods removed: `write()`, `read()` and + `remove()`. Added `getBag()`, `registerBag()`. The `NativeSessionStorage` class + is a mediator for the session storage internals including the session handlers + which do the real work of participating in the internal PHP session workflow. + * [BC BREAK] Introduced mock implementations of `SessionStorage` to enable unit + and functional testing without starting real PHP sessions. Removed + `ArraySessionStorage`, and replaced with `MockArraySessionStorage` for unit + tests; removed `FilesystemSessionStorage`, and replaced with`MockFileSessionStorage` + for functional tests. These do not interact with global session ini + configuration values, session functions or `$_SESSION` supreglobal. This means + they can be configured directly allowing multiple instances to work without + conflicting in the same PHP process. + * [BC BREAK] Removed the `close()` method from the `Session` class, as this is + now redundant. * Deprecated the following methods from the Session class: `setFlash()`, `setFlashes()` - `getFlash()`, `hasFlash()`, and `removeFlash()`. Use `getFlashBag()` instead which returns a `FlashBagInterface`. - * `Session->clear()` now only clears session attributes as before it cleared flash messages and - attributes. `Session->getFlashBag()->all()` clears flashes now. - * Added `Symfony\Component\HttpFoundation\Session\Storage\AbstractSessionStorage` base class for - session storage drivers. - * Added `SessionHandlerInterface` interface which storage drivers should implement after inheriting from - `Symfony\Component\HttpFoundation\Session\Storage\AbstractSessionStorage` when writing custom - session save handlers using PHP 5.3. This interface is a stub for the PHP 5.4 interface. - * [BC BREAK] `SessionStorageInterface` methods removed: `write()`, `read()` and `remove()`. Added - `getBag()`, `registerBag()`. - * Moved attribute storage to `Symfony\Component\HttpFoundation\Attribute\AttributeBagInterface`. - * Added `Symfony\Component\HttpFoundation\Attribute\AttributeBag` to replicate attributes storage - behaviour from 2.0.x (default). - * Added `Symfony\Component\HttpFoundation\Attribute\NamespacedAttributeBag` for namespace session attributes. - * Session now implements `Symfony\Component\HttpFoundation\Session\SessionInterface` making - implementation customizable and portable. - * [BC BREAK] Removed `NativeSessionStorage` and replaced with `NativeFileSessionStorage`. - * Added session storage drivers for PHP native Memcache, Memcached and SQLite session save handlers. - * Added session storage drivers for custom Memcache, Memcached and Null session save handlers. - * Removed `FilesystemSessionStorage`, use `MockFileSessionStorage` for functional testing instead. + `getFlash()`, `hasFlash()`, and `removeFlash()`. Use `getFlashBag()` instead + which returns a `FlashBagInterface`. + * `Session->clear()` now only clears session attributes as before it cleared + flash messages and attributes. `Session->getFlashBag()->all()` clears flashes now. + * Session data is now managed by `SessionBagInterface` which to better encapsulate + session data. + * Refactored session attribute and flash messages system to their own + `SessionBagInterface` implementations. + * Added `FlashBag`. Flashes expire when retrieved by `get()` or `all()`. This + implementation is ESI compatible. + * Added `AutoExpireFlashBag` (default) to replicate Symfony 2.0.x auto expire + behaviour of messages auto expiring. + after one page page load. Messages must be retrieved by `get()` or `all()`. + * Added `Symfony\Component\HttpFoundation\Attribute\AttributeBag` to replicate + attributes storage behaviour from 2.0.x (default). + * Added `Symfony\Component\HttpFoundation\Attribute\NamespacedAttributeBag` for + namespace session attributes. ### HttpKernel diff --git a/UPGRADE-2.1.md b/UPGRADE-2.1.md index db6e4c511305d..2a4927a5ec237 100644 --- a/UPGRADE-2.1.md +++ b/UPGRADE-2.1.md @@ -334,13 +334,11 @@ UPGRADE FROM 2.0 to 2.1 {% endfor %} ``` - * Session storage drivers should inherit from - `Symfony\Component\HttpFoundation\Session\Storage\AbstractSessionStorage` - and should no longer implement `read()`, `write()`, and `remove()`, which - were removed from `SessionStorageInterface`. + * Session handler drivers should implement `\SessionHandlerInterface` or extend from + `Symfony\Component\HttpFoudation\Session\Storage\Handler\NativeHandlerInterface` base class and renamed + to `Handler\FooSessionHandler`. E.g. `PdoSessionStorage` becomes `Handler\PdoSessionHandler`. - Any session storage driver that wants to use custom save handlers should - implement `SessionHandlerInterface`. + * Refactor code using `$session->*flash*()` methods to use `$session->getFlashBag()->*()`. ### FrameworkBundle @@ -371,3 +369,20 @@ UPGRADE FROM 2.0 to 2.1 cookie_httponly: true ``` +Added `handler_id`, defaults to `session.handler.native_file`. + + ``` + framework: + session: + storage_id: session.storage.native + handler_id: session.handler.native_file + ``` + +To use mock session storage use the following. `handler_id` is irrelevant in this context. + + ``` + framework: + session: + storage_id: session.storage.mock_file + ``` + From 9a5fc659d78ac31cc485030aff158e9cbfb1dd78 Mon Sep 17 00:00:00 2001 From: Drak Date: Wed, 14 Mar 2012 21:28:16 +0545 Subject: [PATCH 17/18] [HttpFoundation] Add more tests. --- .../Storage/Proxy/AbstractProxyTest.php | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxyTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxyTest.php index efa9f75e646fd..6850f5b81ef94 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxyTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxyTest.php @@ -89,4 +89,44 @@ public function testSetActive() $this->proxy->setActive(false); $this->assertFalse($this->proxy->isActive()); } + + /** + * @runInSeparateProcess + */ + public function testName() + { + $this->assertEquals(session_name(), $this->proxy->getName()); + $this->proxy->setName('foo'); + $this->assertEquals('foo', $this->proxy->getName()); + $this->assertEquals(session_name(), $this->proxy->getName()); + } + + /** + * @expectedException \LogicException + */ + public function testNameException() + { + $this->proxy->setActive(true); + $this->proxy->setName('foo'); + } + + /** + * @runInSeparateProcess + */ + public function testId() + { + $this->assertEquals(session_id(), $this->proxy->getId()); + $this->proxy->setId('foo'); + $this->assertEquals('foo', $this->proxy->getId()); + $this->assertEquals(session_id(), $this->proxy->getId()); + } + + /** + * @expectedException \LogicException + */ + public function testIdException() + { + $this->proxy->setActive(true); + $this->proxy->setId('foo'); + } } From eb9bf056372f718bee3595801ee2b60955fba135 Mon Sep 17 00:00:00 2001 From: Drak Date: Thu, 15 Mar 2012 09:51:39 +0545 Subject: [PATCH 18/18] [HttpFoundation] Remove hard coded assumptions and replace with API calls. --- .../HttpFoundation/Session/Session.php | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Session.php b/src/Symfony/Component/HttpFoundation/Session/Session.php index 0f507fc4ce424..13c6448874a3a 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Session.php +++ b/src/Symfony/Component/HttpFoundation/Session/Session.php @@ -36,6 +36,16 @@ class Session implements SessionInterface */ protected $storage; + /** + * @var string + */ + private $flashName; + + /** + * @var string + */ + private $attributeName; + /** * Constructor. * @@ -46,8 +56,14 @@ class Session implements SessionInterface public function __construct(SessionStorageInterface $storage = null, AttributeBagInterface $attributes = null, FlashBagInterface $flashes = null) { $this->storage = $storage ?: new NativeSessionStorage(); - $this->registerBag($attributes ?: new AttributeBag()); - $this->registerBag($flashes ?: new FlashBag()); + + $attributeBag = $attributes ?: new AttributeBag(); + $this->attributeName = $attributeBag->getName(); + $this->registerBag($attributeBag); + + $flashBag = $flashes ?: new FlashBag(); + $this->flashName = $flashBag->getName(); + $this->registerBag($flashBag); } /** @@ -63,7 +79,7 @@ public function start() */ public function has($name) { - return $this->storage->getBag('attributes')->has($name); + return $this->storage->getBag($this->attributeName)->has($name); } /** @@ -71,7 +87,7 @@ public function has($name) */ public function get($name, $default = null) { - return $this->storage->getBag('attributes')->get($name, $default); + return $this->storage->getBag($this->attributeName)->get($name, $default); } /** @@ -79,7 +95,7 @@ public function get($name, $default = null) */ public function set($name, $value) { - $this->storage->getBag('attributes')->set($name, $value); + $this->storage->getBag($this->attributeName)->set($name, $value); } /** @@ -87,7 +103,7 @@ public function set($name, $value) */ public function all() { - return $this->storage->getBag('attributes')->all(); + return $this->storage->getBag($this->attributeName)->all(); } /** @@ -95,7 +111,7 @@ public function all() */ public function replace(array $attributes) { - $this->storage->getBag('attributes')->replace($attributes); + $this->storage->getBag($this->attributeName)->replace($attributes); } /** @@ -103,7 +119,7 @@ public function replace(array $attributes) */ public function remove($name) { - return $this->storage->getBag('attributes')->remove($name); + return $this->storage->getBag($this->attributeName)->remove($name); } /** @@ -111,7 +127,7 @@ public function remove($name) */ public function clear() { - $this->storage->getBag('attributes')->clear(); + $this->storage->getBag($this->attributeName)->clear(); } /** @@ -201,7 +217,7 @@ public function getBag($name) */ public function getFlashBag() { - return $this->getBag('flashes'); + return $this->getBag($this->flashName); } // the following methods are kept for compatibility with Symfony 2.0 (they will be removed for Symfony 2.3)