Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
<?php
/**
* @file
* Contains Drupal\user\TempStore.
*/
namespace Drupal\user;
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
use Drupal\Core\Lock\LockBackendInterface;
/**
* Stores and retrieves temporary data for a given owner.
*
* A TempStore can be used to make temporary, non-cache data available across
* requests. The data for the TempStore is stored in one key/value collection.
* 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
* might be used to store work in progress that is later saved permanently
* elsewhere, e.g. autosave data, multistep forms, or in-progress changes
* to complex configuration that are not ready to be saved.
*
* Each TempStore belongs to a particular owner (e.g. a user, session, or
* process). Multiple owners may use the same key/value collection, and the
* owner is stored along with the key/value pair.
*
* Every key is unique within the collection, so the TempStore can check
* whether a particular key is already set by a different owner. This is
* useful for informing one owner that the data is already in use by another;
* for example, to let one user know that another user is in the process of
* editing certain data, or even to restrict other users from editing it at
* the same time. It is the responsibility of the implementation to decide
* when and whether one owner can use or update another owner's data.
*
* @todo We could add getIfOwner() or setIfOwner() methods to make this more
* explicit.
*/
class TempStore {
/**
* The key/value storage object used for this data.
*
* @var Drupal\Core\KeyValueStore\KeyValueStoreExpireInterface;
*/
protected $storage;
/**
* The lock object used for this data.
*
* @var Drupal\Core\Lock\LockBackendInterface
*/
protected $lockBackend;
/**
* The owner key to store along with the data (e.g. a user or session ID).
*
* @var mixed
*/
protected $owner;
/**
* The time to live for items in seconds.
*
* 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;
/**
* Constructs a new object for accessing data from a key/value store.
*
* @param KeyValueStoreExpireInterface $storage
* 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
* The owner key to store along with the data (e.g. a user or session ID).
*/
function __construct(KeyValueStoreExpirableInterface $storage, LockBackendInterface $lockBackend, $owner) {
$this->storage = $storage;
$this->lockBackend = $lockBackend;
$this->owner = $owner;
}
/**
* Retrieves a value from this TempStore for a given key.
*
* @param string $key
* The key of the data to retrieve.
*
* @return mixed
* The data associated with the key, or NULL if the key does not exist.
*/
function get($key) {
if ($object = $this->storage->get($key)) {
return $object->data;
}
}
/**
* Stores a particular key/value pair only if the key doesn't already exist.
*
* @param string $key
* The key of the data to check and store.
* @param mixed $value
* The data to store.
*
* @return bool
* TRUE if the data was set, or FALSE if it already existed.
*/
function setIfNotExists($key, $value) {
$value = (object) array(
'owner' => $this->owner,
'data' => $value,
'updated' => REQUEST_TIME,
);
return $this->storage->setWithExpireIfNotExists($key, $value, $this->expire);
}
/**
* Stores a particular key/value pair in this TempStore.
*
* @param string $key
* The key of the data to store.
* @param mixed $value
* The data to store.
*/
function set($key, $value) {
if (!$this->lockBackend->acquire($key)) {
$this->lockBackend->wait($key);
if (!$this->lockBackend->acquire($key)) {
throw new TempStoreException(format_string("Couldn't acquire lock to update item %key in %collection temporary storage.", array(
'%key' => $key,
'%collection' => $this->storage->collection,
)));
}
}
$value = (object) array(
'owner' => $this->owner,
'data' => $value,
'updated' => REQUEST_TIME,
);
$this->storage->setWithExpire($key, $value, $this->expire);
$this->lockBackend->release($key);
}
/**
* Returns the metadata associated with a particular key/value pair.
*
* @param string $key
* The key of the data to store.
*
* @return mixed
* An object with the owner and updated time if the key has a value, or
* NULL otherwise.
*/
function getMetadata($key) {
// Fetch the key/value pair and its metadata.
$object = $this->storage->get($key);
if ($object) {
// Don't keep the data itself in memory.
unset($object->data);
return $object;
}
}
/**
* Deletes data from the store for a given key and releases the lock on it.
*
* @param string $key
* The key of the data to delete.
*/
function delete($key) {
if (!$this->lockBackend->acquire($key)) {
$this->lockBackend->wait($key);
if (!$this->lockBackend->acquire($key)) {
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);
$this->lockBackend->release($key);
}
}