Skip to content

[2.1][HttpFoundation] Added some basic meta-data to Session #3718

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 8 commits into from Apr 3, 2012
3 changes: 3 additions & 0 deletions CHANGELOG-2.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,9 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c
* Flash API can stores messages in an array so there may be multiple messages
per flash type. The old `Session` class API remains without BC break as it
will single messages as before.
* Added basic session meta-data to the session to record session create time,
last updated time, and the lifetime of the session cookie that was provided
to the client.

### HttpKernel

Expand Down
79 changes: 41 additions & 38 deletions src/Symfony/Component/HttpFoundation/Session/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\Component\HttpFoundation\Session;

use Symfony\Component\HttpFoundation\Session\Storage\MetadataBag;
use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
Expand Down Expand Up @@ -57,13 +58,13 @@ public function __construct(SessionStorageInterface $storage = null, AttributeBa
{
$this->storage = $storage ?: new NativeSessionStorage();

$attributeBag = $attributes ?: new AttributeBag();
$this->attributeName = $attributeBag->getName();
$this->registerBag($attributeBag);
$attributes = $attributes ?: new AttributeBag();
$this->attributeName = $attributes->getName();
$this->registerBag($attributes);

$flashBag = $flashes ?: new FlashBag();
$this->flashName = $flashBag->getName();
$this->registerBag($flashBag);
$flashes = $flashes ?: new FlashBag();
$this->flashName = $flashes->getName();
$this->registerBag($flashes);
}

/**
Expand Down Expand Up @@ -130,22 +131,42 @@ public function clear()
$this->storage->getBag($this->attributeName)->clear();
}

/**
* Returns an iterator for attributes.
*
* @return \ArrayIterator An \ArrayIterator instance
*/
public function getIterator()
{
return new \ArrayIterator($this->storage->getBag($this->attributeName)->all());
}

/**
* Returns the number of attributes.
*
* @return int The number of attributes
*/
public function count()
{
return count($this->storage->getBag($this->attributeName)->all());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't be simpler to implement such count in that bag ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not part of this PR - the method were just moved within the file.

}

/**
* {@inheritdoc}
*/
public function invalidate()
public function invalidate($lifetime = null)
{
$this->storage->clear();

return $this->storage->regenerate(true);
return $this->migrate(true, $lifetime);
}

/**
* {@inheritdoc}
*/
public function migrate($destroy = false)
public function migrate($destroy = false, $lifetime = null)
{
return $this->storage->regenerate($destroy);
return $this->storage->regenerate($destroy, $lifetime);
}

/**
Expand Down Expand Up @@ -189,21 +210,23 @@ public function setName($name)
}

/**
* Registers a SessionBagInterface with the session.
*
* @param SessionBagInterface $bag
* {@iheritdoc}
*/
public function getMetadataBag()
{
return $this->storage->getMetadataBag();
}

/**
* {@iheritdoc}
*/
public function registerBag(SessionBagInterface $bag)
{
$this->storage->registerBag($bag);
}

/**
* Get's a bag instance.
*
* @param string $name
*
* @return SessionBagInterface
* {@iheritdoc}
*/
public function getBag($name)
{
Expand Down Expand Up @@ -310,24 +333,4 @@ public function clearFlashes()
{
return $this->getBag($this->flashName)->clear();
}

/**
* Returns an iterator for attributes.
*
* @return \ArrayIterator An \ArrayIterator instance
*/
public function getIterator()
{
return new \ArrayIterator($this->storage->getBag('attributes')->all());
}

/**
* Returns the number of attributes.
*
* @return int The number of attributes
*/
public function count()
{
return count($this->storage->getBag('attributes')->all());
}
}
38 changes: 35 additions & 3 deletions src/Symfony/Component/HttpFoundation/Session/SessionInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,23 +71,32 @@ function setName($name);
* Clears all session attributes and flashes and regenerates the
* session and deletes the old session from persistence.
*
* @param integer $lifetime Sets the cookie lifetime for the session cookie. A null value
* will leave the system settings unchanged, 0 sets the cookie
* to expire with browser session. Time is in seconds, and is
* not a Unix timestamp.
*
* @return Boolean True if session invalidated, false if error.
*
* @api
*/
function invalidate();
function invalidate($lifetime = null);

/**
* Migrates the current session to a new session id while maintaining all
* session attributes.
*
* @param Boolean $destroy Whether to delete the old session or leave it to garbage collection.
* @param Boolean $destroy Whether to delete the old session or leave it to garbage collection.
* @param integer $lifetime Sets the cookie lifetime for the session cookie. A null value
* will leave the system settings unchanged, 0 sets the cookie
* to expire with browser session. Time is in seconds, and is
* not a Unix timestamp.
*
* @return Boolean True if session migrated, false if error.
*
* @api
*/
function migrate($destroy = false);
function migrate($destroy = false, $lifetime = null);

/**
* Force the session to be saved and closed.
Expand Down Expand Up @@ -164,4 +173,27 @@ function remove($name);
* @api
*/
function clear();

/**
* Registers a SessionBagInterface with the session.
*
* @param SessionBagInterface $bag
*/
public function registerBag(SessionBagInterface $bag);

/**
* Gets a bag instance by name.
*
* @param string $name
*
* @return SessionBagInterface
*/
public function getBag($name);

/**
* Gets session meta.
*
* @return MetadataBag
*/
public function getMetadataBag();
}
160 changes: 160 additions & 0 deletions src/Symfony/Component/HttpFoundation/Session/Storage/MetadataBag.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
<?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\Component\HttpFoundation\Session\Storage;

