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 0000000000..a5338d2da2 --- /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 0000000000..41cd49cb1e --- /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 0000000000..952c7105cd --- /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 0000000000..93a1010a73 --- /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 6465231912..8175090da0 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 @@ namespace Symfony\Component\HttpFoundation\Session\Storage; * @author Fabien Potencier * @author Michael Williams */ -class PdoSessionStorage extends AbstractSessionStorage implements \SessionHandlerInterface +class PdoSessionHandler implements \SessionHandlerInterface { /** * PDO instance. @@ -58,8 +58,6 @@ class PdoSessionStorage extends AbstractSessionStorage implements \SessionHandle '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 2447418c84..077fa0f14e 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 @@ namespace Symfony\Component\HttpFoundation\Session\Storage; * @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 c7c74ddd99..184f76e747 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 4f8fde308f..f34f5bccf0 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 @@ abstract class AbstractSessionStorage implements SessionStorageInterface $this->loadSession(); + if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) { + $this->saveHandler->setActive(false); + } + $this->started = true; $this->closed = false; @@ -149,6 +164,11 @@ abstract class AbstractSessionStorage implements SessionStorageInterface public function save() { session_write_close(); + + if (!$this->saveHandler->isWrapper() && !$this->getSaveHandler()->isSessionHandlerInterface()) { + $this->saveHandler->setActive(false); + } + $this->closed = true; } @@ -230,7 +250,7 @@ abstract class AbstractSessionStorage implements SessionStorageInterface '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 @@ abstract class AbstractSessionStorage implements SessionStorageInterface } /** - * 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 @@ abstract class AbstractSessionStorage implements SessionStorageInterface * * @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 366d815013..bc642cb082 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 @@ namespace Symfony\Component\HttpFoundation\Session\Storage; * * @author Drak */ -class MemcachedSessionStorage extends AbstractSessionStorage implements \SessionHandlerInterface +class MemcachedSessionHandler implements \SessionHandlerInterface { /** * Memcached driver. @@ -63,8 +63,6 @@ class MemcachedSessionStorage extends AbstractSessionStorage implements \Session $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 eca342ec37..5acf004d15 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 @@ namespace Symfony\Component\HttpFoundation\Session\Storage; * * @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 ec34ead6d8..beef87e965 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 @@ namespace Symfony\Component\HttpFoundation\Session\Storage; * * @author Drak */ -class NativeMemcacheSessionStorage extends AbstractSessionStorage +class NativeMemcacheSessionHandler extends NativeSessionHandler { - /** - * @var string - */ - private $savePath; - /** * Constructor. * @@ -41,17 +36,14 @@ class NativeMemcacheSessionStorage extends AbstractSessionStorage 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 @@ class NativeMemcacheSessionStorage extends AbstractSessionStorage 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 e923f34030..11f6790aef 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 @@ namespace Symfony\Component\HttpFoundation\Session\Storage; * * @author Drak */ -class NativeMemcachedSessionStorage extends AbstractSessionStorage +class NativeMemcachedSessionHandler extends NativeSessionHandler { - /** - * @var string - */ - private $savePath; - /** * Constructor. * @@ -41,17 +36,14 @@ class NativeMemcachedSessionStorage extends AbstractSessionStorage 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 @@ class NativeMemcachedSessionStorage extends AbstractSessionStorage 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 4c528b0dd7..4f383efb05 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 @@ namespace Symfony\Component\HttpFoundation\Session\Storage; * * @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 @@ class NativeSqliteSessionStorage extends AbstractSessionStorage 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 8f45a6eff2..0839622aea 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 @@ namespace Symfony\Component\HttpFoundation\Session\Storage; * * @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 68218e86b3..72ecac5550 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 @@ class MemcacheSessionStorage extends AbstractSessionStorage implements \SessionH $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 8d53002c8d..c05d5730ff 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 @@ class CustomHandlerSessionStorage extends AbstractSessionStorage implements \Ses * * @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 @@ class AbstractSessionStorageTest extends \PHPUnit_Framework_TestCase $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 @@ class AbstractSessionStorageTest extends \PHPUnit_Framework_TestCase { 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 @@ class AbstractSessionStorageTest extends \PHPUnit_Framework_TestCase $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 1cdbe2a3a9..3d4adfab47 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 @@ class MemcacheSessionStorageTest extends \PHPUnit_Framework_TestCase { $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 cc8d0bee35..1fca44445e 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 df3ef95cbf..08b8644ebf 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 4274ed5bd1..377fe1754c 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 @@ class NativeMemcacheSessionStorageTest extends \PHPUnit_Framework_TestCase $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 c0a12aa2b4..f4ae96c6e2 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 @@ class NativeMemcachedSessionStorageTest extends \PHPUnit_Framework_TestCase // 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 b1700326b1..373b0e8a49 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 66599f68b3..289aa9c85c 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 @@ class NullSessionStorageTest extends \PHPUnit_Framework_TestCase 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 0000000000..a968e2e0a3 --- /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 0000000000..b62ce8192b --- /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 0000000000..f6c3d7aa75 --- /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 0000000000..fb7d36adda --- /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 ca63874b0f..652531d613 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -167,7 +167,8 @@ class Configuration implements ConfigurationInterface ->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 5a76df3b49..7a7999d4a2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -310,10 +310,16 @@ class FrameworkExtension extends Extension } $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 535c455b0c..8b7c264ce2 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 31d374aa6b..3b985be216 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 219644b563..5119fbdbab 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 @@ $container->loadFromExtension('framework', array( '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 deadfe4b88..b15ea893f0 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 @@ $container->loadFromExtension('framework', array( '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 3ab6488493..32fa1812fa 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 @@ $container->loadFromExtension('framework', array( ), '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 283fb3190c..7b95b42002 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 07df1182cf..701bae53bd 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 d91825bd20..5ee785070e 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 fdc61fd937..e5ec05fbf6 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 e61808b8f2..67ea8bc44b 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 126baf2d4e..dd459e784f 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 eac0395dbd..43ae49a016 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -78,7 +78,8 @@ abstract class FrameworkExtensionTest extends TestCase $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 a260c3a149..cef6cec860 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 @@ use Doctrine\DBAL\Driver\Connection; * @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 @@ class DbalSessionStorage extends AbstractSessionStorage implements \SessionHandl } /** - * Closes a session. - * - * @return Boolean true, if the session was closed, otherwise false + * {@inheritdoc} */ public function close() { @@ -63,13 +62,7 @@ class DbalSessionStorage extends AbstractSessionStorage implements \SessionHandl } /** - * 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 @@ class DbalSessionStorage extends AbstractSessionStorage implements \SessionHandl } /** - * 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 @@ class DbalSessionStorage extends AbstractSessionStorage implements \SessionHandl } /** - * 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 @@ class DbalSessionStorage extends AbstractSessionStorage implements \SessionHandl } /** - * 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 b33862588c..b7b4b91a7a 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 @@ use Doctrine\DBAL\Schema\Schema; * * @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 63dda8d6bd..6f2c6a4262 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 11f6790aef..d66dc953d6 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 @@ class NativeMemcachedSessionHandler extends NativeSessionHandler } } } - } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php index 41cd49cb1e..0cd4d73d96 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 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy; /** * AbstractProxy. + * + * @author Drak */ abstract class AbstractProxy { @@ -43,9 +45,14 @@ abstract class AbstractProxy 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 @@ abstract class AbstractProxy */ 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 952c7105cd..5bb2c712e3 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 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy; * 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 93a1010a73..e925d628df 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 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy; /** * 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 @@ class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterf /** * {@inheritdoc} */ - function open($savePath, $sessionName) + public function open($savePath, $sessionName) { $return = (bool)$this->handler->open($savePath, $sessionName); @@ -52,42 +54,42 @@ class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterf /** * {@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 f34f5bccf0..f5a1578767 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 @@ class SessionStorage implements SessionStorageInterface } 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 @@ class SessionStorage implements SessionStorageInterface * * @see http://php.net/session.configuration */ - protected function setOptions(array $options) + public function setOptions(array $options) { $this->options = $options; @@ -234,7 +233,6 @@ class SessionStorage implements SessionStorageInterface '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 @@ class SessionStorage implements SessionStorageInterface * @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 a968e2e0a3..efa9f75e64 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 @@ namespace Symfony\Tests\Component\HttpFoundation\Session\Storage\Proxy; 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 @@ class AbstractProxyTest extends \PHPUnit_Framework_TestCase 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 f6c3d7aa75..0000000000 --- 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 b62ce8192b..0dc0ce92a3 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 @@ use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHa /** * 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 fb7d36adda..61393f3102 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 d335758b70..9010342d94 100644 --- a/src/Symfony/Bundle/FrameworkBundle/EventListener/TestSessionListener.php +++ b/src/Symfony/Bundle/FrameworkBundle/EventListener/TestSessionListener.php @@ -72,7 +72,7 @@ class TestSessionListener implements EventSubscriberInterface $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 077fa0f14e..482f3b6c20 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php @@ -76,7 +76,7 @@ class MockArraySessionStorage extends SessionStorage */ public function regenerate($destroy = false) { - if ($this->options['auto_start'] && !$this->started) { + if (!$this->started) { $this->start(); } @@ -124,6 +124,22 @@ class MockArraySessionStorage extends SessionStorage $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 f5a1578767..47a6044e87 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 @@ class SessionStorage implements SessionStorageInterface 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 @@ class SessionStorage implements SessionStorageInterface $this->saveHandler->setActive(false); } - $this->started = true; - $this->closed = false; - return true; } @@ -205,8 +210,10 @@ class SessionStorage implements SessionStorageInterface 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 @@ class SessionStorage implements SessionStorageInterface * 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 @@ class SessionStorage implements SessionStorageInterface $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 428f065c1a..eda2dac30d 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 6a6fd6760a..8f921334ae 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 @@ class PdoSessionStorageTest extends \PHPUnit_Framework_TestCase 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 @@ class PdoSessionStorageTest extends \PHPUnit_Framework_TestCase 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 ecce76ec5e..d8cac3857c 100644 --- a/tests/Symfony/Tests/Component/HttpKernel/EventListener/LocaleListenerTest.php +++ b/tests/Symfony/Tests/Component/HttpKernel/EventListener/LocaleListenerTest.php @@ -33,7 +33,7 @@ class LocaleListenerTest extends \PHPUnit_Framework_TestCase 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 @@ class LocaleListenerTest extends \PHPUnit_Framework_TestCase $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 83fdec4b74..ad396347d5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/EventListener/SessionListener.php +++ b/src/Symfony/Bundle/FrameworkBundle/EventListener/SessionListener.php @@ -28,7 +28,14 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; */ 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 9010342d94..8f4536de8e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/EventListener/TestSessionListener.php +++ b/src/Symfony/Bundle/FrameworkBundle/EventListener/TestSessionListener.php @@ -43,15 +43,16 @@ class TestSessionListener implements EventSubscriberInterface } // 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 @@ class TestSessionListener implements EventSubscriberInterface $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 fe551ba360..4c577f292f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/EventListener/TestSessionListenerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/EventListener/TestSessionListenerTest.php @@ -94,8 +94,13 @@ class TestSessionListenerTest extends \PHPUnit_Framework_TestCase 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 f38b1e7d0f..eaa453e1b4 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -496,7 +496,8 @@ class Request 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 6f2c6a4262..9f2e3326e8 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\Attribute\AttributeBagInterface; 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 @@ class Session implements SessionInterface } /** - * Returns the session ID - * - * @return mixed The session ID - * - * @api + * {@inheritdoc} */ public function getId() { @@ -152,7 +149,31 @@ class Session implements SessionInterface } /** - * 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 741969b10e..4e4962de4e 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 5acf004d15..202d8d0f90 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 482f3b6c20..6f1e279f41 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 @@ use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler; * @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 @@ class MockArraySessionStorage extends SessionStorage */ public function setSessionData(array $array) { - $this->sessionData = $array; + $this->data = $array; } /** @@ -61,11 +81,11 @@ class MockArraySessionStorage extends SessionStorage 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 @@ class MockArraySessionStorage extends SessionStorage $this->start(); } - $this->sessionId = $this->generateSessionId(); - session_id($this->sessionId); + $this->id = $this->generateId(); return true; } @@ -91,11 +110,35 @@ class MockArraySessionStorage extends SessionStorage */ 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 @@ class MockArraySessionStorage extends SessionStorage } // 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 @@ class MockArraySessionStorage extends SessionStorage /** * 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(), true)); + return sha1(uniqid(mt_rand())); + } + + protected function loadSession() + { + 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 184f76e747..24457319f9 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php @@ -16,7 +16,9 @@ namespace Symfony\Component\HttpFoundation\Session\Storage; * 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 @@ class MockFileSessionStorage extends MockArraySessionStorage $this->savePath = $savePath; - parent::__construct($options); + parent::__construct($name); } /** @@ -59,12 +59,10 @@ class MockFileSessionStorage extends MockArraySessionStorage 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 @@ class MockFileSessionStorage extends MockArraySessionStorage $this->destroy(); } - session_id($this->generateSessionId()); - $this->sessionId = session_id(); - - $this->save(); + $this->id = $this->generateId(); return true; } @@ -92,23 +87,15 @@ class MockFileSessionStorage extends MockArraySessionStorage /** * {@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 @@ class MockFileSessionStorage extends MockArraySessionStorage * * @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 0cd4d73d96..09f9efa091 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 @@ abstract class AbstractProxy { $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 47a6044e87..194318aa2e 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php @@ -93,6 +93,12 @@ class SessionStorage implements SessionStorageInterface 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 @@ class SessionStorage implements SessionStorageInterface 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 @@ class SessionStorage implements SessionStorageInterface 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 @@ class SessionStorage implements SessionStorageInterface 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 6065a550dc..8bf2e5d32a 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorageInterface.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorageInterface.php @@ -37,12 +37,39 @@ interface SessionStorageInterface /** * 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 @@ interface SessionStorageInterface * 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 3e672da273..136b8fc95b 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php @@ -866,7 +866,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase public function testHasSession() { - $request = new Request; + $request = new Request(); $this->assertFalse($request->hasSession()); $request->setSession(new Session(new MockArraySessionStorage())); @@ -875,10 +875,10 @@ class RequestTest extends \PHPUnit_Framework_TestCase 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 08b8644ebf..37eb40cbe9 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\Handler\NativeFileSessionHa 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 770bcda8f0..c0453df977 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 @@ class MockFileSessionStorageTest extends \PHPUnit_Framework_TestCase 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 @@ class MockFileSessionStorageTest extends \PHPUnit_Framework_TestCase $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 @@ class MockFileSessionStorageTest extends \PHPUnit_Framework_TestCase $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 7a7999d4a2..8c91c37a4e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -316,7 +316,7 @@ class FrameworkExtension extends Extension $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 3b985be216..7392d26a17 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 9f2e3326e8..0f507fc4ce 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\Attribute\AttributeBagInterface; 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 194318aa2e..be6904ed66 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php @@ -21,7 +21,7 @@ use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy; * * @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 37eb40cbe9..c6a4495225 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 @@ class NativeFileSessionHandlerTest extends \PHPUnit_Framework_TestCase 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 377fe1754c..3dbcb4f7f8 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 @@ class NativeMemcacheSessionHandlerTest extends \PHPUnit_Framework_TestCase $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 f4ae96c6e2..a85fbdd056 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 @@ class NativeMemcachedSessionHandlerTest extends \PHPUnit_Framework_TestCase // 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 373b0e8a49..9867e49590 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 @@ class NativeSqliteSessionHandlerTest extends \PHPUnit_Framework_TestCase $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 289aa9c85c..e0c883e7c3 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 @@ class NullSessionStorageTest extends \PHPUnit_Framework_TestCase 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 c05d5730ff..26f6113448 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 @@ use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag; * * @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 @@ class SessionStorageTest extends \PHPUnit_Framework_TestCase { ini_set('session.cache_limiter', 'nocache'); - $storage = new SessionStorage(); + $storage = new NativeSessionStorage(); $this->assertEquals('', ini_get('session.cache_limiter')); } @@ -90,7 +90,7 @@ class SessionStorageTest extends \PHPUnit_Framework_TestCase { 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 5214648ee2..cf9c8c20a7 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 db6e4c5113..2a4927a5ec 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 efa9f75e64..6850f5b81e 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 @@ class AbstractProxyTest extends \PHPUnit_Framework_TestCase $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 0f507fc4ce..13c6448874 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 @@ class Session implements SessionInterface */ public function has($name) { - return $this->storage->getBag('attributes')->has($name); + return $this->storage->getBag($this->attributeName)->has($name); } /** @@ -71,7 +87,7 @@ class Session implements SessionInterface */ 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 @@ class Session implements SessionInterface */ public function set($name, $value) { - $this->storage->getBag('attributes')->set($name, $value); + $this->storage->getBag($this->attributeName)->set($name, $value); } /** @@ -87,7 +103,7 @@ class Session implements SessionInterface */ public function all() { - return $this->storage->getBag('attributes')->all(); + return $this->storage->getBag($this->attributeName)->all(); } /** @@ -95,7 +111,7 @@ class Session implements SessionInterface */ public function replace(array $attributes) { - $this->storage->getBag('attributes')->replace($attributes); + $this->storage->getBag($this->attributeName)->replace($attributes); } /** @@ -103,7 +119,7 @@ class Session implements SessionInterface */ public function remove($name) { - return $this->storage->getBag('attributes')->remove($name); + return $this->storage->getBag($this->attributeName)->remove($name); } /** @@ -111,7 +127,7 @@ class Session implements SessionInterface */ public function clear() { - $this->storage->getBag('attributes')->clear(); + $this->storage->getBag($this->attributeName)->clear(); } /** @@ -201,7 +217,7 @@ class Session implements SessionInterface */ 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)