merged branch drak/sessionhandlerinterface (PR #3384)

Commits
-------

2871ea0 Update composer for HttpFoundation's PHP 5.4 forward compatibility.
ff8d740 [Locale] Update documentation for autoloader.
dd2c4aa [HttpFoundation] Documentation.
e585ca7 [HttpFoundation] Added forward compatibility for \SessionHandlerInterface
d339e74 [ClassLoader] Add ability to incrementally register fallbacks.

Discussion
----------

[HttpFoundation] PHP 5.4 forward compatibility  for \Sessionhandlerinterface

Bug fix: no
Feature addition: yes
Backwards compatibility break: no
Symfony2 tests pass: yes
Fixes the following tickets: -
Todo: -

Utilising the same forward method as in Locale (as requested by @fabpot)

---------------------------------------------------------------------------

by stof at 2012-02-16T20:59:27Z

forward compatibility sent to the master branch, really ?

---------------------------------------------------------------------------

by stof at 2012-02-16T21:00:12Z

Ok, looking at the patch, it is not the same than places where we used the naming "forward compatibility". Sorry

---------------------------------------------------------------------------

by stof at 2012-02-16T21:01:56Z

As this fallback is mandatory to be able to use the component on 5.3, which is our target, please register the fallback in the composer.json file of the component and of the main repo so that it works out of the box when using Composer.

---------------------------------------------------------------------------

by drak at 2012-02-17T02:55:17Z

@stof as a native English speaker I find the terminology used in Symfony2 upside down. "Backward compatible" means compatible with past versions, i.e. legacy.  "Forward compatibility" logically means compatible with future versions - which in this case we are making an interface available in PHP 5.4, available in PHP 5.3.

I will try to adapt my in the context of Sf2's terminology :-)

---------------------------------------------------------------------------

by drak at 2012-02-17T02:56:43Z

Ah I see what you are saying, you mean normally things are made forward compatible from Symfony 2.0 to 2.1, and in this case we're making a native PHP interface forward compatible: so actually we are on the same page :)

---------------------------------------------------------------------------

by drak at 2012-02-17T02:59:00Z

@stof - I took a look at the `composer.json` and I also don't see and handling for the `Locale` component fallback (as written in `autoloader.php.dist`.  Is it even possible in Composer? /cc @Seldaek

---------------------------------------------------------------------------

by stof at 2012-02-17T07:03:44Z

@drak for the Locale, we don't register it through composer as we cannot do it fully: the stub functions are not autoloadable so it will always require some user work to do this. But for the HttpFoundation stub, it is possible as it is autoloadable:

```json
{
    autoload: {
        psr-0: {
            'Symfony\\Component\\HttpFoundation': '',
            '': 'Symfony/Component/HttpFoundation/Resources/stub'
        }
    }
}
```

---------------------------------------------------------------------------

by drak at 2012-02-17T08:11:56Z

Awesome @stof, thanks for the tip.

---------------------------------------------------------------------------

by drak at 2012-02-17T08:18:44Z

@stof do I also need to update the main repo's composer.json file too?

```
"autoload": {
        "psr-0": {
            "Symfony": "src/",
            "": "src/Symfony/Component/HttpFoundation/Resources/stub"
        }
    }

```

---------------------------------------------------------------------------

by Seldaek at 2012-02-17T08:54:46Z

I would use that in the autoload just to avoid file_exists calls for nothing:

```json
            "SessionHandlerInterface": "src/Symfony/Component/HttpFoundation/Resources/stub"
```

The class is part of the "prefix" too.

---------------------------------------------------------------------------

by drak at 2012-02-21T12:32:23Z

This is ready for merge @fabpot

---------------------------------------------------------------------------

by drak at 2012-02-21T16:20:43Z

@fabpot - done.
This commit is contained in:
Fabien Potencier 2012-02-22 10:12:06 +01:00
commit 96e9fddc6a
15 changed files with 220 additions and 184 deletions

View File

@ -20,7 +20,10 @@ $loader->registerPrefixes(array(
if (!function_exists('intl_get_error_code')) {
require_once __DIR__.'/src/Symfony/Component/Locale/Resources/stubs/functions.php';
$loader->registerPrefixFallbacks(array(__DIR__.'/src/Symfony/Component/Locale/Resources/stubs'));
$loader->registerPrefixFallback(__DIR__.'/src/Symfony/Component/Locale/Resources/stubs');
}
if (!interface_exists('SessionHandlerInterface', false)) {
$loader->registerPrefix('SessionHandlerInterface', __DIR__.'/src/Symfony/Component/HttpFoundation/Resources/stubs');
}
$loader->register();

View File

@ -56,6 +56,9 @@
"doctrine/data-fixtures": "1.0.*"
},
"autoload": {
"psr-0": { "Symfony": "src/" }
"psr-0": {
"Symfony": "src/",
"SessionHandlerInterface": "src/Symfony/Component/HttpFoundation/Resources/stub"
}
}
}

View File

@ -141,7 +141,17 @@ class UniversalClassLoader
}
/**
* Registers the directory to use as a fallback for class prefixes.
* Registers a directory to use as a fallback for namespaces.
*
* @param string $dir A directory
*/
public function registerNamespaceFallback($dir)
{
$this->namespaceFallbacks[] = $dir;
}
/**
* Registers directories to use as a fallback for class prefixes.
*
* @param array $dirs An array of directories
*
@ -152,6 +162,16 @@ class UniversalClassLoader
$this->prefixFallbacks = $dirs;
}
/**
* Registers a directory to use as a fallback for class prefixes.
*
* @param string $dir A directory
*/
public function registerPrefixFallback($dir)
{
$this->prefixFallbacks[] = $dir;
}
/**
* Registers an array of namespaces
*

View File

@ -28,6 +28,17 @@ And here is how to create and send a Response:
The Request and the Response classes have many other methods that implement
the HTTP specification.
Loading
-------
If you are using PHP 5.3.x you must add the following to your autoloader:
// SessionHandlerInterface
if (!interface_exists('SessionHandlerInterface')) {
$loader->registerPrefixFallback(__DIR__.'/../vendor/symfony/src/Symfony/Component/HttpFoundation/Resources/stubs');
}
Resources
---------

View File

@ -0,0 +1,155 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Session Savehandler Interface.
*
* This interface is for implementing methods required for the
* session_set_save_handler() function.
*
* @see http://php.net/session_set_save_handler
*
* These are methods called by PHP when the session is started
* and closed and for various house-keeping tasks required
* by session management.
*
* PHP requires session save handlers. There are some defaults set
* automatically when PHP starts, but these can be overriden using
* this command if you need anything other than PHP's default handling.
*
* When the session starts, PHP will call the read() handler
* which should return a string extactly as stored (which will have
* been encoded by PHP using a special session serializer session_decode()
* which is different to the serialize() function. PHP will then populate
* these into $_SESSION.
*
* When PHP shuts down, the write() handler is called and will pass
* the $_SESSION contents already serialized (using session_encode()) to
* be stored.
*
* When a session is specifically destroyed, PHP will call the
* destroy() handler with the session ID. This happens when the
* session is regenerated for example and th handler MUST delete the
* session by ID from the persistent storage immediately.
*
* PHP will call gc() from time to time to expire any session
* records according to the set max lifetime of a session. This routine
* should delete all records from persistent storage which were last
* accessed longer than the $lifetime.
*
* PHP open() and close() are pretty much redundant and
* can return true.
*
* @author Drak <drak@zikula.org>
*/
interface SessionHandlerInterface
{
/**
* Open session.
*
* This method is for internal use by PHP and must not be called manually.
*
* @param string $savePath Save path.
* @param string $sessionName Session Name.
*
* @throws \RuntimeException If something goes wrong starting the session.
*
* @return boolean
*/
function open($savePath, $sessionName);
/**
* Close session.
*
* This method is for internal use by PHP and must not be called manually.
*
* @return boolean
*/
function close();
/**
* Read session.
*
* This method is for internal use by PHP and must not be called manually.
*
* This method is called by PHP itself when the session is started.
* This method should retrieve the session data from storage by the
* ID provided by PHP. Return the string directly as is from storage.
* If the record was not found you must return an empty string.
*
* The returned data will be unserialized automatically by PHP using a
* special unserializer method session_decode() and the result will be used
* to populate the $_SESSION superglobal. This is done automatically and
* is not configurable.
*
* @param string $sessionId Session ID.
*
* @throws \RuntimeException On fatal error but not "record not found".
*
* @return string String as stored in persistent storage or empty string in all other cases.
*/
function read($sessionId);
/**
* Commit session to storage.
*
* This method is for internal use by PHP and must not be called manually.
*
* PHP will call this method when the session is closed. It sends
* the session ID and the contents of $_SESSION to be saved in a lightweight
* serialized format (which PHP does automatically using session_encode()
* which should be stored exactly as is given in $data.
*
* Note this method is normally called by PHP after the output buffers
* have been closed.
*
* @param string $sessionId Session ID.
* @param string $data Session serialized data to save.
*
* @throws \RuntimeException On fatal error.
*
* @return boolean
*/
function write($sessionId, $data);
/**
* Destroys this session.
*
* This method is for internal use by PHP and must not be called manually.
*
* PHP will call this method when the session data associated
* with the session ID provided needs to be immediately
* deleted from the permanent storage.
*
* @param string $sessionId Session ID.
*
* @throws \RuntimeException On fatal error.
*
* @return boolean
*/
function destroy($sessionId);
/**
* Garbage collection for storage.
*
* This method is for internal use by PHP and must not be called manually.
*
* This method is called by PHP periodically and passes the maximum
* time a session can exist for before being deleted from permanent storage.
*
* @param integer $lifetime Max lifetime in seconds to keep sessions stored.
*
* @throws \RuntimeException On fatal error.
*
* @return boolean
*/
function gc($lifetime);
}

