[HttpFoundation] Added AttributesInterface and AttributesBagInterface and concrete implementations.
This commit outsources session attribute storage to it's own class. There are two concrete implementations, one with structured namespace storage and the other without.
This commit is contained in:
parent
92cb685ebc
commit
39288bcdaa
119
src/Symfony/Component/HttpFoundation/AttributeBag.php
Normal file
119
src/Symfony/Component/HttpFoundation/AttributeBag.php
Normal file
@ -0,0 +1,119 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* This class relates to session attribute storage
|
||||
*/
|
||||
class AttributeBag implements AttributeBagInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $storageKey;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $attributes = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param type $storageKey The key used to store flashes in the session.
|
||||
*/
|
||||
public function __construct($storageKey = '_sf2_attributes')
|
||||
{
|
||||
$this->storageKey = $storageKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function initialize(array &$attributes)
|
||||
{
|
||||
$this->attributes = &$attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getStorageKey()
|
||||
{
|
||||
return $this->storageKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
return array_key_exists($name, $this->attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($name, $default = null)
|
||||
{
|
||||
return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($name, $value)
|
||||
{
|
||||
$this->attributes[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function replace(array $attributes)
|
||||
{
|
||||
$this->attributes = array();
|
||||
foreach ($attributes as $key => $value) {
|
||||
$this->set($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
$retval = null;
|
||||
if (array_key_exists($name, $this->attributes)) {
|
||||
$retval = $this->attributes[$name];
|
||||
unset($this->attributes[$name]);
|
||||
}
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->attributes = array();
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\HttpFoundation\AttributeBagInterface;
|
||||
use Symfony\Component\HttpFoundation\SessionStorage\AttributeInterface;
|
||||
|
||||
/**
|
||||
* Attributes store.
|
||||
*
|
||||
* @author Drak <drak@zikula.org>
|
||||
*/
|
||||
interface AttributeBagInterface extends AttributeInterface
|
||||
{
|
||||
/**
|
||||
* Initializes the AttributeBag
|
||||
*
|
||||
* @param array $attributes
|
||||
*/
|
||||
function initialize(array &$attributes);
|
||||
|
||||
/**
|
||||
* Gets the storage key for this bag.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getStorageKey();
|
||||
}
|
181
src/Symfony/Component/HttpFoundation/NamespacedAttributeBag.php
Normal file
181
src/Symfony/Component/HttpFoundation/NamespacedAttributeBag.php
Normal file
@ -0,0 +1,181 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* This class provides structured storage of session attributes using
|
||||
* a name spacing character in the key.
|
||||
*
|
||||
* @author Drak <drak@zikula.org>
|
||||
*/
|
||||
class NamespacedAttributeBag extends AttributeBag
|
||||
{
|
||||
/**
|
||||
* Namespace character.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $namespaceCharacter;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param type $storageKey Session storage key.
|
||||
* @param type $namespaceCharacter Namespace character to use in keys.
|
||||
*/
|
||||
public function __construct($storageKey = '_sf2_attributes', $namespaceCharacter = '/')
|
||||
{
|
||||
$this->namespaceCharacter = $namespaceCharacter;
|
||||
parent::__construct($storageKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
$attributes = $this->resolveAttributePath($name);
|
||||
$name = $this->resolveKey($name);
|
||||
|
||||
return array_key_exists($name, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($name, $default = null)
|
||||
{
|
||||
$attributes = $this->resolveAttributePath($name);
|
||||
$name = $this->resolveKey($name);
|
||||
|
||||
return array_key_exists($name, $attributes) ? $attributes[$name] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($name, $value)
|
||||
{
|
||||
$attributes = & $this->resolveAttributePath($name, true);
|
||||
$name = $this->resolveKey($name);
|
||||
$attributes[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function replace(array $attributes)
|
||||
{
|
||||
$this->attributes = array();
|
||||
foreach ($attributes as $key => $value) {
|
||||
$this->set($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
$retval = null;
|
||||
$attributes = & $this->resolveAttributePath($name);
|
||||
$name = $this->resolveKey($name);
|
||||
if (array_key_exists($name, $attributes)) {
|
||||
$retval = $attributes[$name];
|
||||
unset($attributes[$name]);
|
||||
}
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->attributes = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a path in attributes property and returns it as a reference.
|
||||
*
|
||||
* This method allows structured namespacing of session attributes.
|
||||
*
|
||||
* @param string $name Key name
|
||||
* @param boolean $writeContext Write context, default false
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function &resolveAttributePath($name, $writeContext = false)
|
||||
{
|
||||
$array = & $this->attributes;
|
||||
$name = (strpos($name, $this->namespaceCharacter) === 0) ? substr($name, 1) : $name;
|
||||
|
||||
// Check if there is anything to do, else return
|
||||
if (!$name) {
|
||||
return $array;
|
||||
}
|
||||
|
||||
$parts = explode($this->namespaceCharacter, $name);
|
||||
if (count($parts) < 2) {
|
||||
if (!$writeContext) {
|
||||
return $array;
|
||||
}
|
||||
|
||||
$array[$parts[0]] = array();
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
unset($parts[count($parts)-1]);
|
||||
|
||||
foreach ($parts as $part) {
|
||||
if (!array_key_exists($part, $array)) {
|
||||
if (!$writeContext) {
|
||||
return $array;
|
||||
}
|
||||
|
||||
$array[$part] = array();
|
||||
}
|
||||
|
||||
$array = & $array[$part];
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the key from the name.
|
||||
*
|
||||
* This is the last part in a dot separated string.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function resolveKey($name)
|
||||
{
|
||||
if (strpos($name, $this->namespaceCharacter) !== false) {
|
||||
$name = substr($name, strrpos($name, $this->namespaceCharacter)+1, strlen($name));
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
<?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\SessionStorage;
|
||||
|
||||
/**
|
||||
* Interface for the session.
|
||||
*
|
||||
* @author Drak <drak@zikula.org>
|
||||
*/
|
||||
interface AttributeInterface
|
||||
{
|
||||
/**
|
||||
* Checks if an attribute is defined.
|
||||
*
|
||||
* @param string $name The attribute name
|
||||
*
|
||||
* @return Boolean true if the attribute is defined, false otherwise
|
||||
*/
|
||||
function has($name);
|
||||
|
||||
/**
|
||||
* Returns an attribute.
|
||||
*
|
||||
* @param string $name The attribute name
|
||||
* @param mixed $default The default value if not found.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function get($name, $default = null);
|
||||
|
||||
/**
|
||||
* Sets an attribute.
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
function set($name, $value);
|
||||
|
||||
/**
|
||||
* Returns attributes.
|
||||
*
|
||||
* @return array Attributes
|
||||
*/
|
||||
function all();
|
||||
|
||||
/**
|
||||
* Sets attributes.
|
||||
*
|
||||
* @param array $attributes Attributes
|
||||
*/
|
||||
function replace(array $attributes);
|
||||
|
||||
/**
|
||||
* Removes an attribute.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
function remove($name);
|
||||
|
||||
/**
|
||||
* Clears all attributes.
|
||||
*/
|
||||
function clear();
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Tests\Component\HttpFoundation;
|
||||
use Symfony\Component\HttpFoundation\AttributeBag;
|
||||
|
||||
|
||||
/**
|
||||
* Tests AttributeBag
|
||||
*
|
||||
* @author Drak <drak@zikula.org>
|
||||
*/
|
||||
class AttributeBagTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $array;
|
||||
|
||||
/**
|
||||
* @var AttributeBag
|
||||
*/
|
||||
private $bag;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->array = array(
|
||||
'hello' => 'world',
|
||||
'always' => 'be happy',
|
||||
'user.login' => 'drak',
|
||||
'csrf.token' => array(
|
||||
'a' => '1234',
|
||||
'b' => '4321',
|
||||
),
|
||||
'category' => array(
|
||||
'fishing' => array(
|
||||
'first' => 'cod',
|
||||
'second' => 'sole')
|
||||
),
|
||||
);
|
||||
$this->bag = new AttributeBag('_sf2');
|
||||
$this->bag->initialize($this->array);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
$this->bag = null;
|
||||
$this->array = array();
|
||||
}
|
||||
|
||||
public function testInitialize()
|
||||
{
|
||||
$bag = new AttributeBag();
|
||||
$bag->initialize($this->array);
|
||||
$this->assertEquals($this->array, $bag->all());
|
||||
$array = array('should' => 'change');
|
||||
$bag->initialize($array);
|
||||
$this->assertEquals($array, $bag->all());
|
||||
}
|
||||
|
||||
public function testGetStorageKey()
|
||||
{
|
||||
$this->assertEquals('_sf2', $this->bag->getStorageKey());
|
||||
$attributeBag = new AttributeBag('test');
|
||||
$this->assertEquals('test', $attributeBag->getStorageKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider attributesProvider
|
||||
*/
|
||||
public function testHas($key, $value, $exists)
|
||||
{
|
||||
$this->assertEquals($exists, $this->bag->has($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider attributesProvider
|
||||
*/
|
||||
public function testGet($key, $value, $expected)
|
||||
{
|
||||
$this->assertEquals($value, $this->bag->get($key));
|
||||
}
|
||||
|
||||
public function testGetDefaults()
|
||||
{
|
||||
$this->assertNull($this->bag->get('user2.login'));
|
||||
$this->assertEquals('default', $this->bag->get('user2.login', 'default'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider attributesProvider
|
||||
*/
|
||||
public function testSet($key, $value, $expected)
|
||||
{
|
||||
$this->bag->set($key, $value);
|
||||
$this->assertEquals($value, $this->bag->get($key));
|
||||
}
|
||||
|
||||
public function testAll()
|
||||
{
|
||||
$this->assertEquals($this->array, $this->bag->all());
|
||||
|
||||
$this->bag->set('hello', 'fabien');
|
||||
$array = $this->array;
|
||||
$array['hello'] = 'fabien';
|
||||
$this->assertEquals($array, $this->bag->all());
|
||||
}
|
||||
|
||||
public function testReplace()
|
||||
{
|
||||
$array = array();
|
||||
$array['name'] = 'jack';
|
||||
$array['foo.bar'] = 'beep';
|
||||
$this->bag->replace($array);
|
||||
$this->assertEquals($array, $this->bag->all());
|
||||
$this->assertNull($this->bag->get('hello'));
|
||||
$this->assertNull($this->bag->get('always'));
|
||||
$this->assertNull($this->bag->get('user.login'));
|
||||
}
|
||||
|
||||
public function testRemove()
|
||||
{
|
||||
$this->assertEquals('world', $this->bag->get('hello'));
|
||||
$this->bag->remove('hello');
|
||||
$this->assertNull($this->bag->get('hello'));
|
||||
|
||||
$this->assertEquals('be happy', $this->bag->get('always'));
|
||||
$this->bag->remove('always');
|
||||
$this->assertNull($this->bag->get('always'));
|
||||
|
||||
$this->assertEquals('drak', $this->bag->get('user.login'));
|
||||
$this->bag->remove('user.login');
|
||||
$this->assertNull($this->bag->get('user.login'));
|
||||
}
|
||||
|
||||
public function testClear()
|
||||
{
|
||||
$this->bag->clear();
|
||||
$this->assertEquals(array(), $this->bag->all());
|
||||
}
|
||||
|
||||
public function attributesProvider()
|
||||
{
|
||||
return array(
|
||||
array('hello', 'world', true),
|
||||
array('always', 'be happy', true),
|
||||
array('user.login', 'drak', true),
|
||||
array('csrf.token', array('a' => '1234', 'b' => '4321'), true),
|
||||
array('category', array('fishing' => array('first' => 'cod', 'second' => 'sole')), true),
|
||||
array('user2.login', null, false),
|
||||
array('never', null, false),
|
||||
array('bye', null, false),
|
||||
array('bye/for/now', null, false),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Tests\Component\HttpFoundation;
|
||||
|
||||
use Symfony\Component\HttpFoundation\NamespacedAttributeBag;
|
||||
|
||||
/**
|
||||
* Tests NamespacedAttributeBag
|
||||
*
|
||||
* @author Drak <drak@zikula.org>
|
||||
*/
|
||||
class NamespacedAttributeBagTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $array;
|
||||
|
||||
/**
|
||||
* @var NamespacedAttributeBag
|
||||
*/
|
||||
private $bag;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->array = array(
|
||||
'hello' => 'world',
|
||||
'always' => 'be happy',
|
||||
'user.login' => 'drak',
|
||||
'csrf.token' => array(
|
||||
'a' => '1234',
|
||||
'b' => '4321',
|
||||
),
|
||||
'category' => array(
|
||||
'fishing' => array(
|
||||
'first' => 'cod',
|
||||
'second' => 'sole')
|
||||
),
|
||||
);
|
||||
$this->bag = new NamespacedAttributeBag('_sf2', '/');
|
||||
$this->bag->initialize($this->array);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
$this->bag = null;
|
||||
$this->array = array();
|
||||
}
|
||||
|
||||
public function testInitialize()
|
||||
{
|
||||
$bag = new NamespacedAttributeBag();
|
||||
$bag->initialize($this->array);
|
||||
$this->assertEquals($this->array, $this->bag->all());
|
||||
$array = array('should' => 'not stick');
|
||||
$bag->initialize($array);
|
||||
|
||||
// should have remained the same
|
||||
$this->assertEquals($this->array, $this->bag->all());
|
||||
}
|
||||
|
||||
public function testGetStorageKey()
|
||||
{
|
||||
$this->assertEquals('_sf2', $this->bag->getStorageKey());
|
||||
$attributeBag = new NamespacedAttributeBag('test');
|
||||
$this->assertEquals('test', $attributeBag->getStorageKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider attributesProvider
|
||||
*/
|
||||
public function testHas($key, $value, $exists)
|
||||
{
|
||||
$this->assertEquals($exists, $this->bag->has($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider attributesProvider
|
||||
*/
|
||||
public function testGet($key, $value, $expected)
|
||||
{
|
||||
$this->assertEquals($value, $this->bag->get($key));
|
||||
}
|
||||
|
||||
public function testGetDefaults()
|
||||
{
|
||||
$this->assertNull($this->bag->get('user2.login'));
|
||||
$this->assertEquals('default', $this->bag->get('user2.login', 'default'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider attributesProvider
|
||||
*/
|
||||
public function testSet($key, $value, $expected)
|
||||
{
|
||||
$this->bag->set($key, $value);
|
||||
$this->assertEquals($value, $this->bag->get($key));
|
||||
}
|
||||
|
||||
public function testAll()
|
||||
{
|
||||
$this->assertEquals($this->array, $this->bag->all());
|
||||
|
||||
$this->bag->set('hello', 'fabien');
|
||||
$array = $this->array;
|
||||
$array['hello'] = 'fabien';
|
||||
$this->assertEquals($array, $this->bag->all());
|
||||
}
|
||||
|
||||
public function testReplace()
|
||||
{
|
||||
$array = array();
|
||||
$array['name'] = 'jack';
|
||||
$array['foo.bar'] = 'beep';
|
||||
$this->bag->replace($array);
|
||||
$this->assertEquals($array, $this->bag->all());
|
||||
$this->assertNull($this->bag->get('hello'));
|
||||
$this->assertNull($this->bag->get('always'));
|
||||
$this->assertNull($this->bag->get('user.login'));
|
||||
}
|
||||
|
||||
public function testRemove()
|
||||
{
|
||||
$this->assertEquals('world', $this->bag->get('hello'));
|
||||
$this->bag->remove('hello');
|
||||
$this->assertNull($this->bag->get('hello'));
|
||||
|
||||
$this->assertEquals('be happy', $this->bag->get('always'));
|
||||
$this->bag->remove('always');
|
||||
$this->assertNull($this->bag->get('always'));
|
||||
|
||||
$this->assertEquals('drak', $this->bag->get('user.login'));
|
||||
$this->bag->remove('user.login');
|
||||
$this->assertNull($this->bag->get('user.login'));
|
||||
}
|
||||
|
||||
public function testClear()
|
||||
{
|
||||
$this->bag->clear();
|
||||
$this->assertEquals(array(), $this->bag->all());
|
||||
}
|
||||
|
||||
public function attributesProvider()
|
||||
{
|
||||
return array(
|
||||
array('hello', 'world', true),
|
||||
array('always', 'be happy', true),
|
||||
array('user.login', 'drak', true),
|
||||
array('csrf.token', array('a' => '1234', 'b' => '4321'), true),
|
||||
array('csrf.token/a', '1234', true),
|
||||
array('csrf.token/b', '4321', true),
|
||||
array('category', array('fishing' => array('first' => 'cod', 'second' => 'sole')), true),
|
||||
array('category/fishing', array('first' => 'cod', 'second' => 'sole'), true),
|
||||
array('category/fishing/first', 'cod', true),
|
||||
array('category/fishing/second', 'sole', true),
|
||||
array('user2.login', null, false),
|
||||
array('never', null, false),
|
||||
array('bye', null, false),
|
||||
array('bye/for/now', null, false),
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user