diff --git a/core/lib/Drupal/Core/KeyValueStore/DatabaseStorage.php b/core/lib/Drupal/Core/KeyValueStore/DatabaseStorage.php index d36fd30..042fef7 100644 --- a/core/lib/Drupal/Core/KeyValueStore/DatabaseStorage.php +++ b/core/lib/Drupal/Core/KeyValueStore/DatabaseStorage.php @@ -17,7 +17,7 @@ * * @todo This class still calls db_* functions directly because it's needed * very early, pre-Container. Once the early bootstrap dependencies are - * sorted out, switch this to use an injected database connection. + * sorted out, consider using an injected database connection instead. */ class DatabaseStorage extends StorageBase { diff --git a/core/lib/Drupal/Core/KeyValueStore/DatabaseStorageExpirable.php b/core/lib/Drupal/Core/KeyValueStore/DatabaseStorageExpirable.php index f1a31f9..58785c4 100644 --- a/core/lib/Drupal/Core/KeyValueStore/DatabaseStorageExpirable.php +++ b/core/lib/Drupal/Core/KeyValueStore/DatabaseStorageExpirable.php @@ -32,7 +32,9 @@ class DatabaseStorageExpirable extends DatabaseStorage implements KeyValueStoreE * @param array $options * An associative array of options for the key/value storage collection. * Keys used: - * - table. The name of the SQL table to use, defaults to key_value_expire. + * - connection: The database connection to use for storing the data. + * - table: (optional) The name of the SQL table to use. Defaults to + * key_value_expire. */ public function __construct($collection, array $options = array()) { parent::__construct($collection, $options); @@ -99,7 +101,7 @@ function setWithExpire($key, $value, $expire) { } /** - * Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::setWithExpireIfNotExists(). + * Implements Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface::setWithExpireIfNotExists(). */ function setWithExpireIfNotExists($key, $value, $expire) { $this->garbageCollection(); @@ -117,7 +119,7 @@ function setWithExpireIfNotExists($key, $value, $expire) { } /** - * Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::setMultipleWithExpire(). + * Implements Drupal\Core\KeyValueStore\KeyValueStoreExpirablInterface::setMultipleWithExpire(). */ function setMultipleWithExpire(array $data, $expire) { foreach ($data as $key => $value) { diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php index 6370033..771cb42 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php @@ -439,6 +439,35 @@ protected function assertNotIdentical($first, $second, $message = '', $group = ' } /** + * Checks to see if two objects are identical. + * + * @param object $object1 + * The first object to check. + * @param object $object2 + * The second object to check. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * + * @return + * TRUE if the assertion succeeded, FALSE otherwise. + */ + protected function assertIdenticalObject($object1, $object2, $message = '', $group = '') { + $message = $message ?: format_string('!object1 is identical to !object2', array( + '!object1' => var_export($object1, TRUE), + '!object2' => var_export($object2, TRUE), + )); + $identical = TRUE; + foreach ($object1 as $key => $value) { + $identical = $identical && isset($object2->$key) && $object2->$key === $value; + } + return $this->assertTrue($identical, $message); + } + + + + /** * Fire an assertion that is always positive. * * @param $message @@ -940,6 +969,26 @@ public static function randomName($length = 8) { } /** + * Generates a random PHP object. + * + * @param int $size + * The number of random keys to add to the object. + * + * @return \stdClass + * The generated object, with the specified number of random keys. Each key + * has a random string value. + */ + public static function randomObject($size = 4) { + $object = new \stdClass(); + for ($i = 0; $i < $size; $i++) { + $random_key = $this->randomName(); + $random_value = $this->randomString(); + $object->{$random_key} = $random_value; + } + return $object; + } + + /** * Converts a list of possible parameters into a stack of permutations. * * Takes a list of parameters containing possible values, and converts all of diff --git a/core/modules/user/lib/Drupal/user/TempStore.php b/core/modules/user/lib/Drupal/user/TempStore.php index 857dc2d..4b1c9d2 100644 --- a/core/modules/user/lib/Drupal/user/TempStore.php +++ b/core/modules/user/lib/Drupal/user/TempStore.php @@ -15,9 +15,8 @@ * * A TempStore can be used to make temporary, non-cache data available across * requests. Each TempStore belongs to a particular owner (e.g. a user, - * session, or process) and provides a locking mechanism so that the caller - * can respond to the presence of particular data in the TempStore. TempStore - * data expires automatically after a given timeframe. + * session, or process).TempStore data expires automatically after a given + * timeframe. * * The TempStore is different from a cache, because the data in it is not yet * saved permanently and so it cannot be rebuilt. Typically, the TempStore @@ -54,6 +53,9 @@ class TempStore { * By default, data is stored for one week (604800 seconds) before expiring. * * @var int + * + * @todo Currently, this property is not exposed anywhere, and so the only + * way to override it is by extending the class. */ protected $expire = 604800; @@ -61,7 +63,9 @@ class TempStore { * Constructs a new object for accessing data from a key/value store. * * @param KeyValueStoreExpireInterface $storage - * The key/value storage object used for this data. + * The key/value storage object used for this data. Each storage object + * represents a particular collection of data and will contain any number + * of key/value pairs. * @param Drupal\Core\Lock\LockBackendInterface $lockBackend * The lock object used for this data. * @param mixed $owner @@ -111,14 +115,25 @@ function setIfNotExists($key, $value) { /** * Stores a particular key/value pair in this TempStore. * + * If the key already exists in storage for this TempStore's collection, + * only the stored owner may update it. + * * @param string $key * The key of the data to store. * @param mixed $value * The data to store. + * + * @todo Should we throw an exception here if the lock cannot be acquired + * like we do in delete()? + * @todo Should we return something here so we know whether the operation + * was successful? */ function set($key, $value) { if ($this->lockBackend->acquire($key)) { + // Retrieve the object from storage if it already exists. $object = $this->storage->get($key); + // Store the object if this TempStore's owner already owns it or if it + // is not yet set. if (!$object || $object->owner == $this->owner) { $value = (object) array( 'owner' => $this->owner, @@ -154,12 +169,17 @@ function getMetadata($key) { * * @param string $key * The key of the data to delete. + * + * @todo Why does this ignore whether we're the data owner or not? */ function delete($key) { if (!$this->lockBackend->acquire($key)) { $this->lockBackend->wait($key); if (!$this->lockBackend->acquire($key)) { - throw new TempStoreException("Couldn't acquire lock"); + throw new TempStoreException(format_string("Couldn't acquire lock to delete item %key from %collection temporary storage.", array( + '%key' => $key, + '%collection' => $this->storage->collection, + ))); } } $this->storage->delete($key); diff --git a/core/modules/user/lib/Drupal/user/TempStoreFactory.php b/core/modules/user/lib/Drupal/user/TempStoreFactory.php index 6a672f7..473d515 100644 --- a/core/modules/user/lib/Drupal/user/TempStoreFactory.php +++ b/core/modules/user/lib/Drupal/user/TempStoreFactory.php @@ -46,19 +46,27 @@ function __construct(Connection $connection, LockBackendInterface $lockBackend) /** * Creates a TempStore for the current user or anonymous session. * - * The TempStore is owned by the currently authenticated user, or by the - * active anonymous session if no user is logged in. The data is stored in - * the database. - * - * @param string $namespace - * The namespace to use for this key/value store. + * @param string $collection + * The collection name to use for this key/value store. This is typically + * a shared namespace or module name, e.g. 'views', 'entity', etc. + * @param mixed $owner + * (optional) The owner of this TempStore. By default, the TempStore is + * owned by the currently authenticated user, or by the active anonymous + * session if no user is logged in. * * @return Drupal\user\TempStore * An instance of the the key/value store. */ - function get($namespace) { - $storage = new DatabaseStorageExpirable($namespace, array('connection' => $this->connection)); - return new TempStore($storage, $this->lockBackend, $GLOBALS['user']->uid ?: session_id()); + function get($collection, $owner = NULL) { + // Use the currently authenticated user ID or the active user ID unless + // the owner is overridden. + if (!isset($owner)) { + $owner = $GLOBALS['user']->uid ?: session_id(); + } + + // Store the data for this collection in the database. + $storage = new DatabaseStorageExpirable($collection, array('connection' => $this->connection)); + return new TempStore($storage, $this->lockBackend, $owner); } } diff --git a/core/modules/user/lib/Drupal/user/Tests/TempStoreDatabaseTest.php b/core/modules/user/lib/Drupal/user/Tests/TempStoreDatabaseTest.php index 6ab5b86..0717abb 100644 --- a/core/modules/user/lib/Drupal/user/Tests/TempStoreDatabaseTest.php +++ b/core/modules/user/lib/Drupal/user/Tests/TempStoreDatabaseTest.php @@ -77,26 +77,6 @@ protected function setUp() { } /** - * Generates a random PHP object. - * - * @param int $size - * The number of random keys to add to the object. - * - * @return \stdClass - * The generated object, with the specified number of random keys. Each key - * has a random string value. - */ - public function randomObject($size = 4) { - $object = new \stdClass(); - for ($i = 0; $i < $size; $i++) { - $random_key = $this->randomName(); - $random_value = $this->randomString(); - $object->{$random_key} = $random_value; - } - return $object; - } - - /** * Tests the UserTempStore API. */ public function testUserTempStore() { @@ -145,28 +125,7 @@ public function testUserTempStore() { * The key/value store object. */ protected function getStorePerUID($uid) { - // TempStoreFactory::get() currently relies on the logged-in user ID, so - // set it in globals to test the method. - $GLOBALS['user']->uid = $uid; - return $this->storeFactory->get($this->collection); + return $this->storeFactory->get($this->collection, $uid); } - /** - * Checks to see if two objects are identical. - * - * @param object $object1 - * The first object to check. - * @param object $object2 - * The second object to check. - */ - protected function assertIdenticalObject($object1, $object2) { - $identical = TRUE; - foreach ($object1 as $key => $value) { - $identical = $identical && isset($object2->$key) && $object2->$key === $value; - } - $this->assertTrue($identical, format_string('!object1 is identical to !object2', array( - '!object1' => var_export($object1, TRUE), - '!object2' => var_export($object2, TRUE), - ))); - } }