Skip to content

[2.1] Support PHP 5.4 \SessionHandler #3493

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from Mar 15, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 52 additions & 31 deletions CHANGELOG-2.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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

Expand Down Expand Up @@ -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

Expand Down
27 changes: 21 additions & 6 deletions UPGRADE-2.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
```

Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
<?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 Symfony\Bridge\Doctrine\HttpFoundation;

use Doctrine\DBAL\Platforms\MySqlPlatform;
use Symfony\Component\HttpFoundation\Session\Storage\AbstractSessionStorage;
use Doctrine\DBAL\Driver\Connection;

/**
Expand All @@ -12,7 +20,7 @@
* @author Fabien Potencier <fabien@symfony.com>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class DbalSessionStorage extends AbstractSessionStorage implements \SessionHandlerInterface
class DbalSessionHandler implements \SessionHandlerInterface
{
/**
* @var Connection
Expand All @@ -25,36 +33,27 @@ 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)
{
return true;
}

/**
* Closes a session.
*
* @return Boolean true, if the session was closed, otherwise false
* {@inheritdoc}
*/
public function close()
{
Expand All @@ -63,13 +62,7 @@ public function close()
}

/**
* Destroys a session.
*
* @param string $id A session ID
*
* @return Boolean true, if the session was destroyed, otherwise an exception is thrown
*
* @throws \RuntimeException If the session cannot be destroyed
* {@inheritdoc}
*/
public function destroy($id)
{
Expand All @@ -85,13 +78,7 @@ public function destroy($id)
}

/**
* Cleans up old sessions.
*
* @param int $lifetime The lifetime of a session
*
* @return Boolean true, if old sessions have been cleaned, otherwise an exception is thrown
*
* @throws \RuntimeException If any old sessions cannot be cleaned
* {@inheritdoc}
*/
public function gc($lifetime)
{
Expand All @@ -107,13 +94,7 @@ public function gc($lifetime)
}

/**
* Reads a session.
*
* @param string $id A session ID
*
* @return string The session data if the session was read or created, otherwise an exception is thrown
*
* @throws \RuntimeException If the session cannot be read
* {@inheritdoc}
*/
public function read($id)
{
Expand All @@ -136,14 +117,7 @@ public function read($id)
}

/**
* Writes session data.
*
* @param string $id A session ID
* @param string $data A serialized chunk of session data
*
* @return Boolean true, if the session was written, otherwise an exception is thrown
*
* @throws \RuntimeException If the session data cannot be written
* {@inheritdoc}
*/
public function write($id, $data)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
<?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 Symfony\Bridge\Doctrine\HttpFoundation;

use Doctrine\DBAL\Schema\Schema;
Expand All @@ -9,7 +18,7 @@
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
final class DbalSessionStorageSchema extends Schema
final class DbalSessionHandlerSchema extends Schema
{
private $tableName;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ private function addSessionSection(ArrayNodeDefinition $rootNode)
->canBeUnset()
->children()
->booleanNode('auto_start')->defaultFalse()->end()
->scalarNode('storage_id')->defaultValue('session.storage.native_file')->end()
->scalarNode('storage_id')->defaultValue('session.storage.native')->end()
->scalarNode('handler_id')->defaultValue('session.handler.native_file')->end()
->scalarNode('name')->end()
->scalarNode('cookie_lifetime')->end()
->scalarNode('cookie_path')->end()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,10 +310,16 @@ private function registerSessionConfiguration(array $config, ContainerBuilder $c
}
$container->setParameter('session.storage.options', $options);

// session handler (the internal callback registered with PHP session management)
$container->setAlias('session.handler', $config['handler_id']);

$this->addClassesToCompile(array(
'Symfony\\Bundle\\FrameworkBundle\\EventListener\\SessionListener',
'Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorageInterface',
'Symfony\\Component\\HttpFoundation\\Session\\Storage\\AbstractSessionStorage',
'Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorage',
'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(),
));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,14 @@
*/
class SessionListener implements EventSubscriberInterface
{
/**
* @var ContainerInterface
*/
private $container;

/**
* @var boolean
*/
private $autoStart;

public function __construct(ContainerInterface $container, $autoStart = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,16 @@ public function onKernelRequest(GetResponseEvent $event)
}

// bootstrap the session
if ($this->container->has('session')) {
$this->container->get('session');
if (!$this->container->has('session')) {
return;
}

$session = $this->container->get('session');
$cookies = $event->getRequest()->cookies;
if ($cookies->has(session_name())) {
session_id($cookies->get(session_name()));
if ($cookies->has($session->getName())) {
$session->setId($cookies->get($session->getName()));
} else {
session_id('');
$session->setId('');
}
}

Expand All @@ -72,7 +73,7 @@ public function onKernelResponse(FilterResponseEvent $event)

$params = session_get_cookie_params();

$event->getResponse()->headers->setCookie(new Cookie(session_name(), session_id(), 0 === $params['lifetime'] ? 0 : time() + $params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly']));
$event->getResponse()->headers->setCookie(new Cookie($session->getName(), $session->getId(), 0 === $params['lifetime'] ? 0 : time() + $params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly']));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@

<xsd:complexType name="session">
<xsd:attribute name="storage-id" type="xsd:string" />
<xsd:attribute name="handler-id" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="cookie-lifetime" type="xsd:integer" />
<xsd:attribute name="cookie-path" type="xsd:string" />
Expand Down
Loading