Differences Between: [Versions 402 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 namespace core_xapi; 18 19 use core_xapi\local\state; 20 21 /** 22 * The state store manager. 23 * 24 * @package core_xapi 25 * @since Moodle 4.2 26 * @copyright 2022 Ferran Recio <ferran@moodle.com> 27 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 28 */ 29 class state_store { 30 31 /** @var string component name in frankenstyle. */ 32 protected $component; 33 34 /** 35 * Constructor for a xAPI handler base class. 36 * 37 * @param string $component the component name 38 */ 39 public function __construct(string $component) { 40 $this->component = $component; 41 } 42 43 /** 44 * Convert the xAPI activity ID into an item ID integer. 45 * 46 * @throws xapi_exception if the activity id is not numeric. 47 * @param string $activityid the provided activity ID 48 * @return int 49 */ 50 protected function activity_id_to_item_id(string $activityid): int { 51 if (!is_numeric($activityid)) { 52 throw new xapi_exception('The state store can only store numeric activity IDs.'); 53 } 54 return intval($activityid); 55 } 56 57 /** 58 * Delete any extra state data stored in the database. 59 * 60 * This method will be called only if the state is accepted by validate_state. 61 * 62 * Plugins may override this method add extra clean up tasks to the deletion. 63 * 64 * @param state $state 65 * @return bool if the state is removed 66 */ 67 public function delete(state $state): bool { 68 global $DB; 69 $data = [ 70 'component' => $this->component, 71 'userid' => $state->get_user()->id, 72 'itemid' => $this->activity_id_to_item_id($state->get_activity_id()), 73 'stateid' => $state->get_state_id(), 74 'registration' => $state->get_registration(), 75 ]; 76 return $DB->delete_records('xapi_states', $data); 77 } 78 79 /** 80 * Get a state object from the database. 81 * 82 * This method will be called only if the state is accepted by validate_state. 83 * 84 * Plugins may override this method if they store some data in different tables. 85 * 86 * @param state $state 87 * @return state|null the state 88 */ 89 public function get(state $state): ?state { 90 global $DB; 91 $data = [ 92 'component' => $this->component, 93 'userid' => $state->get_user()->id, 94 'itemid' => $this->activity_id_to_item_id($state->get_activity_id()), 95 'stateid' => $state->get_state_id(), 96 'registration' => $state->get_registration(), 97 ]; 98 $record = $DB->get_record('xapi_states', $data); 99 if ($record) { 100 $statedata = null; 101 if ($record->statedata !== null) { 102 $statedata = json_decode($record->statedata, null, 512, JSON_THROW_ON_ERROR); 103 } 104 $state->set_state_data($statedata); 105 return $state; 106 } 107 108 return null; 109 } 110 111 /** 112 * Inserts an state object into the database. 113 * 114 * This method will be called only if the state is accepted by validate_state. 115 * 116 * Plugins may override this method if they store some data in different tables. 117 * 118 * @param state $state 119 * @return bool if the state is inserted/updated 120 */ 121 public function put(state $state): bool { 122 global $DB; 123 $data = [ 124 'component' => $this->component, 125 'userid' => $state->get_user()->id, 126 'itemid' => $this->activity_id_to_item_id($state->get_activity_id()), 127 'stateid' => $state->get_state_id(), 128 'registration' => $state->get_registration(), 129 ]; 130 $record = $DB->get_record('xapi_states', $data) ?: (object) $data; 131 if (isset($record->id)) { 132 $record->statedata = json_encode($state->jsonSerialize()); 133 $record->timemodified = time(); 134 $result = $DB->update_record('xapi_states', $record); 135 } else { 136 $data['statedata'] = json_encode($state->jsonSerialize()); 137 $data['timecreated'] = time(); 138 $data['timemodified'] = $data['timecreated']; 139 $result = $DB->insert_record('xapi_states', $data); 140 } 141 return $result ? true : false; 142 } 143 144 /** 145 * Reset all states from the component. 146 * The given parameters are filters to decide the states to reset. If no parameters are defined, the only filter applied 147 * will be the component. 148 * 149 * Plugins may override this method if they store some data in different tables. 150 * 151 * @param string|null $itemid 152 * @param int|null $userid 153 * @param string|null $stateid 154 * @param string|null $registration 155 */ 156 public function reset( 157 ?string $itemid = null, 158 ?int $userid = null, 159 ?string $stateid = null, 160 ?string $registration = null 161 ): void { 162 global $DB; 163 164 $data = [ 165 'component' => $this->component, 166 ]; 167 if ($itemid) { 168 $data['itemid'] = $this->activity_id_to_item_id($itemid); 169 } 170 if ($userid) { 171 $data['userid'] = $userid; 172 } 173 if ($stateid) { 174 $data['stateid'] = $stateid; 175 } 176 if ($registration) { 177 $data['registration'] = $registration; 178 } 179 $DB->set_field('xapi_states', 'statedata', null, $data); 180 } 181 182 /** 183 * Remove all states from the component 184 * The given parameters are filters to decide the states to wipe. If no parameters are defined, the only filter applied 185 * will be the component. 186 * 187 * Plugins may override this method if they store some data in different tables. 188 * 189 * @param string|null $itemid 190 * @param int|null $userid 191 * @param string|null $stateid 192 * @param string|null $registration 193 */ 194 public function wipe( 195 ?string $itemid = null, 196 ?int $userid = null, 197 ?string $stateid = null, 198 ?string $registration = null 199 ): void { 200 global $DB; 201 $data = [ 202 'component' => $this->component, 203 ]; 204 if ($itemid) { 205 $data['itemid'] = $this->activity_id_to_item_id($itemid); 206 } 207 if ($userid) { 208 $data['userid'] = $userid; 209 } 210 if ($stateid) { 211 $data['stateid'] = $stateid; 212 } 213 if ($registration) { 214 $data['registration'] = $registration; 215 } 216 $DB->delete_records('xapi_states', $data); 217 } 218 219 /** 220 * Get all state ids from a specific activity and agent. 221 * 222 * Plugins may override this method if they store some data in different tables. 223 * 224 * @param string|null $itemid 225 * @param int|null $userid 226 * @param string|null $registration 227 * @param int|null $since filter ids updated since a specific timestamp 228 * @return string[] the state ids values 229 */ 230 public function get_state_ids( 231 ?string $itemid = null, 232 ?int $userid = null, 233 ?string $registration = null, 234 ?int $since = null, 235 ): array { 236 global $DB; 237 $select = 'component = :component'; 238 $params = [ 239 'component' => $this->component, 240 ]; 241 if ($itemid) { 242 $select .= ' AND itemid = :itemid'; 243 $params['itemid'] = $this->activity_id_to_item_id($itemid); 244 } 245 if ($userid) { 246 $select .= ' AND userid = :userid'; 247 $params['userid'] = $userid; 248 } 249 if ($registration) { 250 $select .= ' AND registration = :registration'; 251 $params['registration'] = $registration; 252 } 253 if ($since) { 254 $select .= ' AND timemodified > :since'; 255 $params['since'] = $since; 256 } 257 return $DB->get_fieldset_select('xapi_states', 'stateid', $select, $params, ''); 258 } 259 260 /** 261 * Execute a state store clean up. 262 * 263 * Plugins can override this methos to provide an alternative clean up logic. 264 */ 265 public function cleanup(): void { 266 global $DB; 267 $xapicleanupperiod = get_config('core', 'xapicleanupperiod'); 268 if (empty($xapicleanupperiod)) { 269 return; 270 } 271 $todelete = time() - $xapicleanupperiod; 272 $DB->delete_records_select( 273 'xapi_states', 274 'component = :component AND timemodified < :todelete', 275 ['component' => $this->component, 'todelete' => $todelete] 276 ); 277 } 278 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body