From 592752e18ac1303017a12ebbd76bb0b961c3d340 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Tue, 27 Mar 2012 10:24:50 -0400 Subject: [PATCH 1/5] Started SessionComponent w/ Symfony integration --- composer.json | 6 +- composer.lock | 12 ++- .../Component/Session/SessionComponent.php | 91 +++++++++++++++++++ .../Session/Storage/Proxy/VirtualProxy.php | 46 ++++++++++ .../Session/Storage/VirtualSessionStorage.php | 62 +++++++++++++ 5 files changed, 213 insertions(+), 4 deletions(-) create mode 100644 src/Ratchet/Component/Session/SessionComponent.php create mode 100644 src/Ratchet/Component/Session/Storage/Proxy/VirtualProxy.php create mode 100644 src/Ratchet/Component/Session/Storage/VirtualSessionStorage.php diff --git a/composer.json b/composer.json index 3000123..de48276 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,8 @@ } , "repositories": { "guzzle": { - "package": { + "type": "package" + , "package": { "name": "guzzle" , "type": "library" , "version": "2.0.2" @@ -41,4 +42,7 @@ "php": ">=5.3.2" , "guzzle": "2.0.2" } + , "suggest": { + "symfony/http-foundation": "dev-master" + } } \ No newline at end of file diff --git a/composer.lock b/composer.lock index 4e02f7a..fb1cd27 100644 --- a/composer.lock +++ b/composer.lock @@ -1,9 +1,15 @@ { - "hash": "e898a89b9f66807dae53937fe3b089d3", + "hash": "ad8d05f50ba77c0700a2019656894cc6", "packages": [ { "package": "guzzle", "version": "2.0.2" + }, + { + "package": "symfony/http-foundation", + "version": "dev-master", + "source-reference": "ec8ce75d0ec64dfe6de235a7c92282bae066532d" } - ] -} \ No newline at end of file + ], + "aliases": [] +} diff --git a/src/Ratchet/Component/Session/SessionComponent.php b/src/Ratchet/Component/Session/SessionComponent.php new file mode 100644 index 0000000..127e21a --- /dev/null +++ b/src/Ratchet/Component/Session/SessionComponent.php @@ -0,0 +1,91 @@ +_app = $app; + $this->_handler = $handler; + $this->_options = array(); + $this->_null = new NullSessionHandler; + + ini_set('session.auto_start', 0); + ini_set('session.cache_limiter', ''); + ini_set('session.use_cookies', 0); + + $options = $this->setOptions($options); + } + + /** + * {@inheritdoc} + */ + function onOpen(ConnectionInterface $conn) { + if (null === ($id = $conn->WebSocket->headers->getCookie($this->_options['name']))) { + $saveHandler = new NullSessionHandler; + $id = ''; + } else { + $saveHandler = $this->_handler; + } + + $conn->Session = new Session(new VirtualSessionStorage($saveHandler, $id)); + + return $this->_app->onOpen($conn); + } + + /** + * {@inheritdoc} + */ + function onMessage(ConnectionInterface $from, $msg) { + return $this->_app->onMessage($from, $msg); + } + + /** + * {@inheritdoc} + */ + function onClose(ConnectionInterface $conn) { + // "close" session for Connection + + return $this->_app->onClose($conn); + } + + /** + * {@inheritdoc} + */ + function onError(ConnectionInterface $conn, \Exception $e) { + return $this->_app->onError($conn, $e); + } + + protected function setOptions(array $options) { + $all = array( + 'auto_start', 'cache_limiter', 'cookie_domain', 'cookie_httponly', + 'cookie_lifetime', 'cookie_path', 'cookie_secure', + 'entropy_file', 'entropy_length', 'gc_divisor', + 'gc_maxlifetime', 'gc_probability', 'hash_bits_per_character', + 'hash_function', 'name', 'referer_check', + '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' + ); + + foreach ($all as $key) { + if (!array_key_exists($key, $options)) { + $options[$key] = ini_get("session.{$key}"); + } else { + ini_set("session.{$key}", $options[$key]); + } + } + + return $options; + } +} \ No newline at end of file diff --git a/src/Ratchet/Component/Session/Storage/Proxy/VirtualProxy.php b/src/Ratchet/Component/Session/Storage/Proxy/VirtualProxy.php new file mode 100644 index 0000000..780286f --- /dev/null +++ b/src/Ratchet/Component/Session/Storage/Proxy/VirtualProxy.php @@ -0,0 +1,46 @@ +saveHandlerName = 'user'; + $this->_sessionId = $sessionId; + $this->_sessionName = ini_get('session.name'); + } + + /** + * {@inheritdoc} + */ + public function getId() { + return $this->_sessionId; + } + + public function setId($id) { + throw new \RuntimeException("Can not change session id in VirtualProxy"); + } + + /** + * {@inheritdoc} + */ + public function getName() { + return $this->_sessionName; + } + + /** + * DO NOT CALL THIS METHOD + * @param string + * @throws RuntimeException + */ + public function setName($name) { + throw new \RuntimeException("Can not change session name in VirtualProxy"); + } +} \ No newline at end of file diff --git a/src/Ratchet/Component/Session/Storage/VirtualSessionStorage.php b/src/Ratchet/Component/Session/Storage/VirtualSessionStorage.php new file mode 100644 index 0000000..639093b --- /dev/null +++ b/src/Ratchet/Component/Session/Storage/VirtualSessionStorage.php @@ -0,0 +1,62 @@ +setSaveHandler($handler, $id); + } + + /** + * {@inheritdoc} + */ + public function start() { + if ($this->started && !$this->closed) { + return true; + } + + $ignore = array(); + $this->loadSession($ignore); + + if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) { + $this->saveHandler->setActive(false); + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function regenerate($destroy = false) { + // .. ? + } + + /** + * {@inheritdoc} + */ + public function save() { +// $this->saveHandler->write($this->saveHandler->getId(), + + if (!$this->saveHandler->isWrapper() && !$this->getSaveHandler()->isSessionHandlerInterface()) { + $this->saveHandler->setActive(false); + } + + $this->closed = true; + } + + /** + * {@inheritdoc} + */ + public function setSaveHandler(\SessionHandlerInterface $saveHandler, $id) { + if (!($saveHandler instanceof \VirtualProxy)) { + $saveHandler = new VirtualProxy($saveHandler, $id); + } + + $this->saveHandler = $saveHandler; + } +} \ No newline at end of file From 33ed96eba080260a6bf19183b845848f5ea4bc45 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Tue, 27 Mar 2012 14:29:56 -0400 Subject: [PATCH 2/5] Session read working --- .../Session/Serialize/HandlerInterface.php | 16 ++++++++ .../Session/Serialize/PhpBinaryHandler.php | 33 +++++++++++++++++ .../Session/Serialize/PhpHandler.php | 37 +++++++++++++++++++ .../Component/Session/SessionComponent.php | 20 ++++++++-- .../Session/Storage/Proxy/VirtualProxy.php | 15 ++++++-- .../Session/Storage/VirtualSessionStorage.php | 29 ++++++++++++--- 6 files changed, 138 insertions(+), 12 deletions(-) create mode 100644 src/Ratchet/Component/Session/Serialize/HandlerInterface.php create mode 100644 src/Ratchet/Component/Session/Serialize/PhpBinaryHandler.php create mode 100644 src/Ratchet/Component/Session/Serialize/PhpHandler.php diff --git a/src/Ratchet/Component/Session/Serialize/HandlerInterface.php b/src/Ratchet/Component/Session/Serialize/HandlerInterface.php new file mode 100644 index 0000000..42774b1 --- /dev/null +++ b/src/Ratchet/Component/Session/Serialize/HandlerInterface.php @@ -0,0 +1,16 @@ +_app = $app; $this->_handler = $handler; $this->_options = array(); @@ -24,6 +27,17 @@ class SessionComponent implements MessageComponentInterface { ini_set('session.use_cookies', 0); $options = $this->setOptions($options); + + if (null === $serializer) { + $serialClass = __NAMESPACE__ . '\\Serialize\\' . str_replace(' ', '', ucwords(str_replace('_', ' ', ini_get('session.serialize_handler')))) . 'Handler'; // awesome/terrible hack, eh? + if (!class_exists($serialClass)) { + throw new \RuntimeExcpetion('Unable to parse session serialize handler'); + } + + $serializer = new $serialClass; + } + + $this->_serializer = $serializer; } /** @@ -31,13 +45,13 @@ class SessionComponent implements MessageComponentInterface { */ function onOpen(ConnectionInterface $conn) { if (null === ($id = $conn->WebSocket->headers->getCookie($this->_options['name']))) { - $saveHandler = new NullSessionHandler; + $saveHandler = $this->_null; $id = ''; } else { $saveHandler = $this->_handler; } - $conn->Session = new Session(new VirtualSessionStorage($saveHandler, $id)); + $conn->Session = new Session(new VirtualSessionStorage($saveHandler, $id, $this->_serializer)); return $this->_app->onOpen($conn); } diff --git a/src/Ratchet/Component/Session/Storage/Proxy/VirtualProxy.php b/src/Ratchet/Component/Session/Storage/Proxy/VirtualProxy.php index 780286f..25ce486 100644 --- a/src/Ratchet/Component/Session/Storage/Proxy/VirtualProxy.php +++ b/src/Ratchet/Component/Session/Storage/Proxy/VirtualProxy.php @@ -3,17 +3,23 @@ namespace Ratchet\Component\Session\Storage\Proxy; use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy; class VirtualProxy extends SessionHandlerProxy { + /** + * @var string + */ protected $_sessionId; + + /** + * @var string + */ protected $_sessionName; /** * {@inheritdoc} */ - public function __construct(\SessionHandlerInterface $handler, $sessionId) { + public function __construct(\SessionHandlerInterface $handler) { parent::__construct($handler); $this->saveHandlerName = 'user'; - $this->_sessionId = $sessionId; $this->_sessionName = ini_get('session.name'); } @@ -24,8 +30,11 @@ class VirtualProxy extends SessionHandlerProxy { return $this->_sessionId; } + /** + * {@inheritdoc} + */ public function setId($id) { - throw new \RuntimeException("Can not change session id in VirtualProxy"); + $this->_sessionId = $id; } /** diff --git a/src/Ratchet/Component/Session/Storage/VirtualSessionStorage.php b/src/Ratchet/Component/Session/Storage/VirtualSessionStorage.php index 639093b..9e3bdd4 100644 --- a/src/Ratchet/Component/Session/Storage/VirtualSessionStorage.php +++ b/src/Ratchet/Component/Session/Storage/VirtualSessionStorage.php @@ -2,13 +2,21 @@ namespace Ratchet\Component\Session\Storage; use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; use Ratchet\Component\Session\Storage\Proxy\VirtualProxy; +use Ratchet\Component\Session\Serialize\HandlerInterface; class VirtualSessionStorage extends NativeSessionStorage { + /** + * @var Ratchet\Component\Session\Serialize\HandlerInterface + */ + protected $_serializer; + /** * {@inheritdoc} */ - public function __construct(\SessionHandlerInterface $handler, $id) { - $this->setSaveHandler($handler, $id); + public function __construct(\SessionHandlerInterface $handler, $sessionId, HandlerInterface $serializer) { + $this->setSaveHandler($handler); + $this->saveHandler->setId($sessionId); + $this->_serializer = $serializer; } /** @@ -19,8 +27,10 @@ class VirtualSessionStorage extends NativeSessionStorage { return true; } - $ignore = array(); - $this->loadSession($ignore); + $rawData = $this->saveHandler->read($this->saveHandler->getId()); + $sessionData = $this->_serializer->unserialize($rawData); + + $this->loadSession($sessionData); if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) { $this->saveHandler->setActive(false); @@ -40,6 +50,9 @@ class VirtualSessionStorage extends NativeSessionStorage { * {@inheritdoc} */ public function save() { + // get the data from the bags? + // serialize the data + // save the data using the saveHandler // $this->saveHandler->write($this->saveHandler->getId(), if (!$this->saveHandler->isWrapper() && !$this->getSaveHandler()->isSessionHandlerInterface()) { @@ -52,9 +65,13 @@ class VirtualSessionStorage extends NativeSessionStorage { /** * {@inheritdoc} */ - public function setSaveHandler(\SessionHandlerInterface $saveHandler, $id) { + public function setSaveHandler($saveHandler = null) { + if (!($saveHandler instanceof \SessionHandlerInterface)) { + throw new \InvalidArgumentException('Handler must be instance of SessionHandlerInterface'); + } + if (!($saveHandler instanceof \VirtualProxy)) { - $saveHandler = new VirtualProxy($saveHandler, $id); + $saveHandler = new VirtualProxy($saveHandler); } $this->saveHandler = $saveHandler; From c58814ab646df460b41984eb0ad64fb8f657cb94 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Tue, 27 Mar 2012 15:31:28 -0400 Subject: [PATCH 3/5] Serialize fix --- src/Ratchet/Component/Session/Serialize/PhpHandler.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Ratchet/Component/Session/Serialize/PhpHandler.php b/src/Ratchet/Component/Session/Serialize/PhpHandler.php index 1922fde..4bc2102 100644 --- a/src/Ratchet/Component/Session/Serialize/PhpHandler.php +++ b/src/Ratchet/Component/Session/Serialize/PhpHandler.php @@ -12,6 +12,7 @@ class PhpHandler implements HandlerInterface { /** * {@inheritdoc} * @link http://ca2.php.net/manual/en/function.session-decode.php#108037 Code from this comment on php.net + * @throws UnexpectedValueException If there is a problem parsing the data */ public function unserialize($raw) { $returnData = array(); @@ -19,7 +20,7 @@ class PhpHandler implements HandlerInterface { while ($offset < strlen($raw)) { if (!strstr(substr($raw, $offset), "|")) { - throw new Exception("invalid data, remaining: " . substr($raw, $offset)); + throw new \UnexpectedValueException("invalid data, remaining: " . substr($raw, $offset)); } $pos = strpos($raw, "|", $offset); From a4bc626fae101bda791786e57e719917d7bd107b Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Thu, 29 Mar 2012 17:42:42 -0400 Subject: [PATCH 4/5] [Session] Fixes, cleanup, docs, tests --- .../Component/Session/SessionComponent.php | 54 ++++++++++++++++-- .../Session/Storage/VirtualSessionStorage.php | 4 +- .../Session/Serialize/PhpHandlerTest.php | 36 ++++++++++++ .../Session/SessionComponentTest.php | 52 ++++++++++++++++++ .../Tests/Mock/MemorySessionHandler.php | 39 +++++++++++++ .../Tests/Mock/NullMessageComponent.php | 55 +++++++++++++++++++ 6 files changed, 234 insertions(+), 6 deletions(-) create mode 100644 tests/Ratchet/Tests/Component/Session/Serialize/PhpHandlerTest.php create mode 100644 tests/Ratchet/Tests/Component/Session/SessionComponentTest.php create mode 100644 tests/Ratchet/Tests/Mock/MemorySessionHandler.php create mode 100644 tests/Ratchet/Tests/Mock/NullMessageComponent.php diff --git a/src/Ratchet/Component/Session/SessionComponent.php b/src/Ratchet/Component/Session/SessionComponent.php index 702b4ea..30654c2 100644 --- a/src/Ratchet/Component/Session/SessionComponent.php +++ b/src/Ratchet/Component/Session/SessionComponent.php @@ -7,29 +7,55 @@ use Ratchet\Component\Session\Serialize\HandlerInterface; use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler; +/** + * This component will allow access to session data from your website for each user connected + * Symfony HttpFoundation is required for this component to work + * Your website must also use Symfony HttpFoundation Sessions to read your sites session data + * If your are not using at least PHP 5.4 you must include a SessionHandlerInterface stub (is included in Symfony HttpFoundation, loaded w/ composer) + */ class SessionComponent implements MessageComponentInterface { + /** + * @var Ratchet\Component\MessageComponentInterface + */ protected $_app; - protected $_options; + /** + * Selected handler storage assigned by the developer + * @var SessionHandlerInterface + */ protected $_handler; + + /** + * Null storage handler if no previous session was found + * @var SessionHandlerInterface + */ protected $_null; + /** + * @var Ratchet\Component\Session\Serialize\HandlerInterface + */ protected $_serializer; + /** + * @param Ratchet\Component\MessageComponentInterface + * @param SessionHandlerInterface + * @param array + * @param Ratchet\Component\Session\Serialize\HandlerInterface + * @throws RuntimeException If unable to match serialization methods + */ public function __construct(MessageComponentInterface $app, \SessionHandlerInterface $handler, array $options = array(), HandlerInterface $serializer = null) { $this->_app = $app; $this->_handler = $handler; - $this->_options = array(); $this->_null = new NullSessionHandler; ini_set('session.auto_start', 0); ini_set('session.cache_limiter', ''); ini_set('session.use_cookies', 0); - $options = $this->setOptions($options); + $this->setOptions($options); if (null === $serializer) { - $serialClass = __NAMESPACE__ . '\\Serialize\\' . str_replace(' ', '', ucwords(str_replace('_', ' ', ini_get('session.serialize_handler')))) . 'Handler'; // awesome/terrible hack, eh? + $serialClass = __NAMESPACE__ . "\\Serialize\\{$this->toClassCase(ini_get('session.serialize_handler'))}Handler"; // awesome/terrible hack, eh? if (!class_exists($serialClass)) { throw new \RuntimeExcpetion('Unable to parse session serialize handler'); } @@ -44,7 +70,7 @@ class SessionComponent implements MessageComponentInterface { * {@inheritdoc} */ function onOpen(ConnectionInterface $conn) { - if (null === ($id = $conn->WebSocket->headers->getCookie($this->_options['name']))) { + if (null === ($id = $conn->WebSocket->headers->getCookie(ini_get('session.name')))) { $saveHandler = $this->_null; $id = ''; } else { @@ -53,6 +79,10 @@ class SessionComponent implements MessageComponentInterface { $conn->Session = new Session(new VirtualSessionStorage($saveHandler, $id, $this->_serializer)); + if (ini_get('session.auto_start')) { + $conn->Session->start(); + } + return $this->_app->onOpen($conn); } @@ -79,6 +109,12 @@ class SessionComponent implements MessageComponentInterface { return $this->_app->onError($conn, $e); } + /** + * Set all the php session. ini options + * © Symfony + * @param array + * @return array + */ protected function setOptions(array $options) { $all = array( 'auto_start', 'cache_limiter', 'cookie_domain', 'cookie_httponly', @@ -102,4 +138,12 @@ class SessionComponent implements MessageComponentInterface { return $options; } + + /** + * @param string Input to convert + * @return string + */ + protected function toClassCase($langDef) { + return str_replace(' ', '', ucwords(str_replace('_', ' ', $langDef))); + } } \ No newline at end of file diff --git a/src/Ratchet/Component/Session/Storage/VirtualSessionStorage.php b/src/Ratchet/Component/Session/Storage/VirtualSessionStorage.php index 9e3bdd4..795e4f4 100644 --- a/src/Ratchet/Component/Session/Storage/VirtualSessionStorage.php +++ b/src/Ratchet/Component/Session/Storage/VirtualSessionStorage.php @@ -11,7 +11,9 @@ class VirtualSessionStorage extends NativeSessionStorage { protected $_serializer; /** - * {@inheritdoc} + * @param SessionHandlerInterface + * @param string The ID of the session to retreive + * @param Ratchet\Component\Session\Serialize\HandlerInterface */ public function __construct(\SessionHandlerInterface $handler, $sessionId, HandlerInterface $serializer) { $this->setSaveHandler($handler); diff --git a/tests/Ratchet/Tests/Component/Session/Serialize/PhpHandlerTest.php b/tests/Ratchet/Tests/Component/Session/Serialize/PhpHandlerTest.php new file mode 100644 index 0000000..0528817 --- /dev/null +++ b/tests/Ratchet/Tests/Component/Session/Serialize/PhpHandlerTest.php @@ -0,0 +1,36 @@ +_handler = new PhpHandler; + } + + public function serializedProvider() { + return array( + array( + '_sf2_attributes|a:2:{s:5:"hello";s:5:"world";s:4:"last";i:1332872102;}_sf2_flashes|a:0:{}' + , array( + '_sf2_attributes' => array( + 'hello' => 'world' + , 'last' => 1332872102 + ) + , '_sf2_flashes' => array() + ) + ) + ); + } + + /** + * @dataProvider serializedProvider + */ + public function testUnserialize($in, $expected) { + $this->assertEquals($expected, $this->_handler->unserialize($in)); + } +} \ No newline at end of file diff --git a/tests/Ratchet/Tests/Component/Session/SessionComponentTest.php b/tests/Ratchet/Tests/Component/Session/SessionComponentTest.php new file mode 100644 index 0000000..87020c9 --- /dev/null +++ b/tests/Ratchet/Tests/Component/Session/SessionComponentTest.php @@ -0,0 +1,52 @@ +app = new SessionComponent + } + + /** + * @return bool + */ + public function checkSymfonyPresent() { + return class_exists('Symfony\\Component\\HttpFoundation\\Session\\Session'); + } + + public function classCaseProvider() { + return array( + array('php', 'Php') + , array('php_binary', 'PhpBinary') + ); + } + + /** + * @dataProvider classCaseProvider + */ + public function testToClassCase($in, $out) { + if (!interface_exists('SessionHandlerInterface')) { + return $this->markTestSkipped('SessionHandlerInterface not defined. Requires PHP 5.4 or Symfony HttpFoundation'); + } + + $ref = new \ReflectionClass('\\Ratchet\\Component\\Session\\SessionComponent'); + $method = $ref->getMethod('toClassCase'); + $method->setAccessible(true); + + $component = new SessionComponent(new NullMessageComponent, new MemorySessionHandler); + $this->assertEquals($out, $method->invokeArgs($component, array($in))); + } + +/* Put this in test methods that require Symfony + if (false === $this->checkSymfonyPresent()) { + return $this->markTestSkipped('Symfony HttpFoundation not loaded'); + } +*/ +} \ No newline at end of file diff --git a/tests/Ratchet/Tests/Mock/MemorySessionHandler.php b/tests/Ratchet/Tests/Mock/MemorySessionHandler.php new file mode 100644 index 0000000..87e9953 --- /dev/null +++ b/tests/Ratchet/Tests/Mock/MemorySessionHandler.php @@ -0,0 +1,39 @@ +_sessions[$session_id])) { + unset($this->_sessions[$session_id]); + } + + return true; + } + + public function gc($maxlifetime) { + return true; + } + + public function open($save_path, $session_id) { + if (!isset($this->_sessions[$session_id])) { + $this->_sessions[$session_id] = ''; + } + + return true; + } + + public function read($session_id) { + return $this->_sessions[$session_id]; + } + + public function write($session_id, $session_data) { + $this->_sessions[$session_id] = $session_data; + + return true; + } +} \ No newline at end of file diff --git a/tests/Ratchet/Tests/Mock/NullMessageComponent.php b/tests/Ratchet/Tests/Mock/NullMessageComponent.php new file mode 100644 index 0000000..0f93fde --- /dev/null +++ b/tests/Ratchet/Tests/Mock/NullMessageComponent.php @@ -0,0 +1,55 @@ +connections = new \SplObjectStorage; + $this->messageHistory = new \SplQueue; + $this->errorHistory = new \SplQueue; + } + + /** + * {@inheritdoc} + */ + function onOpen(ConnectionInterface $conn) { + $this->connections->attach($conn); + } + + /** + * {@inheritdoc} + */ + function onMessage(ConnectionInterface $from, $msg) { + $this->messageHistory->enqueue(array('from' => $from, 'msg' => $msg)); + } + + /** + * {@inheritdoc} + */ + function onClose(ConnectionInterface $conn) { + $this->connections->detach($conn); + } + + /** + * {@inheritdoc} + */ + function onError(ConnectionInterface $conn, \Exception $e) { + $this->errorHistory->enqueue(array('conn' => $conn, 'exception' => $e)); + } +} \ No newline at end of file From 1e9665f6cd03351e4dcd7b6f3651095b542af6dd Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Thu, 29 Mar 2012 18:31:50 -0400 Subject: [PATCH 5/5] [Session] PDO Unit Test --- .../Session/SessionComponentTest.php | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/tests/Ratchet/Tests/Component/Session/SessionComponentTest.php b/tests/Ratchet/Tests/Component/Session/SessionComponentTest.php index 87020c9..f335e3e 100644 --- a/tests/Ratchet/Tests/Component/Session/SessionComponentTest.php +++ b/tests/Ratchet/Tests/Component/Session/SessionComponentTest.php @@ -3,17 +3,15 @@ namespace Ratchet\Tests\Component\Session; use Ratchet\Component\Session\SessionComponent; use Ratchet\Tests\Mock\NullMessageComponent; use Ratchet\Tests\Mock\MemorySessionHandler; +use Ratchet\Resource\Connection; +use Ratchet\Tests\Mock\FakeSocket; +use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; +use Guzzle\Http\Message\Request; /** * @covers Ratchet\Component\Session\SessionComponent */ class SessionComponentTest extends \PHPUnit_Framework_TestCase { - protected $_app; - - public function setUp() { -// $this->app = new SessionComponent - } - /** * @return bool */ @@ -44,9 +42,38 @@ class SessionComponentTest extends \PHPUnit_Framework_TestCase { $this->assertEquals($out, $method->invokeArgs($component, array($in))); } -/* Put this in test methods that require Symfony + /** + * I think I have severly butchered this test...it's not so much of a unit test as it is a full-fledged component test + */ + public function testConnectionValueFromPdo() { if (false === $this->checkSymfonyPresent()) { - return $this->markTestSkipped('Symfony HttpFoundation not loaded'); + return $this->markTestSkipped('Dependency of Symfony HttpFoundation failed'); } -*/ + + $sessionId = md5('testSession'); + + $dbOptions = array( + 'db_table' => 'sessions' + , 'db_id_col' => 'sess_id' + , 'db_data_col' => 'sess_data' + , 'db_time_col' => 'sess_time' + ); + + $pdo = new \PDO("sqlite::memory:"); + $pdo->exec(vsprintf("CREATE TABLE %s (%s VARCHAR(255) PRIMARY KEY, %s TEXT, %s INTEGER)", $dbOptions)); + $pdo->prepare(vsprintf("INSERT INTO %s (%s, %s, %s) VALUES (?, ?, ?)", $dbOptions))->execute(array($sessionId, base64_encode('_sf2_attributes|a:2:{s:5:"hello";s:5:"world";s:4:"last";i:1332872102;}_sf2_flashes|a:0:{}'), time())); + + $component = new SessionComponent(new NullMessageComponent, new PdoSessionHandler($pdo, $dbOptions), array('auto_start' => 1)); + $connection = new Connection(new FakeSocket); + + $headers = $this->getMock('Guzzle\\Http\\Message\\Request', array('getCookie'), array('POST', '/', array())); + $headers->expects($this->once())->method('getCookie', array(ini_get('session.name')))->will($this->returnValue($sessionId)); + + $connection->WebSocket = new \StdClass; + $connection->WebSocket->headers = $headers; + + $component->onOpen($connection); + + $this->assertEquals('world', $connection->Session->get('hello')); + } } \ No newline at end of file