Commit 13c930f9 authored by webchick's avatar webchick

Issue #2216527 by sun: Inject a serialization format into database key/value storage.

parent 0263085f
......@@ -127,15 +127,23 @@ services:
arguments: ['@service_container', '@settings']
keyvalue.database:
class: Drupal\Core\KeyValueStore\KeyValueDatabaseFactory
arguments: ['@database']
arguments: ['@serialization.phpserialize', '@database']
keyvalue.expirable:
class: Drupal\Core\KeyValueStore\KeyValueExpirableFactory
arguments: ['@service_container', '@settings']
keyvalue.expirable.database:
class: Drupal\Core\KeyValueStore\KeyValueDatabaseExpirableFactory
arguments: ['@serialization.phpserialize', '@database']
tags:
- { name: needs_destruction }
arguments: ['@database']
serialization.json:
class: Drupal\Component\Serialization\Json
serialization.phpserialize:
class: Drupal\Component\Serialization\PhpSerialize
serialization.yaml:
class: Drupal\Component\Serialization\Yaml
settings:
class: Drupal\Component\Utility\Settings
factory_class: Drupal\Component\Utility\Settings
......@@ -288,7 +296,7 @@ services:
arguments: ['@database']
user.tempstore:
class: Drupal\user\TempStoreFactory
arguments: ['@database', '@lock']
arguments: ['@serialization.phpserialize', '@database', '@lock']
router.request_context:
class: Symfony\Component\Routing\RequestContext
tags:
......
......@@ -8,44 +8,32 @@
namespace Drupal\Component\Serialization;
/**
* Provides helpers for dealing with json.
*
* @ingroup utility
* Default serialization for JSON.
*/
class Json {
class Json implements SerializationInterface {
/**
* Converts a PHP variable into its JavaScript equivalent.
* {@inheritdoc}
*
* We use HTML-safe strings, with several characters escaped.
*
* @param mixed $variable
* The variable to encode.
*
* @return string
* Returns the encoded variable.
*
* @see drupal_json_decode()
* @ingroup php_wrappers
* Uses HTML-safe strings, with several characters escaped.
*/
public static function encode($variable) {
// Encode <, >, ', &, and " using the json_encode() options parameter.
// Encode <, >, ', &, and ".
return json_encode($variable, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
}
/**
* Converts an HTML-safe JSON string into its PHP equivalent.
*
* @param string $string
* The string to decode.
*
* @return mixed
* Returns the decoded string.
*
* @ingroup php_wrappers
* {@inheritdoc}
*/
public static function decode($string) {
return json_decode($string, TRUE);
}
/**
* {@inheritdoc}
*/
public static function getFileExtension() {
return 'json';
}
}
<?php
/**
* @file
* Contains \Drupal\Component\Serialization\PhpSerialize.
*/
namespace Drupal\Component\Serialization;
/**
* Default serialization for serialized PHP.
*/
class PhpSerialize implements SerializationInterface {
/**
* {@inheritdoc}
*/
public static function encode($data) {
return serialize($data);
}
/**
* {@inheritdoc}
*/
public static function decode($raw) {
return unserialize($raw);
}
/**
* {@inheritdoc}
*/
public static function getFileExtension() {
return 'serialized';
}
}
......@@ -7,6 +7,7 @@
namespace Drupal\Core\KeyValueStore;
use Drupal\Component\Serialization\SerializationInterface;
use Drupal\Core\Database\Query\Merge;
use Drupal\Core\Database\Connection;
......@@ -18,6 +19,13 @@
*/
class DatabaseStorage extends StorageBase {
/**
* The serialization class to use.
*
* @var \Drupal\Component\Serialization\SerializationInterface
*/
protected $serializer;
/**
* The database connection.
*
......@@ -37,11 +45,16 @@ class DatabaseStorage extends StorageBase {
*
* @param string $collection
* The name of the collection holding key and value pairs.
* @param \Drupal\Component\Serialization\SerializationInterface $serializer
* The serialization class to use.
* @param \Drupal\Core\Database\Connection $connection
* The database connection to use.
* @param string $table
* The name of the SQL table to use, defaults to key_value.
*/
public function __construct($collection, Connection $connection, $table = 'key_value') {
public function __construct($collection, SerializationInterface $serializer, Connection $connection, $table = 'key_value') {
parent::__construct($collection);
$this->serializer = $serializer;
$this->connection = $connection;
$this->table = $table;
}
......@@ -65,7 +78,7 @@ public function getMultiple(array $keys) {
$result = $this->connection->query('SELECT name, value FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name IN (:keys) AND collection = :collection', array(':keys' => $keys, ':collection' => $this->collection))->fetchAllAssoc('name');
foreach ($keys as $key) {
if (isset($result[$key])) {
$values[$key] = unserialize($result[$key]->value);
$values[$key] = $this->serializer->decode($result[$key]->value);
}
}
}
......@@ -86,7 +99,7 @@ public function getAll() {
foreach ($result as $item) {
if ($item) {
$values[$item->name] = unserialize($item->value);
$values[$item->name] = $this->serializer->decode($item->value);
}
}
return $values;
......@@ -101,7 +114,7 @@ public function set($key, $value) {
'name' => $key,
'collection' => $this->collection,
))
->fields(array('value' => serialize($value)))
->fields(array('value' => $this->serializer->encode($value)))
->execute();
}
......@@ -113,7 +126,7 @@ public function setIfNotExists($key, $value) {
->insertFields(array(
'collection' => $this->collection,
'name' => $key,
'value' => serialize($value),
'value' => $this->serializer->encode($value),
))
->condition('collection', $this->collection)
->condition('name', $key)
......
......@@ -7,6 +7,7 @@
namespace Drupal\Core\KeyValueStore;
use Drupal\Component\Serialization\SerializationInterface;
use Drupal\Core\DestructableInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Query\Merge;
......@@ -19,13 +20,6 @@
*/
class DatabaseStorageExpirable extends DatabaseStorage implements KeyValueStoreExpirableInterface, DestructableInterface {
/**
* The connection object for this storage.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* Flag indicating whether garbage collection should be performed.
*
......@@ -44,16 +38,15 @@ class DatabaseStorageExpirable extends DatabaseStorage implements KeyValueStoreE
*
* @param string $collection
* The name of the collection holding key and value pairs.
* @param array $options
* An associative array of options for the key/value storage collection.
* Keys used:
* - connection: (optional) The database connection to use for storing the
* data. Defaults to the current connection.
* - table: (optional) The name of the SQL table to use. Defaults to
* key_value_expire.
* @param \Drupal\Component\Serialization\SerializationInterface $serializer
* The serialization class to use.
* @param \Drupal\Core\Database\Connection $connection
* The database connection to use.
* @param string $table
* The name of the SQL table to use, defaults to key_value_expire.
*/
public function __construct($collection, Connection $connection, $table = 'key_value_expire') {
parent::__construct($collection, $connection, $table);
public function __construct($collection, SerializationInterface $serializer, Connection $connection, $table = 'key_value_expire') {
parent::__construct($collection, $serializer, $connection, $table);
}
/**
......@@ -78,7 +71,7 @@ public function getMultiple(array $keys) {
':keys' => $keys,
':collection' => $this->collection,
))->fetchAllKeyed();
return array_map('unserialize', $values);
return array_map(array($this->serializer, 'decode'), $values);
}
/**
......@@ -91,7 +84,7 @@ public function getAll() {
':collection' => $this->collection,
':now' => REQUEST_TIME
))->fetchAllKeyed();
return array_map('unserialize', $values);
return array_map(array($this->serializer, 'decode'), $values);
}
/**
......@@ -107,7 +100,7 @@ function setWithExpire($key, $value, $expire) {
'collection' => $this->collection,
))
->fields(array(
'value' => serialize($value),
'value' => $this->serializer->encode($value),
'expire' => REQUEST_TIME + $expire,
))
->execute();
......@@ -124,7 +117,7 @@ function setWithExpireIfNotExists($key, $value, $expire) {
->insertFields(array(
'collection' => $this->collection,
'name' => $key,
'value' => serialize($value),
'value' => $this->serializer->encode($value),
'expire' => REQUEST_TIME + $expire,
))
->condition('collection', $this->collection)
......
......@@ -7,6 +7,7 @@
namespace Drupal\Core\KeyValueStore;
use Drupal\Component\Serialization\SerializationInterface;
use Drupal\Core\DestructableInterface;
use Drupal\Core\Database\Connection;
......@@ -22,6 +23,13 @@ class KeyValueDatabaseExpirableFactory implements KeyValueExpirableFactoryInterf
*/
protected $storages = array();
/**
* The serialization class to use.
*
* @var \Drupal\Component\Serialization\SerializationInterface
*/
protected $serializer;
/**
* The database connection.
*
......@@ -32,11 +40,13 @@ class KeyValueDatabaseExpirableFactory implements KeyValueExpirableFactoryInterf
/**
* Constructs this factory object.
*
*
* @param \Drupal\Component\Serialization\SerializationInterface $serializer
* The serialization class to use.
* @param \Drupal\Core\Database\Connection $connection
* The Connection object containing the key-value tables.
*/
function __construct(Connection $connection) {
function __construct(SerializationInterface $serializer, Connection $connection) {
$this->serializer = $serializer;
$this->connection = $connection;
}
......@@ -45,7 +55,7 @@ function __construct(Connection $connection) {
*/
public function get($collection) {
if (!isset($this->storages[$collection])) {
$this->storages[$collection] = new DatabaseStorageExpirable($collection, $this->connection);
$this->storages[$collection] = new DatabaseStorageExpirable($collection, $this->serializer, $this->connection);
}
return $this->storages[$collection];
}
......
......@@ -6,6 +6,8 @@
*/
namespace Drupal\Core\KeyValueStore;
use Drupal\Component\Serialization\SerializationInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Database;
......@@ -15,13 +17,29 @@
class KeyValueDatabaseFactory implements KeyValueFactoryInterface {
/**
* Constructs this factory object.
* The serialization class to use.
*
* @var \Drupal\Component\Serialization\SerializationInterface
*/
protected $serializer;
/**
* The database connection to use.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* Constructs this factory object.
*
* @param \Drupal\Component\Serialization\SerializationInterface $serializer
* The serialization class to use.
* @param \Drupal\Core\Database\Connection $connection
* The Connection object containing the key-value tables.
*/
function __construct(Connection $connection) {
function __construct(SerializationInterface $serializer, Connection $connection) {
$this->serializer = $serializer;
$this->connection = $connection;
}
......@@ -29,6 +47,6 @@ function __construct(Connection $connection) {
* {@inheritdoc}
*/
public function get($collection) {
return new DatabaseStorage($collection, $this->connection);
return new DatabaseStorage($collection, $this->serializer, $this->connection);
}
}
......@@ -35,7 +35,10 @@ protected function setUp() {
->addArgument('default');
$this->container
->register('keyvalue.expirable.database', 'Drupal\Core\KeyValueStore\KeyValueDatabaseExpirableFactory')
->addArgument(new Reference('serialization.phpserialize'))
->addArgument(new Reference('database'));
$this->container
->register('serialization.phpserialize', 'Drupal\Component\Serialization\PhpSerialize');
$this->settingsSet('keyvalue_expirable_default', 'keyvalue.expirable.database');
}
......
......@@ -34,7 +34,10 @@ protected function setUp() {
->addArgument('default');
$this->container
->register('keyvalue.database', 'Drupal\Core\KeyValueStore\KeyValueDatabaseFactory')
->addArgument(new Reference('serialization.phpserialize'))
->addArgument(new Reference('database'));
$this->container
->register('serialization.phpserialize', 'Drupal\Component\Serialization\PhpSerialize');
$this->settingsSet('keyvalue_default', 'keyvalue.database');
}
......
......@@ -7,6 +7,7 @@
namespace Drupal\system\Tests\KeyValueStore;
use Drupal\Component\Serialization\PhpSerialize;
use Drupal\Core\Database\Database;
use Drupal\Core\KeyValueStore\DatabaseStorageExpirable;
use Drupal\simpletest\UnitTestBase;
......@@ -41,7 +42,7 @@ protected function tearDown() {
*/
public function testGarbageCollection() {
$collection = $this->randomName();
$store = new DatabaseStorageExpirable($collection, Database::getConnection());
$store = new DatabaseStorageExpirable($collection, new PhpSerialize(), Database::getConnection());
// Insert some items and confirm that they're set.
for ($i = 0; $i <= 3; $i++) {
......
......@@ -7,6 +7,7 @@
namespace Drupal\user;
use Drupal\Component\Serialization\SerializationInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\KeyValueStore\DatabaseStorageExpirable;
use Drupal\Core\Lock\LockBackendInterface;
......@@ -16,6 +17,13 @@
*/
class TempStoreFactory {
/**
* The serialization class to use.
*
* @var \Drupal\Component\Serialization\SerializationInterface
*/
protected $serializer;
/**
* The connection object used for this data.
*
......@@ -33,12 +41,15 @@ class TempStoreFactory {
/**
* Constructs a Drupal\user\TempStoreFactory object.
*
* @param \Drupal\Component\Serialization\SerializationInterface $serializer
* The serialization class to use.
* @param \Drupal\Core\Database\Connection $connection
* The connection object used for this data.
* @param \Drupal\Core\Lock\LockBackendInterface $lockBackend
* The lock object used for this data.
*/
function __construct(Connection $connection, LockBackendInterface $lockBackend) {
function __construct(SerializationInterface $serializer, Connection $connection, LockBackendInterface $lockBackend) {
$this->serializer = $serializer;
$this->connection = $connection;
$this->lockBackend = $lockBackend;
}
......@@ -65,7 +76,7 @@ function get($collection, $owner = NULL) {
}
// Store the data for this collection in the database.
$storage = new DatabaseStorageExpirable($collection, $this->connection);
$storage = new DatabaseStorageExpirable($collection, $this->serializer, $this->connection);
return new TempStore($storage, $this->lockBackend, $owner);
}
......
......@@ -7,6 +7,7 @@
namespace Drupal\user\Tests;
use Drupal\Component\Serialization\PhpSerialize;
use Drupal\simpletest\UnitTestBase;
use Drupal\user\TempStoreFactory;
use Drupal\Core\Lock\DatabaseLockBackend;
......@@ -83,7 +84,7 @@ protected function tearDown() {
*/
public function testUserTempStore() {
// Create a key/value collection.
$factory = new TempStoreFactory(Database::getConnection(), new DatabaseLockBackend(Database::getConnection()));
$factory = new TempStoreFactory(new PhpSerialize(), Database::getConnection(), new DatabaseLockBackend(Database::getConnection()));
$collection = $this->randomName();
// Create two mock users.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment