ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilLSStateDB.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
25{
26 public const TABLE_NAME = 'lso_states';
27
28 public const CURRENT_ITEM_ID = "current_item";
29 public const STATES = "states";
30 public const FIRST_ACCESS = "first_access";
31 public const LAST_ACCESS = "last_access";
32
33 protected ilDBInterface $db;
34
35 public function __construct(ilDBInterface $db)
36 {
37 $this->db = $db;
38 }
39
43 public function getStatesFor(int $lso_ref_id, array $usr_ids = []): array
44 {
45 $data = $this->select($lso_ref_id, $usr_ids);
46 $ret = [];
47 foreach ($usr_ids as $usr_id) {
48 $ret[$usr_id] = [];
49 if (array_key_exists($usr_id, $data)) {
50 $ret[$usr_id] = $data[$usr_id][self::STATES];
51 }
52 }
53
54 return $ret;
55 }
56
60 public function getCurrentItemsFor(int $lso_ref_id, array $usr_ids = []): array
61 {
62 $data = $this->select($lso_ref_id, $usr_ids);
63 $ret = [];
64 foreach ($usr_ids as $usr_id) {
65 $ret[$usr_id] = -1;
66 if (array_key_exists($usr_id, $data)) {
67 $ret[$usr_id] = $data[$usr_id][self::CURRENT_ITEM_ID];
68 }
69 }
70
71 return $ret;
72 }
73
78 public function getFirstAccessFor(int $lso_ref_id, array $usr_ids = []): array
79 {
80 $data = $this->select($lso_ref_id, $usr_ids);
81 $ret = [];
82 foreach ($usr_ids as $usr_id) {
83 $ret[$usr_id] = '-1';
84 if (array_key_exists($usr_id, $data)) {
85 $ret[$usr_id] = $data[$usr_id][self::FIRST_ACCESS];
86 }
87 }
88
89 return $ret;
90 }
91
96 public function getLastAccessFor(int $lso_ref_id, array $usr_ids = []): array
97 {
98 $data = $this->select($lso_ref_id, $usr_ids);
99 $ret = [];
100 foreach ($usr_ids as $usr_id) {
101 $ret[$usr_id] = '-1';
102 if (array_key_exists($usr_id, $data)) {
103 $ret[$usr_id] = $data[$usr_id][self::LAST_ACCESS];
104 }
105 }
106
107 return $ret;
108 }
109
114 public function updateState(
115 int $lso_ref_id,
116 int $usr_id,
117 int $ref_id,
118 ILIAS\KioskMode\State $state,
119 ?int $current_item = null
120 ): void {
121 $insert_first = $this->entryExistsFor($lso_ref_id, $usr_id) === false;
122 $states = $this->getStatesFor($lso_ref_id, [$usr_id]);
123 $states = $states[$usr_id];
124 $states[$ref_id] = $state;
125 $serialized = $this->serializeStates($states);
126 if (is_null($current_item)) {
127 $current_item = $ref_id;
128 }
129
130 $ilAtomQuery = $this->db->buildAtomQuery();
131 $ilAtomQuery->addTableLock(static::TABLE_NAME);
132 $ilAtomQuery->addQueryCallable(
133 function (ilDBInterface $db) use ($insert_first, $lso_ref_id, $usr_id, $current_item, $serialized): void {
134 if ($insert_first) {
135 $this->insert($lso_ref_id, $usr_id);
136 }
137 $this->update($db, $lso_ref_id, $usr_id, $current_item, $serialized);
138 }
139 );
140
141 $ilAtomQuery->run();
142 }
143
144 protected function entryExistsFor(int $lso_ref_id, int $usr_id): bool
145 {
146 return $this->select($lso_ref_id, [$usr_id]) !== [];
147 }
148
149 protected function insert(int $lso_ref_id, int $usr_id): void
150 {
151 $first_access = date("d.m.Y H:i:s");
152 $values = array(
153 "lso_ref_id" => array("integer", $lso_ref_id),
154 "usr_id" => array("integer", $usr_id),
155 "first_access" => array("text", $first_access)
156 );
157
158 $this->db->insert(static::TABLE_NAME, $values);
159 }
160
161 protected function update(
162 ilDBInterface $db,
163 int $lso_ref_id,
164 int $usr_id,
165 int $current_item,
166 string $serialized
167 ): void {
168 $last_access = date("d.m.Y H:i:s");
169 $where = array(
170 "lso_ref_id" => array("integer", $lso_ref_id),
171 "usr_id" => array("integer", $usr_id)
172 );
173 $values = array(
174 "current_item" => array("integer", $current_item),
175 "states" => array("text", $serialized),
176 "last_access" => array("text", $last_access)
177 );
178
179 $db->update(static::TABLE_NAME, $values, $where);
180 }
181
185 public function deleteFor(int $lso_ref_id, array $usr_ids = []): void
186 {
187 $query =
188 "DELETE FROM " . static::TABLE_NAME . PHP_EOL
189 . "WHERE lso_ref_id = " . $this->db->quote($lso_ref_id, "integer") . PHP_EOL
190 ;
191
192 if ($usr_ids !== []) {
193 $query .= "AND usr_id IN (" . implode(',', $usr_ids) . ")";
194 }
195
196 $this->db->manipulate($query);
197 }
198
199 public function deleteForItem(int $lso_ref_id, int $item_ref_id): void
200 {
201 $all_states = $this->select($lso_ref_id);
202 if ($all_states === []) {
203 return;
204 }
205
206 $ilAtomQuery = $this->db->buildAtomQuery();
207 $ilAtomQuery->addTableLock(static::TABLE_NAME);
208 $ilAtomQuery->addQueryCallable(
209 function (ilDBInterface $db) use ($lso_ref_id, $all_states, $item_ref_id): void {
210 foreach ($all_states as $usr_id => $state_entry) {
211 $current_item = $state_entry['current_item'];
212 $states = $state_entry['states'];
213
214 if ($current_item === $item_ref_id) {
215 $current_item = -1;
216 }
217
218 if (array_key_exists($item_ref_id, $states)) {
219 unset($states[$item_ref_id]);
220 }
221 $serialized = $this->serializeStates($states);
222 $this->update($db, $lso_ref_id, (int) $usr_id, $current_item, $serialized);
223 }
224 }
225 );
226
227 $ilAtomQuery->run();
228 }
229
230
234 protected function buildStates(string $serialized): array
235 {
236 $states = [];
237 $data = json_decode($serialized, true);
238 foreach ($data as $ref_id => $kvpair) {
239 $states[$ref_id] = new ILIAS\KioskMode\State();
240 if (is_array($kvpair)) {
241 foreach ($kvpair as $key => $value) {
242 $states[$ref_id] = $states[$ref_id]->withValueFor($key, $value);
243 }
244 }
245 }
246
247 return $states;
248 }
249
253 protected function serializeStates(array $states): string
254 {
255 $data = [];
256 foreach ($states as $ref_id => $state) {
257 $data[$ref_id] = json_decode($state->serialize());
258 }
259
260 $result = json_encode($data);
261
262 if ($result === false) {
263 throw new LogicException("Could not serialize state.");
264 }
265
266 return $result;
267 }
268
273 protected function select(int $lso_ref_id, array $usr_ids = []): array
274 {
275 $query =
276 "SELECT usr_id, current_item, states, first_access, last_access" . PHP_EOL
277 . "FROM " . static::TABLE_NAME . PHP_EOL
278 . "WHERE lso_ref_id = " . $this->db->quote($lso_ref_id, "integer") . PHP_EOL
279 ;
280
281 if ($usr_ids !== []) {
282 $query .= "AND usr_id IN (" . implode(',', $usr_ids) . ")";
283 }
284
285 $result = $this->db->query($query);
286
287 $ret = [];
288 while ($row = $this->db->fetchAssoc($result)) {
289 $ret[$row['usr_id']] = [
290 self::CURRENT_ITEM_ID => (int) $row[self::CURRENT_ITEM_ID],
291 self::STATES => $this->buildStates($row[self::STATES]),
292 self::FIRST_ACCESS => $row[self::FIRST_ACCESS],
293 self::LAST_ACCESS => $row[self::LAST_ACCESS]
294 ];
295 }
296
297 return $ret;
298 }
299}
Keeps the state of a view in a simple stringly type key-value store.
Definition: State.php:27
Persistence for View-States.
serializeStates(array $states)
insert(int $lso_ref_id, int $usr_id)
select(int $lso_ref_id, array $usr_ids=[])
deleteFor(int $lso_ref_id, array $usr_ids=[])
buildStates(string $serialized)
updateState(int $lso_ref_id, int $usr_id, int $ref_id, ILIAS\KioskMode\State $state, ?int $current_item=null)
update a single State (for the item with ref_id); if $current_item is not set, assume that $ref_id is...
getFirstAccessFor(int $lso_ref_id, array $usr_ids=[])
__construct(ilDBInterface $db)
update(ilDBInterface $db, int $lso_ref_id, int $usr_id, int $current_item, string $serialized)
deleteForItem(int $lso_ref_id, int $item_ref_id)
getCurrentItemsFor(int $lso_ref_id, array $usr_ids=[])
getLastAccessFor(int $lso_ref_id, array $usr_ids=[])
entryExistsFor(int $lso_ref_id, int $usr_id)
getStatesFor(int $lso_ref_id, array $usr_ids=[])
ilDBInterface $db
Interface ilDBInterface.
update(string $table_name, array $values, array $where)
@description $where MUST contain existing columns only.
$ref_id
Definition: ltiauth.php:66
Interface Observer \BackgroundTasks Contains several chained tasks and infos about them.