annotate core/modules/user/src/PrivateTempStore.php @ 12:7a779792577d

Update Drupal core to v8.4.5 (via Composer)
author Chris Cannam
date Fri, 23 Feb 2018 15:52:07 +0000
parents 4c8ae668cc8c
children 1fec387a4317
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\user;
Chris@0 4
Chris@0 5 use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
Chris@0 6 use Drupal\Core\Lock\LockBackendInterface;
Chris@0 7 use Drupal\Core\Session\AccountProxyInterface;
Chris@0 8 use Symfony\Component\HttpFoundation\RequestStack;
Chris@0 9
Chris@0 10 /**
Chris@0 11 * Stores and retrieves temporary data for a given owner.
Chris@0 12 *
Chris@0 13 * A PrivateTempStore can be used to make temporary, non-cache data available
Chris@0 14 * across requests. The data for the PrivateTempStore is stored in one
Chris@0 15 * key/value collection. PrivateTempStore data expires automatically after a
Chris@0 16 * given timeframe.
Chris@0 17 *
Chris@0 18 * The PrivateTempStore is different from a cache, because the data in it is not
Chris@0 19 * yet saved permanently and so it cannot be rebuilt. Typically, the
Chris@0 20 * PrivateTempStore might be used to store work in progress that is later saved
Chris@0 21 * permanently elsewhere, e.g. autosave data, multistep forms, or in-progress
Chris@0 22 * changes to complex configuration that are not ready to be saved.
Chris@0 23 *
Chris@0 24 * The PrivateTempStore differs from the SharedTempStore in that all keys are
Chris@0 25 * ensured to be unique for a particular user and users can never share data. If
Chris@0 26 * you want to be able to share data between users or use it for locking, use
Chris@0 27 * \Drupal\user\SharedTempStore.
Chris@0 28 */
Chris@0 29 class PrivateTempStore {
Chris@0 30
Chris@0 31 /**
Chris@0 32 * The key/value storage object used for this data.
Chris@0 33 *
Chris@0 34 * @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
Chris@0 35 */
Chris@0 36 protected $storage;
Chris@0 37
Chris@0 38 /**
Chris@0 39 * The lock object used for this data.
Chris@0 40 *
Chris@0 41 * @var \Drupal\Core\Lock\LockBackendInterface
Chris@0 42 */
Chris@0 43 protected $lockBackend;
Chris@0 44
Chris@0 45 /**
Chris@0 46 * The current user.
Chris@0 47 *
Chris@0 48 * @var \Drupal\Core\Session\AccountProxyInterface
Chris@0 49 */
Chris@0 50 protected $currentUser;
Chris@0 51
Chris@0 52 /**
Chris@0 53 * The request stack.
Chris@0 54 *
Chris@0 55 * @var \Symfony\Component\HttpFoundation\RequestStack
Chris@0 56 */
Chris@0 57 protected $requestStack;
Chris@0 58
Chris@0 59 /**
Chris@0 60 * The time to live for items in seconds.
Chris@0 61 *
Chris@0 62 * By default, data is stored for one week (604800 seconds) before expiring.
Chris@0 63 *
Chris@0 64 * @var int
Chris@0 65 */
Chris@0 66 protected $expire;
Chris@0 67
Chris@0 68 /**
Chris@0 69 * Constructs a new object for accessing data from a key/value store.
Chris@0 70 *
Chris@12 71 * @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $storage
Chris@0 72 * The key/value storage object used for this data. Each storage object
Chris@0 73 * represents a particular collection of data and will contain any number
Chris@0 74 * of key/value pairs.
Chris@0 75 * @param \Drupal\Core\Lock\LockBackendInterface $lock_backend
Chris@0 76 * The lock object used for this data.
Chris@0 77 * @param \Drupal\Core\Session\AccountProxyInterface $current_user
Chris@0 78 * The current user account.
Chris@0 79 * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
Chris@0 80 * The request stack.
Chris@0 81 * @param int $expire
Chris@0 82 * The time to live for items, in seconds.
Chris@0 83 */
Chris@0 84 public function __construct(KeyValueStoreExpirableInterface $storage, LockBackendInterface $lock_backend, AccountProxyInterface $current_user, RequestStack $request_stack, $expire = 604800) {
Chris@0 85 $this->storage = $storage;
Chris@0 86 $this->lockBackend = $lock_backend;
Chris@0 87 $this->currentUser = $current_user;
Chris@0 88 $this->requestStack = $request_stack;
Chris@0 89 $this->expire = $expire;
Chris@0 90 }
Chris@0 91
Chris@0 92 /**
Chris@0 93 * Retrieves a value from this PrivateTempStore for a given key.
Chris@0 94 *
Chris@0 95 * @param string $key
Chris@0 96 * The key of the data to retrieve.
Chris@0 97 *
Chris@0 98 * @return mixed
Chris@0 99 * The data associated with the key, or NULL if the key does not exist.
Chris@0 100 */
Chris@0 101 public function get($key) {
Chris@0 102 $key = $this->createkey($key);
Chris@0 103 if (($object = $this->storage->get($key)) && ($object->owner == $this->getOwner())) {
Chris@0 104 return $object->data;
Chris@0 105 }
Chris@0 106 }
Chris@0 107
Chris@0 108 /**
Chris@0 109 * Stores a particular key/value pair in this PrivateTempStore.
Chris@0 110 *
Chris@0 111 * @param string $key
Chris@0 112 * The key of the data to store.
Chris@0 113 * @param mixed $value
Chris@0 114 * The data to store.
Chris@0 115 *
Chris@0 116 * @throws \Drupal\user\TempStoreException
Chris@0 117 * Thrown when a lock for the backend storage could not be acquired.
Chris@0 118 */
Chris@0 119 public function set($key, $value) {
Chris@0 120 $key = $this->createkey($key);
Chris@0 121 if (!$this->lockBackend->acquire($key)) {
Chris@0 122 $this->lockBackend->wait($key);
Chris@0 123 if (!$this->lockBackend->acquire($key)) {
Chris@0 124 throw new TempStoreException("Couldn't acquire lock to update item '$key' in '{$this->storage->getCollectionName()}' temporary storage.");
Chris@0 125 }
Chris@0 126 }
Chris@0 127
Chris@0 128 $value = (object) [
Chris@0 129 'owner' => $this->getOwner(),
Chris@0 130 'data' => $value,
Chris@0 131 'updated' => (int) $this->requestStack->getMasterRequest()->server->get('REQUEST_TIME'),
Chris@0 132 ];
Chris@0 133 $this->storage->setWithExpire($key, $value, $this->expire);
Chris@0 134 $this->lockBackend->release($key);
Chris@0 135 }
Chris@0 136
Chris@0 137 /**
Chris@0 138 * Returns the metadata associated with a particular key/value pair.
Chris@0 139 *
Chris@0 140 * @param string $key
Chris@0 141 * The key of the data to store.
Chris@0 142 *
Chris@0 143 * @return mixed
Chris@0 144 * An object with the owner and updated time if the key has a value, or
Chris@0 145 * NULL otherwise.
Chris@0 146 */
Chris@0 147 public function getMetadata($key) {
Chris@0 148 $key = $this->createkey($key);
Chris@0 149 // Fetch the key/value pair and its metadata.
Chris@0 150 $object = $this->storage->get($key);
Chris@0 151 if ($object) {
Chris@0 152 // Don't keep the data itself in memory.
Chris@0 153 unset($object->data);
Chris@0 154 return $object;
Chris@0 155 }
Chris@0 156 }
Chris@0 157
Chris@0 158 /**
Chris@0 159 * Deletes data from the store for a given key and releases the lock on it.
Chris@0 160 *
Chris@0 161 * @param string $key
Chris@0 162 * The key of the data to delete.
Chris@0 163 *
Chris@0 164 * @return bool
Chris@0 165 * TRUE if the object was deleted or does not exist, FALSE if it exists but
Chris@0 166 * is not owned by $this->owner.
Chris@0 167 *
Chris@0 168 * @throws \Drupal\user\TempStoreException
Chris@0 169 * Thrown when a lock for the backend storage could not be acquired.
Chris@0 170 */
Chris@0 171 public function delete($key) {
Chris@0 172 $key = $this->createkey($key);
Chris@0 173 if (!$object = $this->storage->get($key)) {
Chris@0 174 return TRUE;
Chris@0 175 }
Chris@0 176 elseif ($object->owner != $this->getOwner()) {
Chris@0 177 return FALSE;
Chris@0 178 }
Chris@0 179 if (!$this->lockBackend->acquire($key)) {
Chris@0 180 $this->lockBackend->wait($key);
Chris@0 181 if (!$this->lockBackend->acquire($key)) {
Chris@0 182 throw new TempStoreException("Couldn't acquire lock to delete item '$key' from '{$this->storage->getCollectionName()}' temporary storage.");
Chris@0 183 }
Chris@0 184 }
Chris@0 185 $this->storage->delete($key);
Chris@0 186 $this->lockBackend->release($key);
Chris@0 187 return TRUE;
Chris@0 188 }
Chris@0 189
Chris@0 190 /**
Chris@0 191 * Ensures that the key is unique for a user.
Chris@0 192 *
Chris@0 193 * @param string $key
Chris@0 194 * The key.
Chris@0 195 *
Chris@0 196 * @return string
Chris@0 197 * The unique key for the user.
Chris@0 198 */
Chris@0 199 protected function createkey($key) {
Chris@0 200 return $this->getOwner() . ':' . $key;
Chris@0 201 }
Chris@0 202
Chris@0 203 /**
Chris@0 204 * Gets the current owner based on the current user or the session ID.
Chris@0 205 *
Chris@0 206 * @return string
Chris@0 207 * The owner.
Chris@0 208 */
Chris@0 209 protected function getOwner() {
Chris@0 210 return $this->currentUser->id() ?: $this->requestStack->getCurrentRequest()->getSession()->getId();
Chris@0 211 }
Chris@0 212
Chris@0 213 }