View File

@ -13,11 +13,6 @@ namespace Symfony\Component\HttpFoundation\Session\Storage;
use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
// force load forward compatability for PHP 5.4's SessionHandlerInterface if necessary.
if (version_compare(phpversion(), '5.4.0', '<')) {
interface_exists('Symfony\Component\HttpFoundation\Session\Storage\SessionHandlerInterface');
}
/**
* This provides a base class for session attribute storage.
*
@ -283,7 +278,7 @@ abstract class AbstractSessionStorage implements SessionStorageInterface
{
// 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 || $this instanceof SessionHandlerInterface) {
if ($this instanceof \SessionHandlerInterface) {
session_set_save_handler(
array($this, 'open'),
array($this, 'close'),

View File

@ -16,7 +16,7 @@ namespace Symfony\Component\HttpFoundation\Session\Storage;
*
* @author Drak <drak@zikula.org>
*/
class MemcacheSessionStorage extends AbstractSessionStorage implements SessionHandlerInterface
class MemcacheSessionStorage extends AbstractSessionStorage implements \SessionHandlerInterface
{
/**
* Memcache driver.

View File

@ -16,7 +16,7 @@ namespace Symfony\Component\HttpFoundation\Session\Storage;
*
* @author Drak <drak@zikula.org>
*/
class MemcachedSessionStorage extends AbstractSessionStorage implements SessionHandlerInterface
class MemcachedSessionStorage extends AbstractSessionStorage implements \SessionHandlerInterface
{
/**
* Memcached driver.

View File

@ -20,7 +20,7 @@ namespace Symfony\Component\HttpFoundation\Session\Storage;
*
* @api
*/
class NullSessionStorage extends AbstractSessionStorage implements SessionHandlerInterface
class NullSessionStorage extends AbstractSessionStorage implements \SessionHandlerInterface
{
/**
* {@inheritdoc}

View File

@ -17,7 +17,7 @@ namespace Symfony\Component\HttpFoundation\Session\Storage;
* @author Fabien Potencier <fabien@symfony.com>
* @author Michael Williams <michael.williams@funsational.com>
*/
class PdoSessionStorage extends AbstractSessionStorage implements SessionHandlerInterface
class PdoSessionStorage extends AbstractSessionStorage implements \SessionHandlerInterface
{
/**
* PDO instance.

View File

@ -1,167 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace
{
if (!interface_exists('SessionHandlerInterface', false)) {
/**
* Session Savehandler Interface.
*
* This interface is for implementing methods required for the
* session_set_save_handler() function.
*
* @see http://php.net/session_set_save_handler
*
* These are methods called by PHP when the session is started
* and closed and for various house-keeping tasks required
* by session management.
*
* PHP requires session save handlers. There are some defaults set
* automatically when PHP starts, but these can be overriden using
* this command if you need anything other than PHP's default handling.
*
* When the session starts, PHP will call the read() handler
* which should return a string extactly as stored (which will have
* been encoded by PHP using a special session serializer session_decode()
* which is different to the serialize() function. PHP will then populate
* these into $_SESSION.
*
* When PHP shuts down, the write() handler is called and will pass
* the $_SESSION contents already serialized (using session_encode()) to
* be stored.
*
* When a session is specifically destroyed, PHP will call the
* destroy() handler with the session ID. This happens when the
* session is regenerated for example and th handler MUST delete the
* session by ID from the persistent storage immediately.
*
* PHP will call gc() from time to time to expire any session
* records according to the set max lifetime of a session. This routine
* should delete all records from persistent storage which were last
* accessed longer than the $lifetime.
*
* PHP open() and close() are pretty much redundant and
* can return true.
*
* @author Drak <drak@zikula.org>
*/
interface SessionHandlerInterface
{
/**
* Open session.
*
* This method is for internal use by PHP and must not be called manually.
*
* @param string $savePath Save path.
* @param string $sessionName Session Name.
*
* @throws \RuntimeException If something goes wrong starting the session.
*
* @return boolean
*/
function open($savePath, $sessionName);
/**
* Close session.
*
* This method is for internal use by PHP and must not be called manually.
*
* @return boolean
*/
function close();
/**
* Read session.
*
* This method is for internal use by PHP and must not be called manually.
*
* This method is called by PHP itself when the session is started.
* This method should retrieve the session data from storage by the
* ID provided by PHP. Return the string directly as is from storage.
* If the record was not found you must return an empty string.
*
* The returned data will be unserialized automatically by PHP using a
* special unserializer method session_decode() and the result will be used
* to populate the $_SESSION superglobal. This is done automatically and
* is not configurable.
*
* @param string $sessionId Session ID.
*
* @throws \RuntimeException On fatal error but not "record not found".
*
* @return string String as stored in persistent storage or empty string in all other cases.
*/
function read($sessionId);
/**
* Commit session to storage.
*
* This method is for internal use by PHP and must not be called manually.
*
* PHP will call this method when the session is closed. It sends
* the session ID and the contents of $_SESSION to be saved in a lightweight
* serialized format (which PHP does automatically using session_encode()
* which should be stored exactly as is given in $data.
*
* Note this method is normally called by PHP after the output buffers
* have been closed.
*
* @param string $sessionId Session ID.
* @param string $data Session serialized data to save.
*
* @throws \RuntimeException On fatal error.
*
* @return boolean
*/
function write($sessionId, $data);
/**
* Destroys this session.
*
* This method is for internal use by PHP and must not be called manually.
*
* PHP will call this method when the session data associated
* with the session ID provided needs to be immediately
* deleted from the permanent storage.
*
* @param string $sessionId Session ID.
*
* @throws \RuntimeException On fatal error.
*
* @return boolean
*/
function destroy($sessionId);
/**
* Garbage collection for storage.
*
* This method is for internal use by PHP and must not be called manually.
*
* This method is called by PHP periodically and passes the maximum
* time a session can exist for before being deleted from permanent storage.
*
* @param integer $lifetime Max lifetime in seconds to keep sessions stored.
*
* @throws \RuntimeException On fatal error.
*
* @return boolean
*/
function gc($lifetime);
}
}
}
namespace Symfony\Component\HttpFoundation\Session\Storage
{
interface SessionHandlerInterface extends \SessionHandlerInterface
{
}
}

View File

@ -20,7 +20,10 @@
"php": ">=5.3.2"
},
"autoload": {
"psr-0": { "Symfony\\Component\\HttpFoundation": "" }
"psr-0": {
"Symfony\\Component\\HttpFoundation": "",
"SessionHandlerInterface": "Symfony/Component/HttpFoundation/Resources/stub"
}
},
"target-dir": "Symfony/Component/HttpFoundation"
}