use Symfony\Component\HttpFoundation\Session\SessionBagInterface;

/**
* Metadata container.
*
* Adds metadata to the session.
*
* @author Drak <drak@zikula.org>
*/
class MetadataBag implements SessionBagInterface
{
const CREATED = 'c';
const UPDATED = 'u';
const LIFETIME = 'l';

/**
* @var string
*/
private $name = '__metadata';

/**
* @var string
*/
private $storageKey;

/**
* @var array
*/
protected $meta = array();

/**
* Unix timestamp.
*
* @var integer
*/
private $lastUsed;

/**
* Constructor.
*
* @param string $storageKey The key used to store bag in the session.
*/
public function __construct($storageKey = '_sf2_meta')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You missed _sf2_metadata

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the keys here dont matter, it's purely internal to avoid name clashes - it just needs to be sufficiently obscure.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know. For God's sake, it's just for consistency.

{
$this->storageKey = $storageKey;
$this->meta = array(self::CREATED => 0, self::UPDATED => 0, self::LIFETIME => 0);
}

/**
* {@inheritdoc}
*/
public function initialize(array &$array)
{
$this->meta = &$array;

if (isset($array[self::CREATED])) {
$this->lastUsed = $this->meta[self::UPDATED];
$this->meta[self::UPDATED] = time();
} else {
$this->stampCreated();
}
}

/**
* Gets the lifetime that the session cookie was set with.
*
* @return integer
*/
public function getLifetime()
{
return $this->meta[self::LIFETIME];
}

/**
* Stamps a new session's metadata.
*
* @param integer $lifetime Sets the cookie lifetime for the session cookie. A null value
* will leave the system settings unchanged, 0 sets the cookie
* to expire with browser session. Time is in seconds, and is
* not a Unix timestamp.
*/
public function stampNew($lifetime = null)
{
$this->stampCreated($lifetime);
}

/**
* {@inheritdoc}
*/
public function getStorageKey()
{
return $this->storageKey;
}

/**
* Gets the created timestamp metadata.
*
* @return integer Unix timestamp
*/
public function getCreated()
{
return $this->meta[self::CREATED];
}

/**
* Gets the last used metadata.
*
* @return integer Unix timestamp
*/
public function getLastUsed()
{
return $this->lastUsed;
}

/**
* {@inheritdoc}
*/
public function clear()
{
// nothing to do
}

/**
* {@inheritdoc}
*/
public function getName()
{
return $this->name;
}

/**
* Sets name.
*
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}

private function stampCreated($lifetime = null)
{
$timeStamp = time();
$this->meta[self::CREATED] = $this->meta[self::UPDATED] = $this->lastUsed = $timeStamp;
$this->meta[self::LIFETIME] = (null === $lifetime) ? ini_get('session.cookie_lifetime') : $lifetime;
}
}
Loading