View File

@ -11,7 +11,7 @@ requires adding the following lines to your autoloader:
if (!function_exists('intl_get_error_code')) {
require __DIR__.'/../vendor/symfony/src/Symfony/Component/Locale/Resources/stubs/functions.php';
$loader->registerPrefixFallbacks(array(__DIR__.'/../vendor/symfony/src/Symfony/Component/Locale/Resources/stubs'));
$loader->registerPrefixFallback(__DIR__.'/../vendor/symfony/src/Symfony/Component/Locale/Resources/stubs');
}
Resources

View File

@ -80,6 +80,20 @@ class UniversalClassLoaderTest extends \PHPUnit_Framework_TestCase
);
}
public function testRegisterPrefixFallback()
{
$loader = new UniversalClassLoader();
$loader->registerPrefixFallback(__DIR__.DIRECTORY_SEPARATOR.'Fixtures/fallback');
$this->assertEquals(array(__DIR__.DIRECTORY_SEPARATOR.'Fixtures/fallback'), $loader->getPrefixFallbacks());
}
public function testRegisterNamespaceFallback()
{
$loader = new UniversalClassLoader();
$loader->registerNamespaceFallback(__DIR__.DIRECTORY_SEPARATOR.'Fixtures/Namespaced/fallback');
$this->assertEquals(array(__DIR__.DIRECTORY_SEPARATOR.'Fixtures/Namespaced/fallback'), $loader->getNamespaceFallbacks());
}
/**
* @dataProvider getLoadClassNamespaceCollisionTests
*/

View File

@ -5,7 +5,6 @@ namespace Symfony\Tests\Component\HttpFoundation\Session\Storage;
use Symfony\Component\HttpFoundation\Session\Storage\AbstractSessionStorage;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
use Symfony\Component\HttpFoundation\Session\Storage\SessionHandlerInterface;
/**
* Turn AbstractSessionStorage into something concrete because
@ -16,7 +15,7 @@ class ConcreteSessionStorage extends AbstractSessionStorage
{
}
class CustomHandlerSessionStorage extends AbstractSessionStorage implements SessionHandlerInterface
class CustomHandlerSessionStorage extends AbstractSessionStorage implements \SessionHandlerInterface
{
public function open($path, $id)
{