1 | <?php |
||||||
2 | |||||||
3 | /* For licensing terms, see /license.txt */ |
||||||
4 | |||||||
5 | use Chamilo\CourseBundle\Entity\CLpItem; |
||||||
6 | |||||||
7 | /** |
||||||
8 | * Class learnpathItem |
||||||
9 | * lp_item defines items belonging to a learnpath. Each item has a name, |
||||||
10 | * a score, a use time and additional information that enables tracking a user's |
||||||
11 | * progress in a learning path. |
||||||
12 | * |
||||||
13 | * @author Yannick Warnier <[email protected]> |
||||||
14 | */ |
||||||
15 | class learnpathItem |
||||||
16 | { |
||||||
17 | public const DEBUG = 0; // Logging parameter. |
||||||
18 | public $iId; |
||||||
19 | public $attempt_id; // Also called "objectives" SCORM-wise. |
||||||
20 | public $audio; // The path to an audio file (stored in document/audio/). |
||||||
21 | public $children = []; // Contains the ids of children items. |
||||||
22 | public $condition; // If this item has a special condition embedded. |
||||||
23 | public $current_score; |
||||||
24 | public $current_start_time; |
||||||
25 | public $current_stop_time; |
||||||
26 | public $current_data = ''; |
||||||
27 | public $db_id; |
||||||
28 | public $db_item_view_id = ''; |
||||||
29 | public $description = ''; |
||||||
30 | public $file; |
||||||
31 | /** |
||||||
32 | * At the moment, interactions are just an array of arrays with a structure |
||||||
33 | * of 8 text fields: id(0), type(1), time(2), weighting(3), |
||||||
34 | * correct_responses(4), student_response(5), result(6), latency(7). |
||||||
35 | */ |
||||||
36 | public $interactions = []; |
||||||
37 | public $interactions_count = 0; |
||||||
38 | public $objectives = []; |
||||||
39 | public $objectives_count = 0; |
||||||
40 | public $launch_data = ''; |
||||||
41 | public $lesson_location = ''; |
||||||
42 | public $level = 0; |
||||||
43 | public $core_exit = ''; |
||||||
44 | public $lp_id; |
||||||
45 | public $max_score; |
||||||
46 | public $mastery_score; |
||||||
47 | public $min_score; |
||||||
48 | public $max_time_allowed = ''; |
||||||
49 | public $name; |
||||||
50 | public $next; |
||||||
51 | public $parent; |
||||||
52 | public $path; // In some cases the exo_id = exercise_id in courseDb exercices table. |
||||||
53 | public $possible_status = [ |
||||||
54 | 'not attempted', |
||||||
55 | 'incomplete', |
||||||
56 | 'completed', |
||||||
57 | 'passed', |
||||||
58 | 'failed', |
||||||
59 | 'browsed', |
||||||
60 | ]; |
||||||
61 | public $prereq_string = ''; |
||||||
62 | public $prereq_alert = ''; |
||||||
63 | public $prereqs = []; |
||||||
64 | public $previous; |
||||||
65 | public $prevent_reinit = 1; // 0 = multiple attempts 1 = one attempt |
||||||
66 | public $seriousgame_mode; |
||||||
67 | public $ref; |
||||||
68 | public $save_on_close = true; |
||||||
69 | public $search_did = null; |
||||||
70 | public $status; |
||||||
71 | public $title; |
||||||
72 | /** |
||||||
73 | * Type attribute can contain one of |
||||||
74 | * link|student_publication|dir|quiz|document|forum|thread. |
||||||
75 | */ |
||||||
76 | public $type; |
||||||
77 | public $view_id; |
||||||
78 | public $oldTotalTime; |
||||||
79 | public $view_max_score; |
||||||
80 | public $courseInfo; |
||||||
81 | public $courseId; |
||||||
82 | //var used if absolute session time mode is used |
||||||
83 | private $last_scorm_session_time = 0; |
||||||
84 | private $prerequisiteMaxScore; |
||||||
85 | private $prerequisiteMinScore; |
||||||
86 | |||||||
87 | /** |
||||||
88 | * Prepares the learning path item for later launch. |
||||||
89 | * Don't forget to use set_lp_view() if applicable after creating the item. |
||||||
90 | * Setting an lp_view will finalise the item_view data collection. |
||||||
91 | * |
||||||
92 | * @param int $id Learning path item ID |
||||||
93 | * @param CLpItem|array|null $item_content Contents of the item |
||||||
94 | */ |
||||||
95 | public function __construct($id, $item_content = null) |
||||||
96 | { |
||||||
97 | $items_table = Database::get_course_table(TABLE_LP_ITEM); |
||||||
98 | $id = (int) $id; |
||||||
99 | $this->courseId = api_get_course_int_id(); |
||||||
100 | |||||||
101 | if (!empty($id)) { |
||||||
102 | $sql = "SELECT * FROM $items_table |
||||||
103 | WHERE iid = $id"; |
||||||
104 | $res = Database::query($sql); |
||||||
105 | if (Database::num_rows($res) < 1) { |
||||||
106 | $this->error = 'Could not find given learnpath item in learnpath_item table'; |
||||||
107 | } |
||||||
108 | $row = Database::fetch_array($res); |
||||||
109 | } else { |
||||||
110 | if ($item_content instanceof CLpItem) { |
||||||
111 | $row = []; |
||||||
112 | $row['lp_id'] = $item_content->getLp()->getIid(); |
||||||
113 | $row['iid'] = $item_content->getIid(); |
||||||
114 | $row['max_score'] = $item_content->getMaxScore(); |
||||||
115 | $row['min_score'] = $item_content->getMinScore(); |
||||||
116 | $row['title'] = $item_content->getTitle(); |
||||||
117 | $row['item_type'] = $item_content->getItemType(); |
||||||
118 | $row['ref'] = $item_content->getRef(); |
||||||
119 | $row['description'] = $item_content->getDescription(); |
||||||
120 | $row['path'] = $item_content->getPath(); |
||||||
121 | $row['mastery_score'] = $item_content->getMasteryScore(); |
||||||
122 | $row['parent_item_id'] = $item_content->getParentItemId(); |
||||||
123 | $row['next_item_id'] = $item_content->getNextItemId(); |
||||||
124 | $row['previous_item_id'] = $item_content->getPreviousItemId(); |
||||||
125 | $row['display_order'] = $item_content->getDisplayOrder(); |
||||||
126 | $row['prerequisite'] = $item_content->getPrerequisite(); |
||||||
127 | $row['max_time_allowed'] = $item_content->getMaxTimeAllowed(); |
||||||
128 | $row['prerequisite_max_score'] = $item_content->getPrerequisiteMaxScore(); |
||||||
129 | $row['prerequisite_min_score'] = $item_content->getPrerequisiteMinScore(); |
||||||
130 | $row['audio'] = $item_content->getAudio(); |
||||||
131 | $row['launch_data'] = $item_content->getLaunchData(); |
||||||
132 | } |
||||||
133 | } |
||||||
134 | |||||||
135 | $this->iId = $row['iid']; |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
![]() |
|||||||
136 | $this->lp_id = $row['lp_id']; |
||||||
137 | $this->max_score = $row['max_score']; |
||||||
138 | $this->min_score = $row['min_score']; |
||||||
139 | $this->name = $row['title']; |
||||||
140 | $this->type = $row['item_type']; |
||||||
141 | $this->ref = $row['ref']; |
||||||
142 | $this->title = $row['title']; |
||||||
143 | $this->description = $row['description']; |
||||||
144 | $this->path = $row['path']; |
||||||
145 | $this->mastery_score = $row['mastery_score']; |
||||||
146 | $this->parent = $row['parent_item_id']; |
||||||
147 | $this->next = $row['next_item_id']; |
||||||
148 | $this->previous = $row['previous_item_id']; |
||||||
149 | $this->display_order = $row['display_order']; |
||||||
150 | $this->prereq_string = $row['prerequisite']; |
||||||
151 | $this->max_time_allowed = $row['max_time_allowed']; |
||||||
152 | $this->setPrerequisiteMaxScore($row['prerequisite_max_score']); |
||||||
153 | $this->setPrerequisiteMinScore($row['prerequisite_min_score']); |
||||||
154 | $this->oldTotalTime = 0; |
||||||
155 | $this->view_max_score = 0; |
||||||
156 | $this->seriousgame_mode = 0; |
||||||
157 | //$this->audio = self::fixAudio($row['audio']); |
||||||
158 | $this->audio = $row['audio']; |
||||||
159 | $this->launch_data = $row['launch_data']; |
||||||
160 | $this->save_on_close = true; |
||||||
161 | $this->db_id = $row['iid']; |
||||||
162 | |||||||
163 | // Load children list |
||||||
164 | if (!empty($this->lp_id)) { |
||||||
165 | $sql = "SELECT iid FROM $items_table |
||||||
166 | WHERE |
||||||
167 | lp_id = ".$this->lp_id." AND |
||||||
168 | parent_item_id = $id"; |
||||||
169 | $res = Database::query($sql); |
||||||
170 | if (Database::num_rows($res) > 0) { |
||||||
171 | while ($row = Database::fetch_assoc($res)) { |
||||||
172 | $this->children[] = $row['iid']; |
||||||
173 | } |
||||||
174 | } |
||||||
175 | |||||||
176 | /* |
||||||
177 | // Xapian full text search does not work |
||||||
178 | // and if the option is activated it generates an error |
||||||
179 | // So I comment this part of the code to avoid unnecesary errors |
||||||
180 | // Get search_did. |
||||||
181 | if ('true' === api_get_setting('search_enabled')) { |
||||||
182 | $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF); |
||||||
183 | $sql = 'SELECT * |
||||||
184 | FROM %s |
||||||
185 | WHERE |
||||||
186 | course_code=\'%s\' AND |
||||||
187 | tool_id=\'%s\' AND |
||||||
188 | ref_id_high_level=%s AND |
||||||
189 | ref_id_second_level=%d |
||||||
190 | LIMIT 1'; |
||||||
191 | // TODO: Verify if it's possible to assume the actual course instead |
||||||
192 | // of getting it from db. |
||||||
193 | $sql = sprintf( |
||||||
194 | $sql, |
||||||
195 | $tbl_se_ref, |
||||||
196 | api_get_course_id(), |
||||||
197 | TOOL_LEARNPATH, |
||||||
198 | $this->lp_id, |
||||||
199 | $id |
||||||
200 | ); |
||||||
201 | $res = Database::query($sql); |
||||||
202 | if (Database::num_rows($res) > 0) { |
||||||
203 | $se_ref = Database::fetch_array($res); |
||||||
204 | $this->search_did = (int) $se_ref['search_did']; |
||||||
205 | } |
||||||
206 | } |
||||||
207 | */ |
||||||
208 | } |
||||||
209 | } |
||||||
210 | |||||||
211 | public static function fixAudio($audio) |
||||||
212 | { |
||||||
213 | $courseInfo = api_get_course_info(); |
||||||
214 | // Do not check in DB as we expect the call to come from the |
||||||
215 | if (empty($audio) || empty($courseInfo)) { |
||||||
216 | return ''; |
||||||
217 | } |
||||||
218 | // learnpath class which should be aware of any fake. |
||||||
219 | // Old structure |
||||||
220 | $file = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document/audio/'.$audio; |
||||||
0 ignored issues
–
show
|
|||||||
221 | if (file_exists($file)) { |
||||||
222 | $audio = '/audio/'.$audio; |
||||||
223 | $audio = str_replace('//', '/', $audio); |
||||||
224 | |||||||
225 | return $audio; |
||||||
226 | } |
||||||
227 | |||||||
228 | $file = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document'.$audio; |
||||||
229 | |||||||
230 | if (file_exists($file)) { |
||||||
231 | return $audio; |
||||||
232 | } |
||||||
233 | |||||||
234 | return ''; |
||||||
235 | } |
||||||
236 | |||||||
237 | /** |
||||||
238 | * Adds an interaction to the current item. |
||||||
239 | * |
||||||
240 | * @param int $index Index (order ID) of the interaction inside this item |
||||||
241 | * @param array $params Array of parameters: |
||||||
242 | * id(0), type(1), time(2), weighting(3), correct_responses(4), |
||||||
243 | * student_response(5), result(6), latency(7) |
||||||
244 | */ |
||||||
245 | public function add_interaction($index, $params) |
||||||
246 | { |
||||||
247 | $this->interactions[$index] = $params; |
||||||
248 | // Take the current maximum index to generate the interactions_count. |
||||||
249 | if (($index + 1) > $this->interactions_count) { |
||||||
250 | $this->interactions_count = $index + 1; |
||||||
251 | } |
||||||
252 | } |
||||||
253 | |||||||
254 | /** |
||||||
255 | * Adds an objective to the current item. |
||||||
256 | * |
||||||
257 | * @param array Array of parameters: |
||||||
258 | * id(0), status(1), score_raw(2), score_max(3), score_min(4) |
||||||
259 | */ |
||||||
260 | public function add_objective($index, $params) |
||||||
261 | { |
||||||
262 | if (empty($params[0])) { |
||||||
263 | return null; |
||||||
264 | } |
||||||
265 | $this->objectives[$index] = $params; |
||||||
266 | // Take the current maximum index to generate the objectives_count. |
||||||
267 | if ((count($this->objectives) + 1) > $this->objectives_count) { |
||||||
268 | $this->objectives_count = (count($this->objectives) + 1); |
||||||
269 | } |
||||||
270 | } |
||||||
271 | |||||||
272 | /** |
||||||
273 | * Closes/stops the item viewing. Finalises runtime values. |
||||||
274 | * If required, save to DB. |
||||||
275 | * |
||||||
276 | * @param bool $prerequisitesCheck Needed to check if asset can be set as completed or not |
||||||
277 | * |
||||||
278 | * @return bool True on success, false otherwise |
||||||
279 | */ |
||||||
280 | public function close() |
||||||
281 | { |
||||||
282 | $debug = self::DEBUG; |
||||||
283 | $this->current_stop_time = time(); |
||||||
284 | $type = $this->get_type(); |
||||||
285 | if ($debug) { |
||||||
286 | error_log('Start - learnpathItem:close'); |
||||||
287 | error_log("Type: ".$type); |
||||||
288 | error_log("get_id: ".$this->get_id()); |
||||||
289 | } |
||||||
290 | if ('sco' !== $type) { |
||||||
291 | if (TOOL_QUIZ == $type || TOOL_HOTPOTATOES == $type) { |
||||||
292 | $this->get_status( |
||||||
293 | true, |
||||||
294 | true |
||||||
295 | ); // Update status (second option forces the update). |
||||||
296 | } else { |
||||||
297 | /*$this->status = $this->possible_status[2]; |
||||||
298 | if (self::DEBUG) { |
||||||
299 | error_log("STATUS changed to: ".$this->status); |
||||||
300 | }*/ |
||||||
301 | } |
||||||
302 | } |
||||||
303 | if ($this->save_on_close) { |
||||||
304 | if ($debug) { |
||||||
305 | error_log('save_on_close'); |
||||||
306 | } |
||||||
307 | $this->save(); |
||||||
308 | } |
||||||
309 | |||||||
310 | if ($debug) { |
||||||
311 | error_log('End - learnpathItem:close'); |
||||||
312 | } |
||||||
313 | |||||||
314 | return true; |
||||||
315 | } |
||||||
316 | |||||||
317 | /** |
||||||
318 | * Deletes all traces of this item in the database. |
||||||
319 | * |
||||||
320 | * @return bool true. Doesn't check for errors yet. |
||||||
321 | */ |
||||||
322 | public function delete() |
||||||
323 | { |
||||||
324 | $lp_item_view = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||||||
325 | $lp_item = Database::get_course_table(TABLE_LP_ITEM); |
||||||
326 | |||||||
327 | $sql = "DELETE FROM $lp_item_view |
||||||
328 | WHERE lp_item_id = ".$this->db_id; |
||||||
329 | Database::query($sql); |
||||||
330 | |||||||
331 | $sql = "SELECT * FROM $lp_item |
||||||
332 | WHERE iid = ".$this->db_id; |
||||||
333 | $res_sel = Database::query($sql); |
||||||
334 | if (Database::num_rows($res_sel) < 1) { |
||||||
335 | return false; |
||||||
336 | } |
||||||
337 | |||||||
338 | $sql = "DELETE FROM $lp_item |
||||||
339 | WHERE iid = ".$this->db_id; |
||||||
340 | Database::query($sql); |
||||||
341 | |||||||
342 | if ('true' == api_get_setting('search_enabled')) { |
||||||
343 | if (!is_null($this->search_did)) { |
||||||
344 | $di = new ChamiloIndexer(); |
||||||
345 | $di->remove_document($this->search_did); |
||||||
346 | } |
||||||
347 | } |
||||||
348 | |||||||
349 | return true; |
||||||
350 | } |
||||||
351 | |||||||
352 | /** |
||||||
353 | * Gets the current attempt_id for this user on this item. |
||||||
354 | * |
||||||
355 | * @return int attempt_id for this item view by this user or 1 if none defined |
||||||
356 | */ |
||||||
357 | public function get_attempt_id() |
||||||
358 | { |
||||||
359 | $res = 1; |
||||||
360 | if (!empty($this->attempt_id)) { |
||||||
361 | $res = (int) $this->attempt_id; |
||||||
362 | } |
||||||
363 | |||||||
364 | return $res; |
||||||
365 | } |
||||||
366 | |||||||
367 | /** |
||||||
368 | * Gets a list of the item's children. |
||||||
369 | * |
||||||
370 | * @return array Array of children items IDs |
||||||
371 | */ |
||||||
372 | public function get_children() |
||||||
373 | { |
||||||
374 | $list = []; |
||||||
375 | foreach ($this->children as $child) { |
||||||
376 | if (!empty($child)) { |
||||||
377 | $list[] = $child; |
||||||
378 | } |
||||||
379 | } |
||||||
380 | |||||||
381 | return $list; |
||||||
382 | } |
||||||
383 | |||||||
384 | /** |
||||||
385 | * Gets the core_exit value from the database. |
||||||
386 | */ |
||||||
387 | public function get_core_exit() |
||||||
388 | { |
||||||
389 | return $this->core_exit; |
||||||
390 | } |
||||||
391 | |||||||
392 | /** |
||||||
393 | * Gets the credit information (rather scorm-stuff) based on current status |
||||||
394 | * and reinit autorization. Credit tells the sco(content) if Chamilo will |
||||||
395 | * record the data it is sent (credit) or not (no-credit). |
||||||
396 | * |
||||||
397 | * @return string 'credit' or 'no-credit'. Defaults to 'credit' |
||||||
398 | * Because if we don't know enough about this item, it's probably because |
||||||
399 | * it was never used before. |
||||||
400 | */ |
||||||
401 | public function get_credit() |
||||||
402 | { |
||||||
403 | if (self::DEBUG > 1) { |
||||||
404 | error_log('learnpathItem::get_credit()', 0); |
||||||
405 | } |
||||||
406 | $credit = 'credit'; |
||||||
407 | // Now check the value of prevent_reinit (if it's 0, return credit as |
||||||
408 | // the default was). |
||||||
409 | // If prevent_reinit == 1 (or more). |
||||||
410 | if (0 != $this->get_prevent_reinit()) { |
||||||
411 | // If status is not attempted or incomplete, credit anyway. |
||||||
412 | // Otherwise: |
||||||
413 | // Check the status in the database rather than in the object, as |
||||||
414 | // checking in the object would always return "no-credit" when we |
||||||
415 | // want to set it to completed. |
||||||
416 | $status = $this->get_status(true); |
||||||
417 | if (self::DEBUG > 2) { |
||||||
418 | error_log( |
||||||
419 | 'learnpathItem::get_credit() - get_prevent_reinit!=0 and '. |
||||||
420 | 'status is '.$status, |
||||||
421 | 0 |
||||||
422 | ); |
||||||
423 | } |
||||||
424 | //0=not attempted - 1 = incomplete |
||||||
425 | if ($status != $this->possible_status[0] && |
||||||
426 | $status != $this->possible_status[1] |
||||||
427 | ) { |
||||||
428 | $credit = 'no-credit'; |
||||||
429 | } |
||||||
430 | } |
||||||
431 | if (self::DEBUG > 1) { |
||||||
432 | error_log("learnpathItem::get_credit() returns: $credit"); |
||||||
433 | } |
||||||
434 | |||||||
435 | return $credit; |
||||||
436 | } |
||||||
437 | |||||||
438 | /** |
||||||
439 | * Gets the current start time property. |
||||||
440 | * |
||||||
441 | * @return int Current start time, or current time if none |
||||||
442 | */ |
||||||
443 | public function get_current_start_time() |
||||||
444 | { |
||||||
445 | if (empty($this->current_start_time)) { |
||||||
446 | return time(); |
||||||
447 | } |
||||||
448 | |||||||
449 | return $this->current_start_time; |
||||||
450 | } |
||||||
451 | |||||||
452 | /** |
||||||
453 | * Gets the item's description. |
||||||
454 | * |
||||||
455 | * @return string Description |
||||||
456 | */ |
||||||
457 | public function get_description() |
||||||
458 | { |
||||||
459 | if (empty($this->description)) { |
||||||
460 | return ''; |
||||||
461 | } |
||||||
462 | |||||||
463 | return $this->description; |
||||||
464 | } |
||||||
465 | |||||||
466 | /** |
||||||
467 | * Gets the file path from the course's root directory, no matter what |
||||||
468 | * tool it is from. |
||||||
469 | * |
||||||
470 | * @param string $path_to_scorm_dir |
||||||
471 | * |
||||||
472 | * @return string The file path, or an empty string if there is no file |
||||||
473 | * attached, or '-1' if the file must be replaced by an error page |
||||||
474 | */ |
||||||
475 | public function get_file_path($path_to_scorm_dir = '') |
||||||
476 | { |
||||||
477 | $courseId = $this->courseId; |
||||||
478 | $path = $this->get_path(); |
||||||
479 | $type = $this->get_type(); |
||||||
480 | |||||||
481 | if (empty($path)) { |
||||||
482 | if ('dir' == $type) { |
||||||
483 | return ''; |
||||||
484 | } else { |
||||||
485 | return '-1'; |
||||||
486 | } |
||||||
487 | } elseif ($path == strval(intval($path))) { |
||||||
488 | // The path is numeric, so it is a reference to a Chamilo object. |
||||||
489 | switch ($type) { |
||||||
490 | case 'dir': |
||||||
491 | return ''; |
||||||
492 | case TOOL_DOCUMENT: |
||||||
493 | $table_doc = Database::get_course_table(TABLE_DOCUMENT); |
||||||
494 | $sql = 'SELECT path |
||||||
495 | FROM '.$table_doc.' |
||||||
496 | WHERE iid = '.$path; |
||||||
497 | $res = Database::query($sql); |
||||||
498 | $row = Database::fetch_array($res); |
||||||
499 | $real_path = 'document'.$row['path']; |
||||||
500 | |||||||
501 | return $real_path; |
||||||
502 | case TOOL_STUDENTPUBLICATION: |
||||||
503 | case TOOL_QUIZ: |
||||||
504 | case TOOL_FORUM: |
||||||
505 | case TOOL_THREAD: |
||||||
506 | case TOOL_LINK: |
||||||
507 | default: |
||||||
508 | return '-1'; |
||||||
509 | } |
||||||
510 | } else { |
||||||
511 | if (!empty($path_to_scorm_dir)) { |
||||||
512 | $path = $path_to_scorm_dir.$path; |
||||||
513 | } |
||||||
514 | |||||||
515 | return $path; |
||||||
516 | } |
||||||
517 | } |
||||||
518 | |||||||
519 | /** |
||||||
520 | * Gets the DB ID. |
||||||
521 | * |
||||||
522 | * @return int Database ID for the current item |
||||||
523 | */ |
||||||
524 | public function get_id() |
||||||
525 | { |
||||||
526 | if (!empty($this->db_id)) { |
||||||
527 | return $this->db_id; |
||||||
528 | } |
||||||
529 | // TODO: Check this return value is valid for children classes (SCORM?). |
||||||
530 | return 0; |
||||||
531 | } |
||||||
532 | |||||||
533 | /** |
||||||
534 | * Loads the interactions into the item object, from the database. |
||||||
535 | * If object interactions exist, they will be overwritten by this function, |
||||||
536 | * using the database elements only. |
||||||
537 | */ |
||||||
538 | public function load_interactions() |
||||||
539 | { |
||||||
540 | $this->interactions = []; |
||||||
541 | $courseId = $this->courseId; |
||||||
542 | $tbl = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||||||
543 | $sql = "SELECT id FROM $tbl |
||||||
544 | WHERE |
||||||
545 | lp_item_id = ".$this->db_id." AND |
||||||
546 | lp_view_id = ".$this->view_id." AND |
||||||
547 | view_count = ".$this->get_view_count(); |
||||||
548 | $res = Database::query($sql); |
||||||
549 | if (Database::num_rows($res) > 0) { |
||||||
550 | $row = Database::fetch_array($res); |
||||||
551 | $lp_iv_id = $row[0]; |
||||||
552 | $iva_table = Database::get_course_table(TABLE_LP_IV_INTERACTION); |
||||||
553 | $sql = "SELECT * FROM $iva_table |
||||||
554 | WHERE c_id = $courseId AND lp_iv_id = $lp_iv_id "; |
||||||
555 | $res_sql = Database::query($sql); |
||||||
556 | while ($row = Database::fetch_array($res_sql)) { |
||||||
557 | $this->interactions[$row['interaction_id']] = [ |
||||||
558 | $row['interaction_id'], |
||||||
559 | $row['interaction_type'], |
||||||
560 | $row['weighting'], |
||||||
561 | $row['completion_time'], |
||||||
562 | $row['correct_responses'], |
||||||
563 | $row['student_responses'], |
||||||
564 | $row['result'], |
||||||
565 | $row['latency'], |
||||||
566 | ]; |
||||||
567 | } |
||||||
568 | } |
||||||
569 | } |
||||||
570 | |||||||
571 | /** |
||||||
572 | * Gets the current count of interactions recorded in the database. |
||||||
573 | * |
||||||
574 | * @param bool $checkdb Whether to count from database or not (defaults to no) |
||||||
575 | * |
||||||
576 | * @return int The current number of interactions recorder |
||||||
577 | */ |
||||||
578 | public function get_interactions_count($checkdb = false) |
||||||
579 | { |
||||||
580 | $return = 0; |
||||||
581 | if (api_is_invitee()) { |
||||||
582 | // If the user is an invitee, we consider there's no interaction |
||||||
583 | return 0; |
||||||
584 | } |
||||||
585 | if ($checkdb) { |
||||||
586 | $tbl = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||||||
587 | $sql = "SELECT iid FROM $tbl |
||||||
588 | WHERE |
||||||
589 | lp_item_id = ".$this->db_id." AND |
||||||
590 | lp_view_id = ".$this->view_id." AND |
||||||
591 | view_count = ".$this->get_attempt_id(); |
||||||
592 | $res = Database::query($sql); |
||||||
593 | if (Database::num_rows($res) > 0) { |
||||||
594 | $row = Database::fetch_array($res); |
||||||
595 | $lp_iv_id = $row[0]; |
||||||
596 | $iva_table = Database::get_course_table(TABLE_LP_IV_INTERACTION); |
||||||
597 | $sql = "SELECT count(iid) as count |
||||||
598 | FROM $iva_table |
||||||
599 | WHERE lp_iv_id = $lp_iv_id "; |
||||||
600 | $res_sql = Database::query($sql); |
||||||
601 | if (Database::num_rows($res_sql) > 0) { |
||||||
602 | $row = Database::fetch_array($res_sql); |
||||||
603 | $return = (int) $row['count']; |
||||||
604 | } |
||||||
605 | } |
||||||
606 | } else { |
||||||
607 | if (!empty($this->interactions_count)) { |
||||||
608 | $return = $this->interactions_count; |
||||||
609 | } |
||||||
610 | } |
||||||
611 | |||||||
612 | return $return; |
||||||
613 | } |
||||||
614 | |||||||
615 | /** |
||||||
616 | * Gets the JavaScript array content to fill the interactions array. |
||||||
617 | * |
||||||
618 | * @param bool $checkdb Whether to check directly into the database (default no) |
||||||
619 | * |
||||||
620 | * @return string An empty string if no interaction, a JS array definition otherwise |
||||||
621 | */ |
||||||
622 | public function get_interactions_js_array($checkdb = false) |
||||||
623 | { |
||||||
624 | $return = ''; |
||||||
625 | if ($checkdb) { |
||||||
626 | $this->load_interactions(); |
||||||
627 | } |
||||||
628 | foreach ($this->interactions as $id => $in) { |
||||||
629 | $return .= "[ |
||||||
630 | '$id', |
||||||
631 | '".$in[1]."', |
||||||
632 | '".$in[2]."', |
||||||
633 | '".$in[3]."', |
||||||
634 | '".$in[4]."', |
||||||
635 | '".$in[5]."', |
||||||
636 | '".$in[6]."', |
||||||
637 | '".$in[7]."'],"; |
||||||
638 | } |
||||||
639 | if (!empty($return)) { |
||||||
640 | $return = substr($return, 0, -1); |
||||||
641 | } |
||||||
642 | |||||||
643 | return $return; |
||||||
644 | } |
||||||
645 | |||||||
646 | /** |
||||||
647 | * Gets the current count of objectives recorded in the database. |
||||||
648 | * |
||||||
649 | * @return int The current number of objectives recorder |
||||||
650 | */ |
||||||
651 | public function get_objectives_count() |
||||||
652 | { |
||||||
653 | $res = 0; |
||||||
654 | if (!empty($this->objectives_count)) { |
||||||
655 | $res = $this->objectives_count; |
||||||
656 | } |
||||||
657 | |||||||
658 | return $res; |
||||||
659 | } |
||||||
660 | |||||||
661 | /** |
||||||
662 | * Gets the launch_data field found in imsmanifests (this is SCORM- or |
||||||
663 | * AICC-related, really). |
||||||
664 | * |
||||||
665 | * @return string Launch data as found in imsmanifest and stored in |
||||||
666 | * Chamilo (read only). Defaults to ''. |
||||||
667 | */ |
||||||
668 | public function get_launch_data() |
||||||
669 | { |
||||||
670 | if (!empty($this->launch_data)) { |
||||||
671 | return str_replace( |
||||||
672 | ["\r", "\n", "'"], |
||||||
673 | ['\r', '\n', "\\'"], |
||||||
674 | $this->launch_data |
||||||
675 | ); |
||||||
676 | } |
||||||
677 | |||||||
678 | return ''; |
||||||
679 | } |
||||||
680 | |||||||
681 | /** |
||||||
682 | * Gets the lesson location. |
||||||
683 | * |
||||||
684 | * @return string lesson location as recorded by the SCORM and AICC |
||||||
685 | * elements. Defaults to '' |
||||||
686 | */ |
||||||
687 | public function get_lesson_location() |
||||||
688 | { |
||||||
689 | if (!empty($this->lesson_location)) { |
||||||
690 | return str_replace( |
||||||
691 | ["\r", "\n", "'"], |
||||||
692 | ['\r', '\n', "\\'"], |
||||||
693 | $this->lesson_location |
||||||
694 | ); |
||||||
695 | } |
||||||
696 | |||||||
697 | return ''; |
||||||
698 | } |
||||||
699 | |||||||
700 | /** |
||||||
701 | * Gets the lesson_mode (scorm feature, but might be used by aicc as well |
||||||
702 | * as chamilo paths). |
||||||
703 | * |
||||||
704 | * The "browse" mode is not supported yet (because there is no such way of |
||||||
705 | * seeing a sco in Chamilo) |
||||||
706 | * |
||||||
707 | * @return string 'browse','normal' or 'review'. Defaults to 'normal' |
||||||
708 | */ |
||||||
709 | public function get_lesson_mode() |
||||||
710 | { |
||||||
711 | $mode = 'normal'; |
||||||
712 | if (0 != $this->get_prevent_reinit()) { |
||||||
713 | // If prevent_reinit == 0 |
||||||
714 | $my_status = $this->get_status(); |
||||||
715 | if ($my_status != $this->possible_status[0] && $my_status != $this->possible_status[1]) { |
||||||
716 | $mode = 'review'; |
||||||
717 | } |
||||||
718 | } |
||||||
719 | |||||||
720 | return $mode; |
||||||
721 | } |
||||||
722 | |||||||
723 | /** |
||||||
724 | * Gets the depth level. |
||||||
725 | * |
||||||
726 | * @return int Level. Defaults to 0 |
||||||
727 | */ |
||||||
728 | public function get_level() |
||||||
729 | { |
||||||
730 | if (empty($this->level)) { |
||||||
731 | return 0; |
||||||
732 | } |
||||||
733 | |||||||
734 | return $this->level; |
||||||
735 | } |
||||||
736 | |||||||
737 | /** |
||||||
738 | * Gets the mastery score. |
||||||
739 | */ |
||||||
740 | public function get_mastery_score() |
||||||
741 | { |
||||||
742 | if (isset($this->mastery_score)) { |
||||||
743 | return $this->mastery_score; |
||||||
744 | } |
||||||
745 | |||||||
746 | return -1; |
||||||
747 | } |
||||||
748 | |||||||
749 | /** |
||||||
750 | * Gets the maximum (score). |
||||||
751 | * |
||||||
752 | * @return int Maximum score. Defaults to 100 if nothing else is defined |
||||||
753 | */ |
||||||
754 | public function get_max() |
||||||
755 | { |
||||||
756 | if ('sco' === $this->type) { |
||||||
757 | if (!empty($this->view_max_score) && $this->view_max_score > 0) { |
||||||
758 | return $this->view_max_score; |
||||||
759 | } else { |
||||||
760 | if (!empty($this->max_score)) { |
||||||
761 | return $this->max_score; |
||||||
762 | } |
||||||
763 | |||||||
764 | return 100; |
||||||
765 | } |
||||||
766 | } else { |
||||||
767 | if (!empty($this->max_score)) { |
||||||
768 | return $this->max_score; |
||||||
769 | } |
||||||
770 | |||||||
771 | return 100; |
||||||
772 | } |
||||||
773 | } |
||||||
774 | |||||||
775 | /** |
||||||
776 | * Gets the maximum time allowed for this user in this attempt on this item. |
||||||
777 | * |
||||||
778 | * @return string Time string in SCORM format |
||||||
779 | * (HH:MM:SS or HH:MM:SS.SS or HHHH:MM:SS.SS) |
||||||
780 | */ |
||||||
781 | public function get_max_time_allowed() |
||||||
782 | { |
||||||
783 | if (!empty($this->max_time_allowed)) { |
||||||
784 | return $this->max_time_allowed; |
||||||
785 | } |
||||||
786 | |||||||
787 | return ''; |
||||||
788 | } |
||||||
789 | |||||||
790 | /** |
||||||
791 | * Gets the minimum (score). |
||||||
792 | * |
||||||
793 | * @return int Minimum score. Defaults to 0 |
||||||
794 | */ |
||||||
795 | public function get_min() |
||||||
796 | { |
||||||
797 | if (!empty($this->min_score)) { |
||||||
798 | return $this->min_score; |
||||||
799 | } |
||||||
800 | |||||||
801 | return 0; |
||||||
802 | } |
||||||
803 | |||||||
804 | /** |
||||||
805 | * Gets the parent ID. |
||||||
806 | * |
||||||
807 | * @return int Parent ID. Defaults to null |
||||||
808 | */ |
||||||
809 | public function get_parent() |
||||||
810 | { |
||||||
811 | if (!empty($this->parent)) { |
||||||
812 | return $this->parent; |
||||||
813 | } |
||||||
814 | // TODO: Check this return value is valid for children classes (SCORM?). |
||||||
815 | return null; |
||||||
816 | } |
||||||
817 | |||||||
818 | /** |
||||||
819 | * Gets the path attribute. |
||||||
820 | * |
||||||
821 | * @return string Path. Defaults to '' |
||||||
822 | */ |
||||||
823 | public function get_path() |
||||||
824 | { |
||||||
825 | if (empty($this->path)) { |
||||||
826 | return ''; |
||||||
827 | } |
||||||
828 | |||||||
829 | return $this->path; |
||||||
830 | } |
||||||
831 | |||||||
832 | /** |
||||||
833 | * Gets the prerequisites string. |
||||||
834 | * |
||||||
835 | * @return string empty string or prerequisites string if defined |
||||||
836 | */ |
||||||
837 | public function get_prereq_string() |
||||||
838 | { |
||||||
839 | if (!empty($this->prereq_string)) { |
||||||
840 | return $this->prereq_string; |
||||||
841 | } |
||||||
842 | |||||||
843 | return ''; |
||||||
844 | } |
||||||
845 | |||||||
846 | /** |
||||||
847 | * Gets the prevent_reinit attribute value (and sets it if not set already). |
||||||
848 | * |
||||||
849 | * @return int 1 or 0 (defaults to 1) |
||||||
850 | */ |
||||||
851 | public function get_prevent_reinit() |
||||||
852 | { |
||||||
853 | if (self::DEBUG > 2) { |
||||||
854 | error_log('learnpathItem::get_prevent_reinit()', 0); |
||||||
855 | } |
||||||
856 | if (!isset($this->prevent_reinit)) { |
||||||
857 | if (!empty($this->lp_id)) { |
||||||
858 | $table = Database::get_course_table(TABLE_LP_MAIN); |
||||||
859 | $sql = "SELECT prevent_reinit |
||||||
860 | FROM $table |
||||||
861 | WHERE iid = ".$this->lp_id; |
||||||
862 | $res = Database::query($sql); |
||||||
863 | if (Database::num_rows($res) < 1) { |
||||||
864 | $this->error = 'Could not find parent learnpath in lp table'; |
||||||
865 | if (self::DEBUG > 2) { |
||||||
866 | error_log( |
||||||
867 | 'LearnpathItem::get_prevent_reinit() - Returning false', |
||||||
868 | 0 |
||||||
869 | ); |
||||||
870 | } |
||||||
871 | |||||||
872 | return false; |
||||||
873 | } else { |
||||||
874 | $row = Database::fetch_array($res); |
||||||
875 | $this->prevent_reinit = $row['prevent_reinit']; |
||||||
876 | } |
||||||
877 | } else { |
||||||
878 | // Prevent reinit is always 1 by default - see learnpath.class.php |
||||||
879 | $this->prevent_reinit = 1; |
||||||
880 | } |
||||||
881 | } |
||||||
882 | if (self::DEBUG > 2) { |
||||||
883 | error_log('End of learnpathItem::get_prevent_reinit() - Returned '.$this->prevent_reinit); |
||||||
884 | } |
||||||
885 | |||||||
886 | return $this->prevent_reinit; |
||||||
887 | } |
||||||
888 | |||||||
889 | /** |
||||||
890 | * Returns 1 if seriousgame_mode is activated, 0 otherwise. |
||||||
891 | * |
||||||
892 | * @return int (0 or 1) |
||||||
893 | * |
||||||
894 | * @deprecated seriousgame_mode seems not to be used |
||||||
895 | * |
||||||
896 | * @author ndiechburg <[email protected]> |
||||||
897 | */ |
||||||
898 | public function get_seriousgame_mode() |
||||||
899 | { |
||||||
900 | if (!isset($this->seriousgame_mode)) { |
||||||
901 | if (!empty($this->lp_id)) { |
||||||
902 | $table = Database::get_course_table(TABLE_LP_MAIN); |
||||||
903 | $sql = "SELECT seriousgame_mode |
||||||
904 | FROM $table |
||||||
905 | WHERE iid = ".$this->lp_id; |
||||||
906 | $res = Database::query($sql); |
||||||
907 | if (Database::num_rows($res) < 1) { |
||||||
908 | $this->error = 'Could not find parent learnpath in learnpath table'; |
||||||
909 | |||||||
910 | return false; |
||||||
911 | } else { |
||||||
912 | $row = Database::fetch_array($res); |
||||||
913 | $this->seriousgame_mode = isset($row['seriousgame_mode']) ? $row['seriousgame_mode'] : 0; |
||||||
914 | } |
||||||
915 | } else { |
||||||
916 | $this->seriousgame_mode = 0; //SeriousGame mode is always off by default |
||||||
917 | } |
||||||
918 | } |
||||||
919 | |||||||
920 | return $this->seriousgame_mode; |
||||||
921 | } |
||||||
922 | |||||||
923 | /** |
||||||
924 | * Gets the item's reference column. |
||||||
925 | * |
||||||
926 | * @return string The item's reference field (generally used for SCORM identifiers) |
||||||
927 | */ |
||||||
928 | public function get_ref() |
||||||
929 | { |
||||||
930 | return $this->ref; |
||||||
931 | } |
||||||
932 | |||||||
933 | /** |
||||||
934 | * Gets the list of included resources as a list of absolute or relative |
||||||
935 | * paths of resources included in the current item. This allows for a |
||||||
936 | * better SCORM export. The list will generally include pictures, flash |
||||||
937 | * objects, java applets, or any other stuff included in the source of the |
||||||
938 | * current item. The current item is expected to be an HTML file. If it |
||||||
939 | * is not, then the function will return and empty list. |
||||||
940 | * |
||||||
941 | * @param string $type (one of the Chamilo tools) - optional (otherwise takes the current item's type) |
||||||
942 | * @param string $abs_path absolute file path - optional (otherwise takes the current item's path) |
||||||
943 | * @param int $recursivity level of recursivity we're in |
||||||
944 | * |
||||||
945 | * @return array List of file paths. |
||||||
946 | * An additional field containing 'local' or 'remote' helps determine if |
||||||
947 | * the file should be copied into the zip or just linked |
||||||
948 | */ |
||||||
949 | public function get_resources_from_source( |
||||||
950 | $type = null, |
||||||
951 | $abs_path = null, |
||||||
952 | $recursivity = 1 |
||||||
953 | ) { |
||||||
954 | $max = 5; |
||||||
955 | if ($recursivity > $max) { |
||||||
956 | return []; |
||||||
957 | } |
||||||
958 | |||||||
959 | $type = empty($type) ? $this->get_type() : $type; |
||||||
960 | |||||||
961 | if (!isset($abs_path)) { |
||||||
962 | $path = $this->get_file_path(); |
||||||
963 | $abs_path = api_get_path(SYS_COURSE_PATH).api_get_course_path().'/'.$path; |
||||||
0 ignored issues
–
show
The function
api_get_course_path was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
964 | } |
||||||
965 | |||||||
966 | $files_list = []; |
||||||
967 | switch ($type) { |
||||||
968 | case TOOL_DOCUMENT: |
||||||
969 | case TOOL_QUIZ: |
||||||
970 | case 'sco': |
||||||
971 | // Get the document and, if HTML, open it. |
||||||
972 | if (!is_file($abs_path)) { |
||||||
973 | // The file could not be found. |
||||||
974 | return false; |
||||||
975 | } |
||||||
976 | |||||||
977 | // for now, read the whole file in one go (that's gonna be |
||||||
978 | // a problem when the file is too big). |
||||||
979 | $info = pathinfo($abs_path); |
||||||
980 | $ext = $info['extension']; |
||||||
981 | |||||||
982 | switch (strtolower($ext)) { |
||||||
983 | case 'html': |
||||||
984 | case 'htm': |
||||||
985 | case 'shtml': |
||||||
986 | case 'css': |
||||||
987 | $wantedAttributes = [ |
||||||
988 | 'src', |
||||||
989 | 'url', |
||||||
990 | '@import', |
||||||
991 | 'href', |
||||||
992 | 'value', |
||||||
993 | ]; |
||||||
994 | |||||||
995 | // Parse it for included resources. |
||||||
996 | $fileContent = file_get_contents($abs_path); |
||||||
997 | // Get an array of attributes from the HTML source. |
||||||
998 | $attributes = DocumentManager::parse_HTML_attributes( |
||||||
999 | $fileContent, |
||||||
1000 | $wantedAttributes |
||||||
1001 | ); |
||||||
1002 | |||||||
1003 | // Look at 'src' attributes in this file |
||||||
1004 | foreach ($wantedAttributes as $attr) { |
||||||
1005 | if (isset($attributes[$attr])) { |
||||||
1006 | // Find which kind of path these are (local or remote). |
||||||
1007 | $sources = $attributes[$attr]; |
||||||
1008 | |||||||
1009 | foreach ($sources as $source) { |
||||||
1010 | // Skip what is obviously not a resource. |
||||||
1011 | if (strpos($source, "+this.")) { |
||||||
1012 | continue; |
||||||
1013 | } // javascript code - will still work unaltered. |
||||||
1014 | if (false === strpos($source, '.')) { |
||||||
1015 | continue; |
||||||
1016 | } // No dot, should not be an external file anyway. |
||||||
1017 | if (strpos($source, 'mailto:')) { |
||||||
1018 | continue; |
||||||
1019 | } // mailto link. |
||||||
1020 | if (strpos($source, ';') && |
||||||
1021 | !strpos($source, '&') |
||||||
1022 | ) { |
||||||
1023 | continue; |
||||||
1024 | } // Avoid code - that should help. |
||||||
1025 | |||||||
1026 | if ('value' == $attr) { |
||||||
1027 | if (strpos($source, 'mp3file')) { |
||||||
1028 | $files_list[] = [ |
||||||
1029 | substr( |
||||||
1030 | $source, |
||||||
1031 | 0, |
||||||
1032 | strpos( |
||||||
1033 | $source, |
||||||
1034 | '.swf' |
||||||
1035 | ) + 4 |
||||||
1036 | ), |
||||||
1037 | 'local', |
||||||
1038 | 'abs', |
||||||
1039 | ]; |
||||||
1040 | $mp3file = substr( |
||||||
1041 | $source, |
||||||
1042 | strpos( |
||||||
1043 | $source, |
||||||
1044 | 'mp3file=' |
||||||
1045 | ) + 8 |
||||||
1046 | ); |
||||||
1047 | if ('/' == substr($mp3file, 0, 1)) { |
||||||
1048 | $files_list[] = [ |
||||||
1049 | $mp3file, |
||||||
1050 | 'local', |
||||||
1051 | 'abs', |
||||||
1052 | ]; |
||||||
1053 | } else { |
||||||
1054 | $files_list[] = [ |
||||||
1055 | $mp3file, |
||||||
1056 | 'local', |
||||||
1057 | 'rel', |
||||||
1058 | ]; |
||||||
1059 | } |
||||||
1060 | } elseif (0 === strpos($source, 'flv=')) { |
||||||
1061 | $source = substr($source, 4); |
||||||
1062 | if (strpos($source, '&') > 0) { |
||||||
1063 | $source = substr( |
||||||
1064 | $source, |
||||||
1065 | 0, |
||||||
1066 | strpos($source, '&') |
||||||
1067 | ); |
||||||
1068 | } |
||||||
1069 | if (strpos($source, '://') > 0) { |
||||||
1070 | if (false !== strpos($source, api_get_path(WEB_PATH))) { |
||||||
1071 | // We found the current portal url. |
||||||
1072 | $files_list[] = [ |
||||||
1073 | $source, |
||||||
1074 | 'local', |
||||||
1075 | 'url', |
||||||
1076 | ]; |
||||||
1077 | } else { |
||||||
1078 | // We didn't find any trace of current portal. |
||||||
1079 | $files_list[] = [ |
||||||
1080 | $source, |
||||||
1081 | 'remote', |
||||||
1082 | 'url', |
||||||
1083 | ]; |
||||||
1084 | } |
||||||
1085 | } else { |
||||||
1086 | $files_list[] = [ |
||||||
1087 | $source, |
||||||
1088 | 'local', |
||||||
1089 | 'abs', |
||||||
1090 | ]; |
||||||
1091 | } |
||||||
1092 | continue; // Skipping anything else to avoid two entries |
||||||
1093 | //(while the others can have sub-files in their url, flv's can't). |
||||||
1094 | } |
||||||
1095 | } |
||||||
1096 | |||||||
1097 | if (strpos($source, '://') > 0) { |
||||||
1098 | // Cut at '?' in a URL with params. |
||||||
1099 | if (strpos($source, '?') > 0) { |
||||||
1100 | $second_part = substr( |
||||||
1101 | $source, |
||||||
1102 | strpos($source, '?') |
||||||
1103 | ); |
||||||
1104 | if (strpos($second_part, '://') > 0) { |
||||||
1105 | // If the second part of the url contains a url too, |
||||||
1106 | // treat the second one before cutting. |
||||||
1107 | $pos1 = strpos( |
||||||
1108 | $second_part, |
||||||
1109 | '=' |
||||||
1110 | ); |
||||||
1111 | $pos2 = strpos( |
||||||
1112 | $second_part, |
||||||
1113 | '&' |
||||||
1114 | ); |
||||||
1115 | $second_part = substr( |
||||||
1116 | $second_part, |
||||||
1117 | $pos1 + 1, |
||||||
1118 | $pos2 - ($pos1 + 1) |
||||||
1119 | ); |
||||||
1120 | if (false !== strpos($second_part, api_get_path(WEB_PATH))) { |
||||||
1121 | // We found the current portal url. |
||||||
1122 | $files_list[] = [ |
||||||
1123 | $second_part, |
||||||
1124 | 'local', |
||||||
1125 | 'url', |
||||||
1126 | ]; |
||||||
1127 | $in_files_list[] = self::get_resources_from_source( |
||||||
0 ignored issues
–
show
The method
learnpathItem::get_resources_from_source() is not static, but was called statically.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
1128 | TOOL_DOCUMENT, |
||||||
1129 | $second_part, |
||||||
1130 | $recursivity + 1 |
||||||
1131 | ); |
||||||
1132 | if (count($in_files_list) > 0) { |
||||||
1133 | $files_list = array_merge( |
||||||
1134 | $files_list, |
||||||
1135 | $in_files_list |
||||||
1136 | ); |
||||||
1137 | } |
||||||
1138 | } else { |
||||||
1139 | // We didn't find any trace of current portal. |
||||||
1140 | $files_list[] = [ |
||||||
1141 | $second_part, |
||||||
1142 | 'remote', |
||||||
1143 | 'url', |
||||||
1144 | ]; |
||||||
1145 | } |
||||||
1146 | } elseif (strpos($second_part, '=') > 0) { |
||||||
1147 | if ('/' === substr($second_part, 0, 1)) { |
||||||
1148 | // Link starts with a /, |
||||||
1149 | // making it absolute (relative to DocumentRoot). |
||||||
1150 | $files_list[] = [ |
||||||
1151 | $second_part, |
||||||
1152 | 'local', |
||||||
1153 | 'abs', |
||||||
1154 | ]; |
||||||
1155 | $in_files_list[] = self::get_resources_from_source( |
||||||
1156 | TOOL_DOCUMENT, |
||||||
1157 | $second_part, |
||||||
1158 | $recursivity + 1 |
||||||
1159 | ); |
||||||
1160 | if (count($in_files_list) > 0) { |
||||||
1161 | $files_list = array_merge( |
||||||
1162 | $files_list, |
||||||
1163 | $in_files_list |
||||||
1164 | ); |
||||||
1165 | } |
||||||
1166 | } elseif (0 === strstr($second_part, '..')) { |
||||||
1167 | // Link is relative but going back in the hierarchy. |
||||||
1168 | $files_list[] = [ |
||||||
1169 | $second_part, |
||||||
1170 | 'local', |
||||||
1171 | 'rel', |
||||||
1172 | ]; |
||||||
1173 | $dir = dirname( |
||||||
1174 | $abs_path |
||||||
1175 | ); |
||||||
1176 | $new_abs_path = realpath( |
||||||
1177 | $dir.'/'.$second_part |
||||||
1178 | ); |
||||||
1179 | $in_files_list[] = self::get_resources_from_source( |
||||||
1180 | TOOL_DOCUMENT, |
||||||
1181 | $new_abs_path, |
||||||
1182 | $recursivity + 1 |
||||||
1183 | ); |
||||||
1184 | if (count($in_files_list) > 0) { |
||||||
1185 | $files_list = array_merge( |
||||||
1186 | $files_list, |
||||||
1187 | $in_files_list |
||||||
1188 | ); |
||||||
1189 | } |
||||||
1190 | } else { |
||||||
1191 | // No starting '/', making it relative to current document's path. |
||||||
1192 | if ('./' == substr($second_part, 0, 2)) { |
||||||
1193 | $second_part = substr( |
||||||
1194 | $second_part, |
||||||
1195 | 2 |
||||||
1196 | ); |
||||||
1197 | } |
||||||
1198 | $files_list[] = [ |
||||||
1199 | $second_part, |
||||||
1200 | 'local', |
||||||
1201 | 'rel', |
||||||
1202 | ]; |
||||||
1203 | $dir = dirname( |
||||||
1204 | $abs_path |
||||||
1205 | ); |
||||||
1206 | $new_abs_path = realpath( |
||||||
1207 | $dir.'/'.$second_part |
||||||
1208 | ); |
||||||
1209 | $in_files_list[] = self::get_resources_from_source( |
||||||
1210 | TOOL_DOCUMENT, |
||||||
1211 | $new_abs_path, |
||||||
1212 | $recursivity + 1 |
||||||
1213 | ); |
||||||
1214 | if (count($in_files_list) > 0) { |
||||||
1215 | $files_list = array_merge( |
||||||
1216 | $files_list, |
||||||
1217 | $in_files_list |
||||||
1218 | ); |
||||||
1219 | } |
||||||
1220 | } |
||||||
1221 | } |
||||||
1222 | // Leave that second part behind now. |
||||||
1223 | $source = substr( |
||||||
1224 | $source, |
||||||
1225 | 0, |
||||||
1226 | strpos($source, '?') |
||||||
1227 | ); |
||||||
1228 | if (strpos($source, '://') > 0) { |
||||||
1229 | if (false !== strpos($source, api_get_path(WEB_PATH))) { |
||||||
1230 | // We found the current portal url. |
||||||
1231 | $files_list[] = [ |
||||||
1232 | $source, |
||||||
1233 | 'local', |
||||||
1234 | 'url', |
||||||
1235 | ]; |
||||||
1236 | $in_files_list[] = self::get_resources_from_source( |
||||||
1237 | TOOL_DOCUMENT, |
||||||
1238 | $source, |
||||||
1239 | $recursivity + 1 |
||||||
1240 | ); |
||||||
1241 | if (count($in_files_list) > 0) { |
||||||
1242 | $files_list = array_merge( |
||||||
1243 | $files_list, |
||||||
1244 | $in_files_list |
||||||
1245 | ); |
||||||
1246 | } |
||||||
1247 | } else { |
||||||
1248 | // We didn't find any trace of current portal. |
||||||
1249 | $files_list[] = [ |
||||||
1250 | $source, |
||||||
1251 | 'remote', |
||||||
1252 | 'url', |
||||||
1253 | ]; |
||||||
1254 | } |
||||||
1255 | } else { |
||||||
1256 | // No protocol found, make link local. |
||||||
1257 | if ('/' === substr($source, 0, 1)) { |
||||||
1258 | // Link starts with a /, making it absolute (relative to DocumentRoot). |
||||||
1259 | $files_list[] = [ |
||||||
1260 | $source, |
||||||
1261 | 'local', |
||||||
1262 | 'abs', |
||||||
1263 | ]; |
||||||
1264 | $in_files_list[] = self::get_resources_from_source( |
||||||
1265 | TOOL_DOCUMENT, |
||||||
1266 | $source, |
||||||
1267 | $recursivity + 1 |
||||||
1268 | ); |
||||||
1269 | if (count($in_files_list) > 0) { |
||||||
1270 | $files_list = array_merge( |
||||||
1271 | $files_list, |
||||||
1272 | $in_files_list |
||||||
1273 | ); |
||||||
1274 | } |
||||||
1275 | } elseif (0 === strstr($source, '..')) { |
||||||
1276 | // Link is relative but going back in the hierarchy. |
||||||
1277 | $files_list[] = [ |
||||||
1278 | $source, |
||||||
1279 | 'local', |
||||||
1280 | 'rel', |
||||||
1281 | ]; |
||||||
1282 | $dir = dirname( |
||||||
1283 | $abs_path |
||||||
1284 | ); |
||||||
1285 | $new_abs_path = realpath( |
||||||
1286 | $dir.'/'.$source |
||||||
1287 | ); |
||||||
1288 | $in_files_list[] = self::get_resources_from_source( |
||||||
1289 | TOOL_DOCUMENT, |
||||||
1290 | $new_abs_path, |
||||||
1291 | $recursivity + 1 |
||||||
1292 | ); |
||||||
1293 | if (count($in_files_list) > 0) { |
||||||
1294 | $files_list = array_merge( |
||||||
1295 | $files_list, |
||||||
1296 | $in_files_list |
||||||
1297 | ); |
||||||
1298 | } |
||||||
1299 | } else { |
||||||
1300 | // No starting '/', making it relative to current document's path. |
||||||
1301 | if ('./' == substr($source, 0, 2)) { |
||||||
1302 | $source = substr( |
||||||
1303 | $source, |
||||||
1304 | 2 |
||||||
1305 | ); |
||||||
1306 | } |
||||||
1307 | $files_list[] = [ |
||||||
1308 | $source, |
||||||
1309 | 'local', |
||||||
1310 | 'rel', |
||||||
1311 | ]; |
||||||
1312 | $dir = dirname( |
||||||
1313 | $abs_path |
||||||
1314 | ); |
||||||
1315 | $new_abs_path = realpath( |
||||||
1316 | $dir.'/'.$source |
||||||
1317 | ); |
||||||
1318 | $in_files_list[] = self::get_resources_from_source( |
||||||
1319 | TOOL_DOCUMENT, |
||||||
1320 | $new_abs_path, |
||||||
1321 | $recursivity + 1 |
||||||
1322 | ); |
||||||
1323 | if (count($in_files_list) > 0) { |
||||||
1324 | $files_list = array_merge( |
||||||
1325 | $files_list, |
||||||
1326 | $in_files_list |
||||||
1327 | ); |
||||||
1328 | } |
||||||
1329 | } |
||||||
1330 | } |
||||||
1331 | } |
||||||
1332 | |||||||
1333 | // Found some protocol there. |
||||||
1334 | if (false !== strpos($source, api_get_path(WEB_PATH))) { |
||||||
1335 | // We found the current portal url. |
||||||
1336 | $files_list[] = [ |
||||||
1337 | $source, |
||||||
1338 | 'local', |
||||||
1339 | 'url', |
||||||
1340 | ]; |
||||||
1341 | $in_files_list[] = self::get_resources_from_source( |
||||||
1342 | TOOL_DOCUMENT, |
||||||
1343 | $source, |
||||||
1344 | $recursivity + 1 |
||||||
1345 | ); |
||||||
1346 | if (count($in_files_list) > 0) { |
||||||
1347 | $files_list = array_merge( |
||||||
1348 | $files_list, |
||||||
1349 | $in_files_list |
||||||
1350 | ); |
||||||
1351 | } |
||||||
1352 | } else { |
||||||
1353 | // We didn't find any trace of current portal. |
||||||
1354 | $files_list[] = [ |
||||||
1355 | $source, |
||||||
1356 | 'remote', |
||||||
1357 | 'url', |
||||||
1358 | ]; |
||||||
1359 | } |
||||||
1360 | } else { |
||||||
1361 | // No protocol found, make link local. |
||||||
1362 | if ('/' === substr($source, 0, 1)) { |
||||||
1363 | // Link starts with a /, making it absolute (relative to DocumentRoot). |
||||||
1364 | $files_list[] = [ |
||||||
1365 | $source, |
||||||
1366 | 'local', |
||||||
1367 | 'abs', |
||||||
1368 | ]; |
||||||
1369 | $in_files_list[] = self::get_resources_from_source( |
||||||
1370 | TOOL_DOCUMENT, |
||||||
1371 | $source, |
||||||
1372 | $recursivity + 1 |
||||||
1373 | ); |
||||||
1374 | if (count($in_files_list) > 0) { |
||||||
1375 | $files_list = array_merge( |
||||||
1376 | $files_list, |
||||||
1377 | $in_files_list |
||||||
1378 | ); |
||||||
1379 | } |
||||||
1380 | } elseif (0 === strstr($source, '..')) { |
||||||
1381 | // Link is relative but going back in the hierarchy. |
||||||
1382 | $files_list[] = [ |
||||||
1383 | $source, |
||||||
1384 | 'local', |
||||||
1385 | 'rel', |
||||||
1386 | ]; |
||||||
1387 | $dir = dirname($abs_path); |
||||||
1388 | $new_abs_path = realpath( |
||||||
1389 | $dir.'/'.$source |
||||||
1390 | ); |
||||||
1391 | $in_files_list[] = self::get_resources_from_source( |
||||||
1392 | TOOL_DOCUMENT, |
||||||
1393 | $new_abs_path, |
||||||
1394 | $recursivity + 1 |
||||||
1395 | ); |
||||||
1396 | if (count($in_files_list) > 0) { |
||||||
1397 | $files_list = array_merge( |
||||||
1398 | $files_list, |
||||||
1399 | $in_files_list |
||||||
1400 | ); |
||||||
1401 | } |
||||||
1402 | } else { |
||||||
1403 | // No starting '/', making it relative to current document's path. |
||||||
1404 | if (strpos($source, 'width=') || |
||||||
1405 | strpos($source, 'autostart=') |
||||||
1406 | ) { |
||||||
1407 | continue; |
||||||
1408 | } |
||||||
1409 | |||||||
1410 | if ('./' == substr($source, 0, 2)) { |
||||||
1411 | $source = substr( |
||||||
1412 | $source, |
||||||
1413 | 2 |
||||||
1414 | ); |
||||||
1415 | } |
||||||
1416 | $files_list[] = [ |
||||||
1417 | $source, |
||||||
1418 | 'local', |
||||||
1419 | 'rel', |
||||||
1420 | ]; |
||||||
1421 | $dir = dirname($abs_path); |
||||||
1422 | $new_abs_path = realpath( |
||||||
1423 | $dir.'/'.$source |
||||||
1424 | ); |
||||||
1425 | $in_files_list[] = self::get_resources_from_source( |
||||||
1426 | TOOL_DOCUMENT, |
||||||
1427 | $new_abs_path, |
||||||
1428 | $recursivity + 1 |
||||||
1429 | ); |
||||||
1430 | if (count($in_files_list) > 0) { |
||||||
1431 | $files_list = array_merge( |
||||||
1432 | $files_list, |
||||||
1433 | $in_files_list |
||||||
1434 | ); |
||||||
1435 | } |
||||||
1436 | } |
||||||
1437 | } |
||||||
1438 | } |
||||||
1439 | } |
||||||
1440 | } |
||||||
1441 | break; |
||||||
1442 | default: |
||||||
1443 | break; |
||||||
1444 | } |
||||||
1445 | |||||||
1446 | break; |
||||||
1447 | default: // Ignore. |
||||||
1448 | break; |
||||||
1449 | } |
||||||
1450 | |||||||
1451 | $checked_files_list = []; |
||||||
1452 | $checked_array_list = []; |
||||||
1453 | foreach ($files_list as $idx => $file) { |
||||||
1454 | if (!empty($file[0])) { |
||||||
1455 | if (!in_array($file[0], $checked_files_list)) { |
||||||
1456 | $checked_files_list[] = $files_list[$idx][0]; |
||||||
1457 | $checked_array_list[] = $files_list[$idx]; |
||||||
1458 | } |
||||||
1459 | } |
||||||
1460 | } |
||||||
1461 | |||||||
1462 | return $checked_array_list; |
||||||
1463 | } |
||||||
1464 | |||||||
1465 | /** |
||||||
1466 | * Gets the score. |
||||||
1467 | * |
||||||
1468 | * @return float The current score or 0 if no score set yet |
||||||
1469 | */ |
||||||
1470 | public function get_score() |
||||||
1471 | { |
||||||
1472 | $res = 0; |
||||||
1473 | if (!empty($this->current_score)) { |
||||||
1474 | $res = $this->current_score; |
||||||
1475 | } |
||||||
1476 | |||||||
1477 | return $res; |
||||||
1478 | } |
||||||
1479 | |||||||
1480 | /** |
||||||
1481 | * Gets the item status. |
||||||
1482 | * |
||||||
1483 | * @param bool $check_db Do or don't check into the database for the |
||||||
1484 | * latest value. Optional. Default is true |
||||||
1485 | * @param bool $update_local Do or don't update the local attribute |
||||||
1486 | * value with what's been found in DB |
||||||
1487 | * |
||||||
1488 | * @return string Current status or 'Not attempted' if no status set yet |
||||||
1489 | */ |
||||||
1490 | public function get_status($check_db = true, $update_local = false) |
||||||
1491 | { |
||||||
1492 | $debug = self::DEBUG; |
||||||
1493 | if ($debug) { |
||||||
1494 | error_log('learnpathItem::get_status() on item '.$this->db_id); |
||||||
1495 | } |
||||||
1496 | if ($check_db) { |
||||||
1497 | if ($debug) { |
||||||
1498 | error_log('learnpathItem::get_status(): checking db'); |
||||||
1499 | } |
||||||
1500 | if (!empty($this->db_item_view_id)) { |
||||||
1501 | $table = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||||||
1502 | $sql = "SELECT status FROM $table |
||||||
1503 | WHERE |
||||||
1504 | iid = '".$this->db_item_view_id."' AND |
||||||
1505 | view_count = '".$this->get_attempt_id()."'"; |
||||||
1506 | $res = Database::query($sql); |
||||||
1507 | if (1 == Database::num_rows($res)) { |
||||||
1508 | $row = Database::fetch_array($res); |
||||||
1509 | if ($update_local) { |
||||||
1510 | $this->set_status($row['status']); |
||||||
1511 | } |
||||||
1512 | |||||||
1513 | return $row['status']; |
||||||
1514 | } |
||||||
1515 | } |
||||||
1516 | } else { |
||||||
1517 | if (!empty($this->status)) { |
||||||
1518 | return $this->status; |
||||||
1519 | } |
||||||
1520 | } |
||||||
1521 | |||||||
1522 | return $this->possible_status[0]; |
||||||
1523 | } |
||||||
1524 | |||||||
1525 | /** |
||||||
1526 | * Gets the suspend data. |
||||||
1527 | */ |
||||||
1528 | public function get_suspend_data() |
||||||
1529 | { |
||||||
1530 | // TODO: Improve cleaning of breaklines ... it works but is it really |
||||||
1531 | // a beautiful way to do it ? |
||||||
1532 | if (!empty($this->current_data)) { |
||||||
1533 | return str_replace( |
||||||
1534 | ["\r", "\n", "'"], |
||||||
1535 | ['\r', '\n', "\\'"], |
||||||
1536 | $this->current_data |
||||||
1537 | ); |
||||||
1538 | } |
||||||
1539 | |||||||
1540 | return ''; |
||||||
1541 | } |
||||||
1542 | |||||||
1543 | /** |
||||||
1544 | * @param string $origin |
||||||
1545 | * @param string $time |
||||||
1546 | * |
||||||
1547 | * @return string |
||||||
1548 | */ |
||||||
1549 | public static function getScormTimeFromParameter( |
||||||
1550 | $origin = 'php', |
||||||
1551 | $time = null |
||||||
1552 | ) { |
||||||
1553 | $h = get_lang('h'); |
||||||
1554 | if (!isset($time)) { |
||||||
1555 | if ('js' == $origin) { |
||||||
1556 | return '00 : 00: 00'; |
||||||
1557 | } |
||||||
1558 | |||||||
1559 | return '00 '.$h.' 00 \' 00"'; |
||||||
1560 | } |
||||||
1561 | |||||||
1562 | return api_format_time($time, $origin); |
||||||
1563 | } |
||||||
1564 | |||||||
1565 | /** |
||||||
1566 | * Gets the total time spent on this item view so far. |
||||||
1567 | * |
||||||
1568 | * @param string $origin Origin of the request. If coming from PHP, |
||||||
1569 | * send formatted as xxhxx'xx", otherwise use scorm format 00:00:00 |
||||||
1570 | * @param int|null $given_time Given time is a default time to return formatted |
||||||
1571 | * @param bool $query_db Whether to get the value from db or from memory |
||||||
1572 | * |
||||||
1573 | * @return string A string with the time in SCORM format |
||||||
1574 | */ |
||||||
1575 | public function get_scorm_time( |
||||||
1576 | $origin = 'php', |
||||||
1577 | $given_time = null, |
||||||
1578 | $query_db = false |
||||||
1579 | ) { |
||||||
1580 | $time = null; |
||||||
1581 | $courseId = $this->courseId; |
||||||
1582 | if (empty($courseId)) { |
||||||
1583 | $courseId = api_get_course_int_id(); |
||||||
1584 | } |
||||||
1585 | |||||||
1586 | $courseId = (int) $courseId; |
||||||
1587 | if (!isset($given_time)) { |
||||||
1588 | if (self::DEBUG > 2) { |
||||||
1589 | error_log( |
||||||
1590 | 'learnpathItem::get_scorm_time(): given time empty, current_start_time = '.$this->current_start_time, |
||||||
1591 | 0 |
||||||
1592 | ); |
||||||
1593 | } |
||||||
1594 | if (true === $query_db) { |
||||||
1595 | $table = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||||||
1596 | $sql = "SELECT start_time, total_time |
||||||
1597 | FROM $table |
||||||
1598 | WHERE |
||||||
1599 | iid = '".$this->db_item_view_id."' AND |
||||||
1600 | view_count = '".$this->get_attempt_id()."'"; |
||||||
1601 | $res = Database::query($sql); |
||||||
1602 | $row = Database::fetch_array($res); |
||||||
1603 | $start = $row['start_time']; |
||||||
1604 | $stop = $start + $row['total_time']; |
||||||
1605 | } else { |
||||||
1606 | $start = $this->current_start_time; |
||||||
1607 | $stop = $this->current_stop_time; |
||||||
1608 | } |
||||||
1609 | if (!empty($start)) { |
||||||
1610 | if (!empty($stop)) { |
||||||
1611 | $time = $stop - $start; |
||||||
1612 | } else { |
||||||
1613 | $time = time() - $start; |
||||||
1614 | } |
||||||
1615 | } |
||||||
1616 | } else { |
||||||
1617 | $time = $given_time; |
||||||
1618 | } |
||||||
1619 | if (self::DEBUG > 2) { |
||||||
1620 | error_log( |
||||||
1621 | 'learnpathItem::get_scorm_time(): intermediate = '.$time, |
||||||
1622 | 0 |
||||||
1623 | ); |
||||||
1624 | } |
||||||
1625 | $time = api_format_time($time, $origin); |
||||||
1626 | |||||||
1627 | return $time; |
||||||
1628 | } |
||||||
1629 | |||||||
1630 | /** |
||||||
1631 | * Get the extra terms (tags) that identify this item. |
||||||
1632 | * |
||||||
1633 | * @return mixed |
||||||
1634 | */ |
||||||
1635 | public function get_terms() |
||||||
1636 | { |
||||||
1637 | $table = Database::get_course_table(TABLE_LP_ITEM); |
||||||
1638 | $sql = "SELECT * FROM $table |
||||||
1639 | WHERE iid = ".intval($this->db_id); |
||||||
1640 | $res = Database::query($sql); |
||||||
1641 | $row = Database::fetch_array($res); |
||||||
1642 | |||||||
1643 | return $row['terms']; |
||||||
1644 | } |
||||||
1645 | |||||||
1646 | /** |
||||||
1647 | * Returns the item's title. |
||||||
1648 | * |
||||||
1649 | * @return string Title |
||||||
1650 | */ |
||||||
1651 | public function get_title() |
||||||
1652 | { |
||||||
1653 | if (empty($this->title)) { |
||||||
1654 | return ''; |
||||||
1655 | } |
||||||
1656 | |||||||
1657 | return $this->title; |
||||||
1658 | } |
||||||
1659 | |||||||
1660 | /** |
||||||
1661 | * Returns the total time used to see that item. |
||||||
1662 | * |
||||||
1663 | * @return int Total time |
||||||
1664 | */ |
||||||
1665 | public function get_total_time() |
||||||
1666 | { |
||||||
1667 | $debug = self::DEBUG; |
||||||
1668 | if ($debug) { |
||||||
1669 | error_log( |
||||||
1670 | 'learnpathItem::get_total_time() for item '.$this->db_id. |
||||||
1671 | ' - Initially, current_start_time = '.$this->current_start_time. |
||||||
1672 | ' and current_stop_time = '.$this->current_stop_time, |
||||||
1673 | 0 |
||||||
1674 | ); |
||||||
1675 | } |
||||||
1676 | if (0 == $this->current_start_time) { |
||||||
1677 | // Shouldn't be necessary thanks to the open() method. |
||||||
1678 | if ($debug) { |
||||||
1679 | error_log( |
||||||
1680 | 'learnpathItem::get_total_time() - Current start time was empty', |
||||||
1681 | 0 |
||||||
1682 | ); |
||||||
1683 | } |
||||||
1684 | $this->current_start_time = time(); |
||||||
1685 | } |
||||||
1686 | |||||||
1687 | if (time() < $this->current_stop_time || |
||||||
1688 | 0 == $this->current_stop_time |
||||||
1689 | ) { |
||||||
1690 | if ($debug) { |
||||||
1691 | error_log( |
||||||
1692 | 'learnpathItem::get_total_time() - Current stop time was ' |
||||||
1693 | .'greater than the current time or was empty', |
||||||
1694 | 0 |
||||||
1695 | ); |
||||||
1696 | } |
||||||
1697 | // If this case occurs, then we risk to write huge time data in db. |
||||||
1698 | // In theory, stop time should be *always* updated here, but it |
||||||
1699 | // might be used in some unknown goal. |
||||||
1700 | $this->current_stop_time = time(); |
||||||
1701 | } |
||||||
1702 | |||||||
1703 | $time = $this->current_stop_time - $this->current_start_time; |
||||||
1704 | |||||||
1705 | if ($time < 0) { |
||||||
1706 | if ($debug) { |
||||||
1707 | error_log( |
||||||
1708 | 'learnpathItem::get_total_time() - Time smaller than 0. Returning 0', |
||||||
1709 | 0 |
||||||
1710 | ); |
||||||
1711 | } |
||||||
1712 | |||||||
1713 | return 0; |
||||||
1714 | } else { |
||||||
1715 | $time = $this->fixAbusiveTime($time); |
||||||
1716 | if ($debug) { |
||||||
1717 | error_log( |
||||||
1718 | 'Current start time = '.$this->current_start_time.', current stop time = '. |
||||||
1719 | $this->current_stop_time.' Returning '.$time."-----------\n" |
||||||
1720 | ); |
||||||
1721 | } |
||||||
1722 | |||||||
1723 | return $time; |
||||||
1724 | } |
||||||
1725 | } |
||||||
1726 | |||||||
1727 | /** |
||||||
1728 | * Sometimes time recorded for a learning path item is superior to the maximum allowed duration of the session. |
||||||
1729 | * In this case, this session resets the time for that particular learning path item to 5 minutes |
||||||
1730 | * (something more realistic, that is also used when leaving the portal without closing one's session). |
||||||
1731 | * |
||||||
1732 | * @param int $time |
||||||
1733 | * |
||||||
1734 | * @return int |
||||||
1735 | */ |
||||||
1736 | public function fixAbusiveTime($time) |
||||||
1737 | { |
||||||
1738 | // Code based from Event::courseLogout |
||||||
1739 | $sessionLifetime = api_get_configuration_value('session_lifetime'); |
||||||
1740 | // If session life time too big use 1 hour |
||||||
1741 | if (empty($sessionLifetime) || $sessionLifetime > 86400) { |
||||||
1742 | $sessionLifetime = 3600; |
||||||
1743 | } |
||||||
1744 | |||||||
1745 | if (!Tracking::minimumTimeAvailable(api_get_session_id(), api_get_course_int_id())) { |
||||||
1746 | $fixedAddedMinute = 5 * 60; // Add only 5 minutes |
||||||
1747 | if ($time > $sessionLifetime) { |
||||||
1748 | error_log("fixAbusiveTime: Total time is too big: $time replaced with: $fixedAddedMinute"); |
||||||
1749 | error_log("item_id : ".$this->db_id." lp_item_view.iid: ".$this->db_item_view_id); |
||||||
1750 | $time = $fixedAddedMinute; |
||||||
1751 | } |
||||||
1752 | |||||||
1753 | return $time; |
||||||
1754 | } else { |
||||||
1755 | // Calulate minimum and accumulated time |
||||||
1756 | $user_id = api_get_user_id(); |
||||||
1757 | $myLP = learnpath::getLpFromSession(api_get_course_int_id(), $this->lp_id, $user_id); |
||||||
1758 | $timeLp = $myLP->getAccumulateWorkTime(); |
||||||
1759 | $timeTotalCourse = $myLP->getAccumulateWorkTimeTotalCourse(); |
||||||
1760 | /* |
||||||
1761 | $timeLp = $_SESSION['oLP']->getAccumulateWorkTime(); |
||||||
1762 | $timeTotalCourse = $_SESSION['oLP']->getAccumulateWorkTimeTotalCourse(); |
||||||
1763 | */ |
||||||
1764 | // Minimum connection percentage |
||||||
1765 | $perc = 100; |
||||||
1766 | // Time from the course |
||||||
1767 | $tc = $timeTotalCourse; |
||||||
1768 | /*if (!empty($sessionId) && $sessionId != 0) { |
||||||
1769 | $sql = "SELECT hours, perc FROM plugin_licences_course_session WHERE session_id = $sessionId"; |
||||||
1770 | $res = Database::query($sql); |
||||||
1771 | if (Database::num_rows($res) > 0) { |
||||||
1772 | $aux = Database::fetch_assoc($res); |
||||||
1773 | $perc = $aux['perc']; |
||||||
1774 | $tc = $aux['hours'] * 60; |
||||||
1775 | } |
||||||
1776 | }*/ |
||||||
1777 | // Percentage of the learning paths |
||||||
1778 | $pl = 0; |
||||||
1779 | if (!empty($timeTotalCourse)) { |
||||||
1780 | $pl = $timeLp / $timeTotalCourse; |
||||||
1781 | } |
||||||
1782 | |||||||
1783 | // Minimum time for each learning path |
||||||
1784 | $accumulateWorkTime = ($pl * $tc * $perc / 100); |
||||||
1785 | $time_seg = intval($accumulateWorkTime * 60); |
||||||
1786 | |||||||
1787 | if ($time_seg < $sessionLifetime) { |
||||||
1788 | $sessionLifetime = $time_seg; |
||||||
1789 | } |
||||||
1790 | |||||||
1791 | if ($time > $sessionLifetime) { |
||||||
1792 | $fixedAddedMinute = $time_seg + mt_rand(0, 300); |
||||||
1793 | if (self::DEBUG > 2) { |
||||||
1794 | error_log("Total time is too big: $time replaced with: $fixedAddedMinute"); |
||||||
1795 | } |
||||||
1796 | $time = $fixedAddedMinute; |
||||||
1797 | } |
||||||
1798 | |||||||
1799 | return $time; |
||||||
1800 | } |
||||||
1801 | } |
||||||
1802 | |||||||
1803 | /** |
||||||
1804 | * Gets the item type. |
||||||
1805 | * |
||||||
1806 | * @return string The item type (can be doc, dir, sco, asset) |
||||||
1807 | */ |
||||||
1808 | public function get_type() |
||||||
1809 | { |
||||||
1810 | $res = 'asset'; |
||||||
1811 | if (!empty($this->type)) { |
||||||
1812 | $res = $this->type; |
||||||
1813 | } |
||||||
1814 | |||||||
1815 | return $res; |
||||||
1816 | } |
||||||
1817 | |||||||
1818 | /** |
||||||
1819 | * Gets the view count for this item. |
||||||
1820 | * |
||||||
1821 | * @return int Number of attempts or 0 |
||||||
1822 | */ |
||||||
1823 | public function get_view_count() |
||||||
1824 | { |
||||||
1825 | if (!empty($this->attempt_id)) { |
||||||
1826 | return $this->attempt_id; |
||||||
1827 | } |
||||||
1828 | |||||||
1829 | return 0; |
||||||
1830 | } |
||||||
1831 | |||||||
1832 | /** |
||||||
1833 | * Tells if an item is done ('completed','passed','succeeded') or not. |
||||||
1834 | * |
||||||
1835 | * @return bool True if the item is done ('completed','passed','succeeded'), |
||||||
1836 | * false otherwise |
||||||
1837 | */ |
||||||
1838 | public function is_done() |
||||||
1839 | { |
||||||
1840 | $completedStatusList = [ |
||||||
1841 | 'completed', |
||||||
1842 | 'passed', |
||||||
1843 | 'succeeded', |
||||||
1844 | 'failed', |
||||||
1845 | ]; |
||||||
1846 | |||||||
1847 | if ($this->status_is($completedStatusList)) { |
||||||
1848 | return true; |
||||||
1849 | } |
||||||
1850 | |||||||
1851 | return false; |
||||||
1852 | } |
||||||
1853 | |||||||
1854 | /** |
||||||
1855 | * Tells if a restart is allowed (take it from $this->prevent_reinit and $this->status). |
||||||
1856 | * |
||||||
1857 | * @return int -1 if retaking the sco another time for credit is not allowed, |
||||||
1858 | * 0 if it is not allowed but the item has to be finished |
||||||
1859 | * 1 if it is allowed. Defaults to 1 |
||||||
1860 | */ |
||||||
1861 | public function isRestartAllowed() |
||||||
1862 | { |
||||||
1863 | $restart = 1; |
||||||
1864 | $mystatus = $this->get_status(true); |
||||||
1865 | if ($this->get_prevent_reinit() > 0) { |
||||||
1866 | // If prevent_reinit == 1 (or more) |
||||||
1867 | // If status is not attempted or incomplete, authorize retaking (of the same) anyway. Otherwise: |
||||||
1868 | if ($mystatus != $this->possible_status[0] && $mystatus != $this->possible_status[1]) { |
||||||
1869 | $restart = -1; |
||||||
1870 | } else { //status incompleted or not attempted |
||||||
1871 | $restart = 0; |
||||||
1872 | } |
||||||
1873 | } else { |
||||||
1874 | if ($mystatus == $this->possible_status[0] || $mystatus == $this->possible_status[1]) { |
||||||
1875 | $restart = -1; |
||||||
1876 | } |
||||||
1877 | } |
||||||
1878 | |||||||
1879 | return $restart; |
||||||
1880 | } |
||||||
1881 | |||||||
1882 | /** |
||||||
1883 | * Opens/launches the item. Initialises runtime values. |
||||||
1884 | * |
||||||
1885 | * @param bool $allow_new_attempt |
||||||
1886 | * |
||||||
1887 | * @return bool true on success, false on failure |
||||||
1888 | */ |
||||||
1889 | public function open($allow_new_attempt = false) |
||||||
1890 | { |
||||||
1891 | if (0 == $this->prevent_reinit) { |
||||||
1892 | $this->current_score = 0; |
||||||
1893 | $this->current_start_time = time(); |
||||||
1894 | // In this case, as we are opening the item, what is important to us |
||||||
1895 | // is the database status, in order to know if this item has already |
||||||
1896 | // been used in the past (rather than just loaded and modified by |
||||||
1897 | // some javascript but not written in the database). |
||||||
1898 | // If the database status is different from 'not attempted', we can |
||||||
1899 | // consider this item has already been used, and as such we can |
||||||
1900 | // open a new attempt. Otherwise, we'll just reuse the current |
||||||
1901 | // attempt, which is generally created the first time the item is |
||||||
1902 | // loaded (for example as part of the table of contents). |
||||||
1903 | $stat = $this->get_status(true); |
||||||
1904 | if ($allow_new_attempt && isset($stat) && ($stat != $this->possible_status[0])) { |
||||||
1905 | $this->attempt_id = $this->attempt_id + 1; // Open a new attempt. |
||||||
1906 | } |
||||||
1907 | $this->status = $this->possible_status[1]; |
||||||
1908 | } else { |
||||||
1909 | /*if ($this->current_start_time == 0) { |
||||||
1910 | // Small exception for start time, to avoid amazing values. |
||||||
1911 | $this->current_start_time = time(); |
||||||
1912 | }*/ |
||||||
1913 | // If we don't init start time here, the time is sometimes calculated from the last start time. |
||||||
1914 | $this->current_start_time = time(); |
||||||
1915 | } |
||||||
1916 | } |
||||||
1917 | |||||||
1918 | /** |
||||||
1919 | * Outputs the item contents. |
||||||
1920 | * |
||||||
1921 | * @return string HTML file (displayable in an <iframe>) or empty string if no path defined |
||||||
1922 | */ |
||||||
1923 | public function output() |
||||||
1924 | { |
||||||
1925 | if (!empty($this->path) and is_file($this->path)) { |
||||||
1926 | $output = ''; |
||||||
1927 | $output .= file_get_contents($this->path); |
||||||
1928 | |||||||
1929 | return $output; |
||||||
1930 | } |
||||||
1931 | |||||||
1932 | return ''; |
||||||
1933 | } |
||||||
1934 | |||||||
1935 | /** |
||||||
1936 | * Parses the prerequisites string with the AICC logic language. |
||||||
1937 | * |
||||||
1938 | * @param string $prereqs_string The prerequisites string as it figures in imsmanifest.xml |
||||||
1939 | * @param array $items Array of items in the current learnpath object. |
||||||
1940 | * Although we're in the learnpathItem object, it's necessary to have |
||||||
1941 | * a list of all items to be able to check the current item's prerequisites |
||||||
1942 | * @param array $refs_list list of references |
||||||
1943 | * (the "ref" column in the lp_item table) that are strings used in the |
||||||
1944 | * expression of prerequisites |
||||||
1945 | * @param int $user_id The user ID. In some cases like Chamilo quizzes, |
||||||
1946 | * it's necessary to have the user ID to query other tables (like the results of quizzes) |
||||||
1947 | * |
||||||
1948 | * @return bool True if the list of prerequisites given is entirely satisfied, false otherwise |
||||||
1949 | */ |
||||||
1950 | public function parse_prereq($prereqs_string, $items, $refs_list, $user_id) |
||||||
1951 | { |
||||||
1952 | $debug = self::DEBUG; |
||||||
1953 | if ($debug > 0) { |
||||||
1954 | error_log( |
||||||
1955 | 'learnpathItem::parse_prereq() for learnpath '.$this->lp_id.' with string '.$prereqs_string, |
||||||
1956 | 0 |
||||||
1957 | ); |
||||||
1958 | } |
||||||
1959 | |||||||
1960 | $courseId = $this->courseId; |
||||||
1961 | $sessionId = api_get_session_id(); |
||||||
1962 | |||||||
1963 | // Deal with &, |, ~, =, <>, {}, ,, X*, () in reverse order. |
||||||
1964 | $this->prereq_alert = ''; |
||||||
1965 | |||||||
1966 | // First parse all parenthesis by using a sequential loop |
||||||
1967 | // (looking for less-inclusives first). |
||||||
1968 | if ('_true_' == $prereqs_string) { |
||||||
1969 | return true; |
||||||
1970 | } |
||||||
1971 | |||||||
1972 | if ('_false_' == $prereqs_string) { |
||||||
1973 | if (empty($this->prereq_alert)) { |
||||||
1974 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
1975 | } |
||||||
1976 | |||||||
1977 | return false; |
||||||
1978 | } |
||||||
1979 | |||||||
1980 | while (false !== strpos($prereqs_string, '(')) { |
||||||
1981 | // Remove any () set and replace with its value. |
||||||
1982 | $matches = []; |
||||||
1983 | $res = preg_match_all( |
||||||
1984 | '/(\(([^\(\)]*)\))/', |
||||||
1985 | $prereqs_string, |
||||||
1986 | $matches |
||||||
1987 | ); |
||||||
1988 | if ($res) { |
||||||
0 ignored issues
–
show
The expression
$res of type integer|null is loosely compared to true ; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
![]() |
|||||||
1989 | foreach ($matches[2] as $id => $match) { |
||||||
1990 | $str_res = $this->parse_prereq( |
||||||
1991 | $match, |
||||||
1992 | $items, |
||||||
1993 | $refs_list, |
||||||
1994 | $user_id |
||||||
1995 | ); |
||||||
1996 | if ($str_res) { |
||||||
1997 | $prereqs_string = str_replace( |
||||||
1998 | $matches[1][$id], |
||||||
1999 | '_true_', |
||||||
2000 | $prereqs_string |
||||||
2001 | ); |
||||||
2002 | } else { |
||||||
2003 | $prereqs_string = str_replace( |
||||||
2004 | $matches[1][$id], |
||||||
2005 | '_false_', |
||||||
2006 | $prereqs_string |
||||||
2007 | ); |
||||||
2008 | } |
||||||
2009 | } |
||||||
2010 | } |
||||||
2011 | } |
||||||
2012 | |||||||
2013 | // Parenthesis removed, now look for ORs as it is the lesser-priority |
||||||
2014 | // binary operator (= always uses one text operand). |
||||||
2015 | if (false === strpos($prereqs_string, '|')) { |
||||||
2016 | if ($debug) { |
||||||
2017 | error_log('New LP - Didnt find any OR, looking for AND', 0); |
||||||
2018 | } |
||||||
2019 | if (false !== strpos($prereqs_string, '&')) { |
||||||
2020 | $list = explode('&', $prereqs_string); |
||||||
2021 | if (count($list) > 1) { |
||||||
2022 | $andstatus = true; |
||||||
2023 | foreach ($list as $condition) { |
||||||
2024 | $andstatus = $andstatus && $this->parse_prereq( |
||||||
2025 | $condition, |
||||||
2026 | $items, |
||||||
2027 | $refs_list, |
||||||
2028 | $user_id |
||||||
2029 | ); |
||||||
2030 | |||||||
2031 | if (!$andstatus) { |
||||||
2032 | if ($debug) { |
||||||
2033 | error_log( |
||||||
2034 | 'New LP - One condition in AND was false, short-circuit', |
||||||
2035 | 0 |
||||||
2036 | ); |
||||||
2037 | } |
||||||
2038 | break; |
||||||
2039 | } |
||||||
2040 | } |
||||||
2041 | |||||||
2042 | if (empty($this->prereq_alert) && !$andstatus) { |
||||||
2043 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
2044 | } |
||||||
2045 | |||||||
2046 | return $andstatus; |
||||||
2047 | } else { |
||||||
2048 | if (isset($items[$refs_list[$list[0]]])) { |
||||||
2049 | $status = $items[$refs_list[$list[0]]]->get_status(true); |
||||||
2050 | $returnstatus = ($status == $this->possible_status[2]) || ($status == $this->possible_status[3]); |
||||||
2051 | if (empty($this->prereq_alert) && !$returnstatus) { |
||||||
2052 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
2053 | } |
||||||
2054 | |||||||
2055 | return $returnstatus; |
||||||
2056 | } |
||||||
2057 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
2058 | |||||||
2059 | return false; |
||||||
2060 | } |
||||||
2061 | } else { |
||||||
2062 | // No ORs found, now look for ANDs. |
||||||
2063 | if ($debug) { |
||||||
2064 | error_log('New LP - Didnt find any AND, looking for =', 0); |
||||||
2065 | } |
||||||
2066 | |||||||
2067 | if (false !== strpos($prereqs_string, '=')) { |
||||||
2068 | if ($debug) { |
||||||
2069 | error_log('New LP - Found =, looking into it', 0); |
||||||
2070 | } |
||||||
2071 | // We assume '=' signs only appear when there's nothing else around. |
||||||
2072 | $params = explode('=', $prereqs_string); |
||||||
2073 | if (2 == count($params)) { |
||||||
2074 | // Right number of operands. |
||||||
2075 | if (isset($items[$refs_list[$params[0]]])) { |
||||||
2076 | $status = $items[$refs_list[$params[0]]]->get_status(true); |
||||||
2077 | $returnstatus = $status == $params[1]; |
||||||
2078 | if (empty($this->prereq_alert) && !$returnstatus) { |
||||||
2079 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
2080 | } |
||||||
2081 | |||||||
2082 | return $returnstatus; |
||||||
2083 | } |
||||||
2084 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
2085 | |||||||
2086 | return false; |
||||||
2087 | } |
||||||
2088 | } else { |
||||||
2089 | // No ANDs found, look for <> |
||||||
2090 | if ($debug) { |
||||||
2091 | error_log( |
||||||
2092 | 'New LP - Didnt find any =, looking for <>', |
||||||
2093 | 0 |
||||||
2094 | ); |
||||||
2095 | } |
||||||
2096 | |||||||
2097 | if (false !== strpos($prereqs_string, '<>')) { |
||||||
2098 | if ($debug) { |
||||||
2099 | error_log('New LP - Found <>, looking into it', 0); |
||||||
2100 | } |
||||||
2101 | // We assume '<>' signs only appear when there's nothing else around. |
||||||
2102 | $params = explode('<>', $prereqs_string); |
||||||
2103 | if (2 == count($params)) { |
||||||
2104 | // Right number of operands. |
||||||
2105 | if (isset($items[$refs_list[$params[0]]])) { |
||||||
2106 | $status = $items[$refs_list[$params[0]]]->get_status(true); |
||||||
2107 | $returnstatus = $status != $params[1]; |
||||||
2108 | if (empty($this->prereq_alert) && !$returnstatus) { |
||||||
2109 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
2110 | } |
||||||
2111 | |||||||
2112 | return $returnstatus; |
||||||
2113 | } |
||||||
2114 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
2115 | |||||||
2116 | return false; |
||||||
2117 | } |
||||||
2118 | } else { |
||||||
2119 | // No <> found, look for ~ (unary) |
||||||
2120 | if ($debug) { |
||||||
2121 | error_log( |
||||||
2122 | 'New LP - Didnt find any =, looking for ~', |
||||||
2123 | 0 |
||||||
2124 | ); |
||||||
2125 | } |
||||||
2126 | // Only remains: ~ and X*{} |
||||||
2127 | if (false !== strpos($prereqs_string, '~')) { |
||||||
2128 | // Found NOT. |
||||||
2129 | if ($debug) { |
||||||
2130 | error_log( |
||||||
2131 | 'New LP - Found ~, looking into it', |
||||||
2132 | 0 |
||||||
2133 | ); |
||||||
2134 | } |
||||||
2135 | $list = []; |
||||||
2136 | $myres = preg_match( |
||||||
2137 | '/~([^(\d+\*)\{]*)/', |
||||||
2138 | $prereqs_string, |
||||||
2139 | $list |
||||||
2140 | ); |
||||||
2141 | if ($myres) { |
||||||
2142 | $returnstatus = !$this->parse_prereq( |
||||||
2143 | $list[1], |
||||||
2144 | $items, |
||||||
2145 | $refs_list, |
||||||
2146 | $user_id |
||||||
2147 | ); |
||||||
2148 | if (empty($this->prereq_alert) && !$returnstatus) { |
||||||
2149 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
2150 | } |
||||||
2151 | |||||||
2152 | return $returnstatus; |
||||||
2153 | } else { |
||||||
2154 | // Strange... |
||||||
2155 | if ($debug) { |
||||||
2156 | error_log( |
||||||
2157 | 'New LP - Found ~ but strange string: '.$prereqs_string, |
||||||
2158 | 0 |
||||||
2159 | ); |
||||||
2160 | } |
||||||
2161 | } |
||||||
2162 | } else { |
||||||
2163 | // Finally, look for sets/groups |
||||||
2164 | if ($debug) { |
||||||
2165 | error_log( |
||||||
2166 | 'New LP - Didnt find any ~, looking for groups', |
||||||
2167 | 0 |
||||||
2168 | ); |
||||||
2169 | } |
||||||
2170 | // Only groups here. |
||||||
2171 | $groups = []; |
||||||
2172 | $groups_there = preg_match_all( |
||||||
2173 | '/((\d+\*)?\{([^\}]+)\}+)/', |
||||||
2174 | $prereqs_string, |
||||||
2175 | $groups |
||||||
2176 | ); |
||||||
2177 | |||||||
2178 | if ($groups_there) { |
||||||
0 ignored issues
–
show
The expression
$groups_there of type integer|null is loosely compared to true ; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
![]() |
|||||||
2179 | foreach ($groups[1] as $gr) { |
||||||
2180 | // Only take the results that correspond to |
||||||
2181 | // the big brackets-enclosed condition. |
||||||
2182 | if ($debug) { |
||||||
2183 | error_log( |
||||||
2184 | 'New LP - Dealing with group '.$gr, |
||||||
2185 | 0 |
||||||
2186 | ); |
||||||
2187 | } |
||||||
2188 | $multi = []; |
||||||
2189 | $mycond = false; |
||||||
2190 | if (preg_match( |
||||||
2191 | '/(\d+)\*\{([^\}]+)\}/', |
||||||
2192 | $gr, |
||||||
2193 | $multi |
||||||
2194 | ) |
||||||
2195 | ) { |
||||||
2196 | if ($debug) { |
||||||
2197 | error_log( |
||||||
2198 | 'New LP - Found multiplier '.$multi[0], |
||||||
2199 | 0 |
||||||
2200 | ); |
||||||
2201 | } |
||||||
2202 | $count = $multi[1]; |
||||||
2203 | $list = explode(',', $multi[2]); |
||||||
2204 | $mytrue = 0; |
||||||
2205 | foreach ($list as $cond) { |
||||||
2206 | if (isset($items[$refs_list[$cond]])) { |
||||||
2207 | $status = $items[$refs_list[$cond]]->get_status(true); |
||||||
2208 | if ($status == $this->possible_status[2] || |
||||||
2209 | $status == $this->possible_status[3] |
||||||
2210 | ) { |
||||||
2211 | $mytrue++; |
||||||
2212 | if ($debug) { |
||||||
2213 | error_log( |
||||||
2214 | 'New LP - Found true item, counting.. ('.($mytrue).')', |
||||||
2215 | 0 |
||||||
2216 | ); |
||||||
2217 | } |
||||||
2218 | } |
||||||
2219 | } else { |
||||||
2220 | if ($debug) { |
||||||
2221 | error_log( |
||||||
2222 | 'New LP - item '.$cond.' does not exist in items list', |
||||||
2223 | 0 |
||||||
2224 | ); |
||||||
2225 | } |
||||||
2226 | } |
||||||
2227 | } |
||||||
2228 | if ($mytrue >= $count) { |
||||||
2229 | if ($debug) { |
||||||
2230 | error_log( |
||||||
2231 | 'New LP - Got enough true results, return true', |
||||||
2232 | 0 |
||||||
2233 | ); |
||||||
2234 | } |
||||||
2235 | $mycond = true; |
||||||
2236 | } else { |
||||||
2237 | if ($debug) { |
||||||
2238 | error_log( |
||||||
2239 | 'New LP - Not enough true results', |
||||||
2240 | 0 |
||||||
2241 | ); |
||||||
2242 | } |
||||||
2243 | } |
||||||
2244 | } else { |
||||||
2245 | if ($debug) { |
||||||
2246 | error_log( |
||||||
2247 | 'New LP - No multiplier', |
||||||
2248 | 0 |
||||||
2249 | ); |
||||||
2250 | } |
||||||
2251 | $list = explode(',', $gr); |
||||||
2252 | $mycond = true; |
||||||
2253 | foreach ($list as $cond) { |
||||||
2254 | if (isset($items[$refs_list[$cond]])) { |
||||||
2255 | $status = $items[$refs_list[$cond]]->get_status(true); |
||||||
2256 | if ($status == $this->possible_status[2] || |
||||||
2257 | $status == $this->possible_status[3] |
||||||
2258 | ) { |
||||||
2259 | $mycond = true; |
||||||
2260 | if ($debug) { |
||||||
2261 | error_log( |
||||||
2262 | 'New LP - Found true item', |
||||||
2263 | 0 |
||||||
2264 | ); |
||||||
2265 | } |
||||||
2266 | } else { |
||||||
2267 | if ($debug) { |
||||||
2268 | error_log( |
||||||
2269 | 'New LP - '. |
||||||
2270 | ' Found false item, the set is not true, return false', |
||||||
2271 | 0 |
||||||
2272 | ); |
||||||
2273 | } |
||||||
2274 | $mycond = false; |
||||||
2275 | break; |
||||||
2276 | } |
||||||
2277 | } else { |
||||||
2278 | if ($debug) { |
||||||
2279 | error_log( |
||||||
2280 | 'New LP - item '.$cond.' does not exist in items list', |
||||||
2281 | 0 |
||||||
2282 | ); |
||||||
2283 | } |
||||||
2284 | if ($debug) { |
||||||
2285 | error_log( |
||||||
2286 | 'New LP - Found false item, the set is not true, return false', |
||||||
2287 | 0 |
||||||
2288 | ); |
||||||
2289 | } |
||||||
2290 | $mycond = false; |
||||||
2291 | break; |
||||||
2292 | } |
||||||
2293 | } |
||||||
2294 | } |
||||||
2295 | if (!$mycond && empty($this->prereq_alert)) { |
||||||
2296 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
2297 | } |
||||||
2298 | |||||||
2299 | return $mycond; |
||||||
2300 | } |
||||||
2301 | } else { |
||||||
2302 | // Nothing found there either. Now return the |
||||||
2303 | // value of the corresponding resource completion status. |
||||||
2304 | if (isset($refs_list[$prereqs_string]) && |
||||||
2305 | isset($items[$refs_list[$prereqs_string]]) |
||||||
2306 | ) { |
||||||
2307 | /** @var learnpathItem $itemToCheck */ |
||||||
2308 | $itemToCheck = $items[$refs_list[$prereqs_string]]; |
||||||
2309 | |||||||
2310 | if ('quiz' === $itemToCheck->type) { |
||||||
2311 | // 1. Checking the status in current items. |
||||||
2312 | $status = $itemToCheck->get_status(true); |
||||||
2313 | $returnstatus = $status == $this->possible_status[2] || $status == $this->possible_status[3]; |
||||||
2314 | |||||||
2315 | if (!$returnstatus) { |
||||||
2316 | $explanation = sprintf( |
||||||
2317 | get_lang('Item %s blocks this step'), |
||||||
2318 | $itemToCheck->get_title() |
||||||
2319 | ); |
||||||
2320 | $this->prereq_alert = $explanation; |
||||||
2321 | } |
||||||
2322 | |||||||
2323 | // For one and first attempt. |
||||||
2324 | if (1 == $this->prevent_reinit) { |
||||||
2325 | // 2. If is completed we check the results in the DB of the quiz. |
||||||
2326 | if ($returnstatus) { |
||||||
2327 | $sql = 'SELECT score, max_score |
||||||
2328 | FROM '.Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES).' |
||||||
2329 | WHERE |
||||||
2330 | exe_exo_id = '.$items[$refs_list[$prereqs_string]]->path.' AND |
||||||
2331 | exe_user_id = '.$user_id.' AND |
||||||
2332 | orig_lp_id = '.$this->lp_id.' AND |
||||||
2333 | orig_lp_item_id = '.$prereqs_string.' AND |
||||||
2334 | status <> "incomplete" AND |
||||||
2335 | c_id = '.$courseId.' |
||||||
2336 | ORDER BY exe_date DESC |
||||||
2337 | LIMIT 0, 1'; |
||||||
2338 | $rs_quiz = Database::query($sql); |
||||||
2339 | if ($quiz = Database::fetch_array($rs_quiz)) { |
||||||
2340 | /** @var learnpathItem $myItemToCheck */ |
||||||
2341 | $myItemToCheck = $items[$refs_list[$this->get_id()]]; |
||||||
2342 | $minScore = $myItemToCheck->getPrerequisiteMinScore(); |
||||||
2343 | $maxScore = $myItemToCheck->getPrerequisiteMaxScore(); |
||||||
2344 | |||||||
2345 | if (isset($minScore) && isset($minScore)) { |
||||||
2346 | // Taking min/max prerequisites values see BT#5776 |
||||||
2347 | if ($quiz['score'] >= $minScore && |
||||||
2348 | $quiz['score'] <= $maxScore |
||||||
2349 | ) { |
||||||
2350 | $returnstatus = true; |
||||||
2351 | } else { |
||||||
2352 | $explanation = sprintf( |
||||||
2353 | get_lang('Your result at %s blocks this step'), |
||||||
2354 | $itemToCheck->get_title() |
||||||
2355 | ); |
||||||
2356 | $this->prereq_alert = $explanation; |
||||||
2357 | $returnstatus = false; |
||||||
2358 | } |
||||||
2359 | } else { |
||||||
2360 | // Classic way |
||||||
2361 | if ($quiz['score'] >= |
||||||
2362 | $items[$refs_list[$prereqs_string]]->get_mastery_score() |
||||||
2363 | ) { |
||||||
2364 | $returnstatus = true; |
||||||
2365 | } else { |
||||||
2366 | $explanation = sprintf( |
||||||
2367 | get_lang('Your result at %s blocks this step'), |
||||||
2368 | $itemToCheck->get_title() |
||||||
2369 | ); |
||||||
2370 | $this->prereq_alert = $explanation; |
||||||
2371 | $returnstatus = false; |
||||||
2372 | } |
||||||
2373 | } |
||||||
2374 | } else { |
||||||
2375 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
2376 | $returnstatus = false; |
||||||
2377 | } |
||||||
2378 | } |
||||||
2379 | } else { |
||||||
2380 | // 3. For multiple attempts we check that there are minimum 1 item completed |
||||||
2381 | // Checking in the database. |
||||||
2382 | $sql = 'SELECT score, max_score |
||||||
2383 | FROM '.Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES).' |
||||||
2384 | WHERE |
||||||
2385 | c_id = '.$courseId.' AND |
||||||
2386 | exe_exo_id = '.$items[$refs_list[$prereqs_string]]->path.' AND |
||||||
2387 | exe_user_id = '.$user_id.' AND |
||||||
2388 | orig_lp_id = '.$this->lp_id.' AND |
||||||
2389 | orig_lp_item_id = '.$prereqs_string; |
||||||
2390 | |||||||
2391 | $rs_quiz = Database::query($sql); |
||||||
2392 | if (Database::num_rows($rs_quiz) > 0) { |
||||||
2393 | while ($quiz = Database::fetch_array($rs_quiz)) { |
||||||
2394 | /** @var learnpathItem $myItemToCheck */ |
||||||
2395 | $myItemToCheck = $items[$refs_list[$this->get_id()]]; |
||||||
2396 | $minScore = $myItemToCheck->getPrerequisiteMinScore(); |
||||||
2397 | $maxScore = $myItemToCheck->getPrerequisiteMaxScore(); |
||||||
2398 | |||||||
2399 | if (empty($minScore)) { |
||||||
2400 | // Try with mastery_score |
||||||
2401 | $masteryScoreAsMin = $myItemToCheck->get_mastery_score(); |
||||||
2402 | if (!empty($masteryScoreAsMin)) { |
||||||
2403 | $minScore = $masteryScoreAsMin; |
||||||
2404 | } |
||||||
2405 | } |
||||||
2406 | |||||||
2407 | if (isset($minScore) && isset($minScore)) { |
||||||
2408 | // Taking min/max prerequisites values see BT#5776 |
||||||
2409 | if ($quiz['score'] >= $minScore && $quiz['score'] <= $maxScore) { |
||||||
2410 | $returnstatus = true; |
||||||
2411 | break; |
||||||
2412 | } else { |
||||||
2413 | $explanation = sprintf( |
||||||
2414 | get_lang('Your result at %s blocks this step'), |
||||||
2415 | $itemToCheck->get_title() |
||||||
2416 | ); |
||||||
2417 | $this->prereq_alert = $explanation; |
||||||
2418 | $returnstatus = false; |
||||||
2419 | } |
||||||
2420 | } else { |
||||||
2421 | if ($quiz['score'] >= |
||||||
2422 | $items[$refs_list[$prereqs_string]]->get_mastery_score() |
||||||
2423 | ) { |
||||||
2424 | $returnstatus = true; |
||||||
2425 | break; |
||||||
2426 | } else { |
||||||
2427 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
2428 | $returnstatus = false; |
||||||
2429 | } |
||||||
2430 | } |
||||||
2431 | } |
||||||
2432 | } else { |
||||||
2433 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
2434 | $returnstatus = false; |
||||||
2435 | } |
||||||
2436 | } |
||||||
2437 | |||||||
2438 | if (false === $returnstatus) { |
||||||
2439 | // Check results from another sessions. |
||||||
2440 | $checkOtherSessions = ('true' === api_get_setting('lp.validate_lp_prerequisite_from_other_session')); |
||||||
2441 | if ($checkOtherSessions) { |
||||||
2442 | $returnstatus = $this->getStatusFromOtherSessions( |
||||||
2443 | $user_id, |
||||||
2444 | $prereqs_string, |
||||||
2445 | $refs_list |
||||||
2446 | ); |
||||||
2447 | } |
||||||
2448 | } |
||||||
2449 | |||||||
2450 | return $returnstatus; |
||||||
2451 | } elseif ('student_publication' === $itemToCheck->type) { |
||||||
2452 | $workId = $items[$refs_list[$prereqs_string]]->path; |
||||||
2453 | $count = get_work_count_by_student($user_id, $workId); |
||||||
2454 | if ($count >= 1) { |
||||||
2455 | $returnstatus = true; |
||||||
2456 | } else { |
||||||
2457 | $returnstatus = false; |
||||||
2458 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
2459 | } |
||||||
2460 | |||||||
2461 | return $returnstatus; |
||||||
2462 | } else { |
||||||
2463 | $status = $itemToCheck->get_status(true); |
||||||
2464 | if (self::DEBUG) { |
||||||
2465 | error_log('Status:'.$status); |
||||||
2466 | } |
||||||
2467 | $returnstatus = $status == $this->possible_status[2] || $status == $this->possible_status[3]; |
||||||
2468 | |||||||
2469 | // Check results from another sessions. |
||||||
2470 | $checkOtherSessions = ('true' === api_get_setting('lp.validate_lp_prerequisite_from_other_session')); |
||||||
2471 | if ($checkOtherSessions && !$returnstatus) { |
||||||
2472 | $returnstatus = $this->getStatusFromOtherSessions( |
||||||
2473 | $user_id, |
||||||
2474 | $prereqs_string, |
||||||
2475 | $refs_list |
||||||
2476 | ); |
||||||
2477 | } |
||||||
2478 | |||||||
2479 | if (!$returnstatus) { |
||||||
2480 | $explanation = sprintf( |
||||||
2481 | get_lang('Item %s blocks this step'), |
||||||
2482 | $itemToCheck->get_title() |
||||||
2483 | ); |
||||||
2484 | $this->prereq_alert = $explanation; |
||||||
2485 | } |
||||||
2486 | |||||||
2487 | $lp_item_view = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||||||
2488 | $lp_view = Database::get_course_table(TABLE_LP_VIEW); |
||||||
2489 | |||||||
2490 | if ($returnstatus && 1 == $this->prevent_reinit) { |
||||||
2491 | $sql = "SELECT iid FROM $lp_view |
||||||
2492 | WHERE |
||||||
2493 | c_id = $courseId AND |
||||||
2494 | user_id = $user_id AND |
||||||
2495 | lp_id = $this->lp_id AND |
||||||
2496 | session_id = $sessionId |
||||||
2497 | LIMIT 0, 1"; |
||||||
2498 | $rs_lp = Database::query($sql); |
||||||
2499 | if (Database::num_rows($rs_lp)) { |
||||||
2500 | $lp_id = Database::fetch_row($rs_lp); |
||||||
2501 | $my_lp_id = $lp_id[0]; |
||||||
2502 | |||||||
2503 | $sql = "SELECT status FROM $lp_item_view |
||||||
2504 | WHERE |
||||||
2505 | lp_view_id = $my_lp_id AND |
||||||
2506 | lp_item_id = $refs_list[$prereqs_string] |
||||||
2507 | LIMIT 0, 1"; |
||||||
2508 | $rs_lp = Database::query($sql); |
||||||
2509 | $status_array = Database::fetch_row($rs_lp); |
||||||
2510 | $status = $status_array[0]; |
||||||
2511 | |||||||
2512 | $returnstatus = $status == $this->possible_status[2] || $status == $this->possible_status[3]; |
||||||
2513 | if (!$returnstatus && empty($this->prereq_alert)) { |
||||||
2514 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
2515 | } |
||||||
2516 | } |
||||||
2517 | |||||||
2518 | if ($checkOtherSessions && false === $returnstatus) { |
||||||
2519 | $returnstatus = $returnstatus = $this->getStatusFromOtherSessions( |
||||||
2520 | $user_id, |
||||||
2521 | $prereqs_string, |
||||||
2522 | $refs_list |
||||||
2523 | ); |
||||||
2524 | } |
||||||
2525 | } |
||||||
2526 | |||||||
2527 | return $returnstatus; |
||||||
2528 | } |
||||||
2529 | } |
||||||
2530 | } |
||||||
2531 | } |
||||||
2532 | } |
||||||
2533 | } |
||||||
2534 | } |
||||||
2535 | } else { |
||||||
2536 | $list = explode("\|", $prereqs_string); |
||||||
2537 | if (count($list) > 1) { |
||||||
2538 | if (self::DEBUG > 1) { |
||||||
2539 | error_log('New LP - Found OR, looking into it', 0); |
||||||
2540 | } |
||||||
2541 | $orstatus = false; |
||||||
2542 | foreach ($list as $condition) { |
||||||
2543 | if (self::DEBUG) { |
||||||
2544 | error_log( |
||||||
2545 | 'New LP - Found OR, adding it ('.$condition.')', |
||||||
2546 | 0 |
||||||
2547 | ); |
||||||
2548 | } |
||||||
2549 | $orstatus = $orstatus || $this->parse_prereq( |
||||||
2550 | $condition, |
||||||
2551 | $items, |
||||||
2552 | $refs_list, |
||||||
2553 | $user_id |
||||||
2554 | ); |
||||||
2555 | if ($orstatus) { |
||||||
2556 | // Shortcircuit OR. |
||||||
2557 | if (self::DEBUG > 1) { |
||||||
2558 | error_log( |
||||||
2559 | 'New LP - One condition in OR was true, short-circuit', |
||||||
2560 | 0 |
||||||
2561 | ); |
||||||
2562 | } |
||||||
2563 | break; |
||||||
2564 | } |
||||||
2565 | } |
||||||
2566 | if (!$orstatus && empty($this->prereq_alert)) { |
||||||
2567 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
2568 | } |
||||||
2569 | |||||||
2570 | return $orstatus; |
||||||
2571 | } else { |
||||||
2572 | if (self::DEBUG > 1) { |
||||||
2573 | error_log( |
||||||
2574 | 'New LP - OR was found but only one elem present !?', |
||||||
2575 | 0 |
||||||
2576 | ); |
||||||
2577 | } |
||||||
2578 | if (isset($items[$refs_list[$list[0]]])) { |
||||||
2579 | $status = $items[$refs_list[$list[0]]]->get_status(true); |
||||||
2580 | $returnstatus = 'completed' == $status || 'passed' == $status; |
||||||
2581 | if (!$returnstatus && empty($this->prereq_alert)) { |
||||||
2582 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
2583 | } |
||||||
2584 | |||||||
2585 | return $returnstatus; |
||||||
2586 | } |
||||||
2587 | } |
||||||
2588 | } |
||||||
2589 | if (empty($this->prereq_alert)) { |
||||||
2590 | $this->prereq_alert = get_lang('This learning object cannot display because the course prerequisites are not completed. This happens when a course imposes that you follow it step by step or get a minimum score in tests before you reach the next steps.'); |
||||||
2591 | } |
||||||
2592 | |||||||
2593 | if (self::DEBUG > 1) { |
||||||
2594 | error_log( |
||||||
2595 | 'New LP - End of parse_prereq. Error code is now '.$this->prereq_alert, |
||||||
2596 | 0 |
||||||
2597 | ); |
||||||
2598 | } |
||||||
2599 | |||||||
2600 | return false; |
||||||
2601 | } |
||||||
2602 | |||||||
2603 | /** |
||||||
2604 | * Reinits all local values as the learnpath is restarted. |
||||||
2605 | * |
||||||
2606 | * @return bool True on success, false otherwise |
||||||
2607 | */ |
||||||
2608 | public function restart() |
||||||
2609 | { |
||||||
2610 | if (self::DEBUG > 0) { |
||||||
2611 | error_log('learnpathItem::restart()', 0); |
||||||
2612 | } |
||||||
2613 | $seriousGame = $this->get_seriousgame_mode(); |
||||||
0 ignored issues
–
show
The function
learnpathItem::get_seriousgame_mode() has been deprecated: seriousgame_mode seems not to be used
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||
2614 | //For serious game : We reuse same attempt_id |
||||||
2615 | if (1 == $seriousGame && 'sco' == $this->type) { |
||||||
2616 | // If this is a sco, Chamilo can't update the time without an |
||||||
2617 | // explicit scorm call |
||||||
2618 | $this->current_start_time = 0; |
||||||
2619 | $this->current_stop_time = 0; //Those 0 value have this effect |
||||||
2620 | $this->last_scorm_session_time = 0; |
||||||
2621 | $this->save(); |
||||||
2622 | |||||||
2623 | return true; |
||||||
2624 | } |
||||||
2625 | |||||||
2626 | $this->save(); |
||||||
2627 | |||||||
2628 | $allowed = $this->isRestartAllowed(); |
||||||
2629 | if (-1 === $allowed) { |
||||||
2630 | // Nothing allowed, do nothing. |
||||||
2631 | } elseif (1 === $allowed) { |
||||||
2632 | // Restart as new attempt is allowed, record a new attempt. |
||||||
2633 | $this->attempt_id = $this->attempt_id + 1; // Simply reuse the previous attempt_id. |
||||||
2634 | $this->current_score = 0; |
||||||
2635 | $this->current_start_time = 0; |
||||||
2636 | $this->current_stop_time = 0; |
||||||
2637 | $this->current_data = ''; |
||||||
2638 | $this->status = $this->possible_status[0]; |
||||||
2639 | $this->interactions_count = 0; |
||||||
2640 | $this->interactions = []; |
||||||
2641 | $this->objectives_count = 0; |
||||||
2642 | $this->objectives = []; |
||||||
2643 | $this->lesson_location = ''; |
||||||
2644 | if (TOOL_QUIZ != $this->type) { |
||||||
2645 | $this->write_to_db(); |
||||||
2646 | } |
||||||
2647 | } else { |
||||||
2648 | // Restart current element is allowed (because it's not finished yet), |
||||||
2649 | // reinit current. |
||||||
2650 | //$this->current_score = 0; |
||||||
2651 | $this->current_start_time = 0; |
||||||
2652 | $this->current_stop_time = 0; |
||||||
2653 | $this->interactions_count = $this->get_interactions_count(true); |
||||||
2654 | } |
||||||
2655 | |||||||
2656 | return true; |
||||||
2657 | } |
||||||
2658 | |||||||
2659 | /** |
||||||
2660 | * Saves data in the database. |
||||||
2661 | * |
||||||
2662 | * @param bool $from_outside Save from URL params (1) or from object attributes (0) |
||||||
2663 | * @param bool $prereqs_complete The results of a check on prerequisites for this item. |
||||||
2664 | * True if prerequisites are completed, false otherwise. Defaults to false. Only used if not sco or au |
||||||
2665 | * |
||||||
2666 | * @return bool True on success, false on failure |
||||||
2667 | */ |
||||||
2668 | public function save($from_outside = true, $prereqs_complete = false) |
||||||
2669 | { |
||||||
2670 | $debug = self::DEBUG; |
||||||
2671 | if ($debug) { |
||||||
2672 | error_log('learnpathItem::save()', 0); |
||||||
2673 | } |
||||||
2674 | // First check if parameters passed via GET can be saved here |
||||||
2675 | // in case it's a SCORM, we should get: |
||||||
2676 | if ('sco' === $this->type || 'au' === $this->type) { |
||||||
2677 | $status = $this->get_status(true); |
||||||
2678 | if (1 == $this->prevent_reinit && |
||||||
2679 | $status != $this->possible_status[0] && // not attempted |
||||||
2680 | $status != $this->possible_status[1] //incomplete |
||||||
2681 | ) { |
||||||
2682 | if ($debug) { |
||||||
2683 | error_log( |
||||||
2684 | 'learnpathItem::save() - save reinit blocked by setting', |
||||||
2685 | 0 |
||||||
2686 | ); |
||||||
2687 | } |
||||||
2688 | // Do nothing because the status has already been set. Don't allow it to change. |
||||||
2689 | // TODO: Check there isn't a special circumstance where this should be saved. |
||||||
2690 | } else { |
||||||
2691 | if ($debug) { |
||||||
2692 | error_log( |
||||||
2693 | 'learnpathItem::save() - SCORM save request received', |
||||||
2694 | 0 |
||||||
2695 | ); |
||||||
2696 | } |
||||||
2697 | |||||||
2698 | if ($from_outside) { |
||||||
2699 | if ($debug) { |
||||||
2700 | error_log( |
||||||
2701 | 'learnpathItem::save() - Getting item data from outside', |
||||||
2702 | 0 |
||||||
2703 | ); |
||||||
2704 | } |
||||||
2705 | foreach ($_GET as $param => $value) { |
||||||
2706 | switch ($param) { |
||||||
2707 | case 'score': |
||||||
2708 | $this->set_score($value); |
||||||
2709 | if ($debug) { |
||||||
2710 | error_log( |
||||||
2711 | 'learnpathItem::save() - setting score to '.$value, |
||||||
2712 | 0 |
||||||
2713 | ); |
||||||
2714 | } |
||||||
2715 | break; |
||||||
2716 | case 'max': |
||||||
2717 | $this->set_max_score($value); |
||||||
2718 | if ($debug) { |
||||||
2719 | error_log( |
||||||
2720 | 'learnpathItem::save() - setting view_max_score to '.$value, |
||||||
2721 | 0 |
||||||
2722 | ); |
||||||
2723 | } |
||||||
2724 | break; |
||||||
2725 | case 'min': |
||||||
2726 | $this->min_score = $value; |
||||||
2727 | if ($debug) { |
||||||
2728 | error_log( |
||||||
2729 | 'learnpathItem::save() - setting min_score to '.$value, |
||||||
2730 | 0 |
||||||
2731 | ); |
||||||
2732 | } |
||||||
2733 | break; |
||||||
2734 | case 'lesson_status': |
||||||
2735 | if (!empty($value)) { |
||||||
2736 | $this->set_status($value); |
||||||
2737 | if ($debug) { |
||||||
2738 | error_log( |
||||||
2739 | 'learnpathItem::save() - setting status to '.$value, |
||||||
2740 | 0 |
||||||
2741 | ); |
||||||
2742 | } |
||||||
2743 | } |
||||||
2744 | break; |
||||||
2745 | case 'time': |
||||||
2746 | $this->set_time($value); |
||||||
2747 | if ($debug) { |
||||||
2748 | error_log( |
||||||
2749 | 'learnpathItem::save() - setting time to '.$value, |
||||||
2750 | 0 |
||||||
2751 | ); |
||||||
2752 | } |
||||||
2753 | break; |
||||||
2754 | case 'suspend_data': |
||||||
2755 | $this->current_data = $value; |
||||||
2756 | if ($debug) { |
||||||
2757 | error_log( |
||||||
2758 | 'learnpathItem::save() - setting suspend_data to '.$value, |
||||||
2759 | 0 |
||||||
2760 | ); |
||||||
2761 | } |
||||||
2762 | break; |
||||||
2763 | case 'lesson_location': |
||||||
2764 | $this->set_lesson_location($value); |
||||||
2765 | if ($debug) { |
||||||
2766 | error_log( |
||||||
2767 | 'learnpathItem::save() - setting lesson_location to '.$value, |
||||||
2768 | 0 |
||||||
2769 | ); |
||||||
2770 | } |
||||||
2771 | break; |
||||||
2772 | case 'core_exit': |
||||||
2773 | $this->set_core_exit($value); |
||||||
2774 | if ($debug) { |
||||||
2775 | error_log( |
||||||
2776 | 'learnpathItem::save() - setting core_exit to '.$value, |
||||||
2777 | 0 |
||||||
2778 | ); |
||||||
2779 | } |
||||||
2780 | break; |
||||||
2781 | case 'interactions': |
||||||
2782 | break; |
||||||
2783 | case 'objectives': |
||||||
2784 | break; |
||||||
2785 | default: |
||||||
2786 | // Ignore. |
||||||
2787 | break; |
||||||
2788 | } |
||||||
2789 | } |
||||||
2790 | } else { |
||||||
2791 | // Do nothing, just let the local attributes be used. |
||||||
2792 | if ($debug) { |
||||||
2793 | error_log( |
||||||
2794 | 'learnpathItem::save() - Using inside item status', |
||||||
2795 | 0 |
||||||
2796 | ); |
||||||
2797 | } |
||||||
2798 | } |
||||||
2799 | } |
||||||
2800 | } else { |
||||||
2801 | // If not SCO, such messages should not be expected. |
||||||
2802 | $type = strtolower($this->type); |
||||||
2803 | if ($debug) { |
||||||
2804 | error_log("type: $type"); |
||||||
2805 | } |
||||||
2806 | |||||||
2807 | switch ($type) { |
||||||
2808 | case 'asset': |
||||||
2809 | if ($prereqs_complete) { |
||||||
2810 | $this->set_status($this->possible_status[2]); |
||||||
2811 | } |
||||||
2812 | break; |
||||||
2813 | case TOOL_HOTPOTATOES: |
||||||
2814 | break; |
||||||
2815 | case TOOL_QUIZ: |
||||||
2816 | return false; |
||||||
2817 | break; |
||||||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other ![]() |
|||||||
2818 | default: |
||||||
2819 | // For now, everything that is not sco and not asset is set to |
||||||
2820 | // completed when saved. |
||||||
2821 | if ($prereqs_complete) { |
||||||
2822 | $this->set_status($this->possible_status[2]); |
||||||
2823 | } |
||||||
2824 | break; |
||||||
2825 | } |
||||||
2826 | } |
||||||
2827 | |||||||
2828 | if ($debug) { |
||||||
2829 | error_log('End of learnpathItem::save() - Calling write_to_db() now'); |
||||||
2830 | } |
||||||
2831 | |||||||
2832 | return $this->write_to_db(); |
||||||
2833 | } |
||||||
2834 | |||||||
2835 | /** |
||||||
2836 | * Sets the number of attempt_id to a given value. |
||||||
2837 | * |
||||||
2838 | * @param int $num The given value to set attempt_id to |
||||||
2839 | * |
||||||
2840 | * @return bool TRUE on success, FALSE otherwise |
||||||
2841 | */ |
||||||
2842 | public function set_attempt_id($num) |
||||||
2843 | { |
||||||
2844 | if ($num == strval(intval($num)) && $num >= 0) { |
||||||
2845 | $this->attempt_id = $num; |
||||||
2846 | |||||||
2847 | return true; |
||||||
2848 | } |
||||||
2849 | |||||||
2850 | return false; |
||||||
2851 | } |
||||||
2852 | |||||||
2853 | /** |
||||||
2854 | * Sets the core_exit value to the one given. |
||||||
2855 | * |
||||||
2856 | * @return bool $value True (always) |
||||||
2857 | */ |
||||||
2858 | public function set_core_exit($value) |
||||||
2859 | { |
||||||
2860 | switch ($value) { |
||||||
2861 | case '': |
||||||
2862 | $this->core_exit = ''; |
||||||
2863 | break; |
||||||
2864 | case 'suspend': |
||||||
2865 | $this->core_exit = 'suspend'; |
||||||
2866 | break; |
||||||
2867 | default: |
||||||
2868 | $this->core_exit = 'none'; |
||||||
2869 | break; |
||||||
2870 | } |
||||||
2871 | |||||||
2872 | return true; |
||||||
2873 | } |
||||||
2874 | |||||||
2875 | /** |
||||||
2876 | * Sets the item's description. |
||||||
2877 | * |
||||||
2878 | * @param string $string Description |
||||||
2879 | */ |
||||||
2880 | public function set_description($string = '') |
||||||
2881 | { |
||||||
2882 | if (!empty($string)) { |
||||||
2883 | $this->description = $string; |
||||||
2884 | } |
||||||
2885 | } |
||||||
2886 | |||||||
2887 | /** |
||||||
2888 | * Sets the lesson_location value. |
||||||
2889 | * |
||||||
2890 | * @param string $location lesson_location as provided by the SCO |
||||||
2891 | * |
||||||
2892 | * @return bool True on success, false otherwise |
||||||
2893 | */ |
||||||
2894 | public function set_lesson_location($location) |
||||||
2895 | { |
||||||
2896 | if (isset($location)) { |
||||||
2897 | $this->lesson_location = $location; |
||||||
2898 | |||||||
2899 | return true; |
||||||
2900 | } |
||||||
2901 | |||||||
2902 | return false; |
||||||
2903 | } |
||||||
2904 | |||||||
2905 | /** |
||||||
2906 | * Sets the item's depth level in the LP tree (0 is at root). |
||||||
2907 | * |
||||||
2908 | * @param int $int Level |
||||||
2909 | */ |
||||||
2910 | public function set_level($int = 0) |
||||||
2911 | { |
||||||
2912 | $this->level = (int) $int; |
||||||
2913 | } |
||||||
2914 | |||||||
2915 | /** |
||||||
2916 | * Sets the lp_view id this item view is registered to. |
||||||
2917 | * |
||||||
2918 | * @param int $lp_view_id lp_view DB ID |
||||||
2919 | * |
||||||
2920 | * @todo //todo insert into lp_item_view if lp_view not exists |
||||||
2921 | */ |
||||||
2922 | public function set_lp_view(int $lp_view_id): bool |
||||||
2923 | { |
||||||
2924 | $lpItemId = $this->get_id(); |
||||||
2925 | |||||||
2926 | if (empty($lpItemId)) { |
||||||
2927 | return false; |
||||||
2928 | } |
||||||
2929 | |||||||
2930 | if (empty($lp_view_id)) { |
||||||
2931 | return false; |
||||||
2932 | } |
||||||
2933 | |||||||
2934 | if (self::DEBUG > 0) { |
||||||
2935 | error_log('learnpathItem::set_lp_view('.$lp_view_id.')', 0); |
||||||
2936 | } |
||||||
2937 | |||||||
2938 | $this->view_id = $lp_view_id; |
||||||
2939 | |||||||
2940 | $item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||||||
2941 | // Get the lp_item_view with the highest view_count. |
||||||
2942 | $sql = "SELECT * FROM $item_view_table |
||||||
2943 | WHERE |
||||||
2944 | lp_item_id = $lpItemId AND |
||||||
2945 | lp_view_id = $lp_view_id |
||||||
2946 | ORDER BY view_count DESC"; |
||||||
2947 | |||||||
2948 | if (self::DEBUG > 2) { |
||||||
2949 | error_log( |
||||||
2950 | 'learnpathItem::set_lp_view() - Querying lp_item_view: '.$sql, |
||||||
2951 | 0 |
||||||
2952 | ); |
||||||
2953 | } |
||||||
2954 | $res = Database::query($sql); |
||||||
2955 | if (Database::num_rows($res) > 0) { |
||||||
2956 | $row = Database::fetch_array($res); |
||||||
2957 | $this->db_item_view_id = $row['iid']; |
||||||
2958 | $this->attempt_id = $row['view_count']; |
||||||
2959 | $this->current_score = $row['score']; |
||||||
2960 | $this->current_data = $row['suspend_data']; |
||||||
2961 | $this->view_max_score = $row['max_score']; |
||||||
2962 | $this->status = $row['status']; |
||||||
2963 | $this->current_start_time = $row['start_time']; |
||||||
2964 | $this->current_stop_time = $this->current_start_time + $row['total_time']; |
||||||
2965 | $this->lesson_location = $row['lesson_location']; |
||||||
2966 | $this->core_exit = $row['core_exit']; |
||||||
2967 | |||||||
2968 | if (self::DEBUG > 2) { |
||||||
2969 | error_log( |
||||||
2970 | 'learnpathItem::set_lp_view() - Updated item object with database values', |
||||||
2971 | 0 |
||||||
2972 | ); |
||||||
2973 | } |
||||||
2974 | |||||||
2975 | // Now get the number of interactions for this little guy. |
||||||
2976 | $table = Database::get_course_table(TABLE_LP_IV_INTERACTION); |
||||||
2977 | $sql = "SELECT * FROM $table |
||||||
2978 | WHERE lp_iv_id = ".$this->db_item_view_id; |
||||||
2979 | |||||||
2980 | $res = Database::query($sql); |
||||||
2981 | if (false !== $res) { |
||||||
2982 | $this->interactions_count = Database::num_rows($res); |
||||||
2983 | } else { |
||||||
2984 | $this->interactions_count = 0; |
||||||
2985 | } |
||||||
2986 | // Now get the number of objectives for this little guy. |
||||||
2987 | $table = Database::get_course_table(TABLE_LP_IV_OBJECTIVE); |
||||||
2988 | $sql = "SELECT * FROM $table |
||||||
2989 | WHERE lp_iv_id = ".$this->db_item_view_id; |
||||||
2990 | |||||||
2991 | $this->objectives_count = 0; |
||||||
2992 | $res = Database::query($sql); |
||||||
2993 | if (false !== $res) { |
||||||
2994 | $this->objectives_count = Database::num_rows($res); |
||||||
2995 | } |
||||||
2996 | } |
||||||
2997 | |||||||
2998 | return true; |
||||||
2999 | } |
||||||
3000 | |||||||
3001 | /** |
||||||
3002 | * Sets the path. |
||||||
3003 | * |
||||||
3004 | * @param string $string Path |
||||||
3005 | */ |
||||||
3006 | public function set_path($string = '') |
||||||
3007 | { |
||||||
3008 | if (!empty($string)) { |
||||||
3009 | $this->path = $string; |
||||||
3010 | } |
||||||
3011 | } |
||||||
3012 | |||||||
3013 | /** |
||||||
3014 | * Sets the prevent_reinit attribute. |
||||||
3015 | * This is based on the LP value and is set at creation time for |
||||||
3016 | * each learnpathItem. It is a (bad?) way of avoiding |
||||||
3017 | * a reference to the LP when saving an item. |
||||||
3018 | * |
||||||
3019 | * @param int 1 for "prevent", 0 for "don't prevent" |
||||||
0 ignored issues
–
show
|
|||||||
3020 | * saving freshened values (new "not attempted" status etc) |
||||||
3021 | */ |
||||||
3022 | public function set_prevent_reinit($prevent) |
||||||
3023 | { |
||||||
3024 | $this->prevent_reinit = 0; |
||||||
3025 | if ($prevent) { |
||||||
3026 | $this->prevent_reinit = 1; |
||||||
3027 | } |
||||||
3028 | } |
||||||
3029 | |||||||
3030 | /** |
||||||
3031 | * Sets the score value. If the mastery_score is set and the score reaches |
||||||
3032 | * it, then set the status to 'passed'. |
||||||
3033 | * |
||||||
3034 | * @param float $score Score |
||||||
3035 | * |
||||||
3036 | * @return bool True on success, false otherwise |
||||||
3037 | */ |
||||||
3038 | public function set_score($score) |
||||||
3039 | { |
||||||
3040 | $debug = self::DEBUG; |
||||||
3041 | if ($debug > 0) { |
||||||
3042 | error_log('learnpathItem::set_score('.$score.')', 0); |
||||||
3043 | } |
||||||
3044 | if (($this->max_score <= 0 || $score <= $this->max_score) && ($score >= $this->min_score)) { |
||||||
3045 | $this->current_score = $score; |
||||||
3046 | $masteryScore = $this->get_mastery_score(); |
||||||
3047 | $current_status = $this->get_status(false); |
||||||
3048 | |||||||
3049 | // Fixes bug when SCORM doesn't send a mastery score even if they sent a score! |
||||||
3050 | if (-1 == $masteryScore) { |
||||||
3051 | $masteryScore = $this->max_score; |
||||||
3052 | } |
||||||
3053 | |||||||
3054 | if ($debug > 0) { |
||||||
3055 | error_log('get_mastery_score: '.$masteryScore); |
||||||
3056 | error_log('current_status: '.$current_status); |
||||||
3057 | error_log('current score : '.$this->current_score); |
||||||
3058 | } |
||||||
3059 | |||||||
3060 | // If mastery_score is set AND the current score reaches the mastery |
||||||
3061 | // score AND the current status is different from 'completed', then |
||||||
3062 | // set it to 'passed'. |
||||||
3063 | /* |
||||||
3064 | if ($master != -1 && $this->current_score >= $master && $current_status != $this->possible_status[2]) { |
||||||
3065 | if ($debug > 0) error_log('Status changed to: '.$this->possible_status[3]); |
||||||
3066 | $this->set_status($this->possible_status[3]); //passed |
||||||
3067 | } elseif ($master != -1 && $this->current_score < $master) { |
||||||
3068 | if ($debug > 0) error_log('Status changed to: '.$this->possible_status[4]); |
||||||
3069 | $this->set_status($this->possible_status[4]); //failed |
||||||
3070 | }*/ |
||||||
3071 | return true; |
||||||
3072 | } |
||||||
3073 | |||||||
3074 | return false; |
||||||
3075 | } |
||||||
3076 | |||||||
3077 | /** |
||||||
3078 | * Sets the maximum score for this item. |
||||||
3079 | * |
||||||
3080 | * @param int $score Maximum score - must be a decimal or an empty string |
||||||
3081 | * |
||||||
3082 | * @return bool True on success, false on error |
||||||
3083 | */ |
||||||
3084 | public function set_max_score($score) |
||||||
3085 | { |
||||||
3086 | if (is_int($score) || '' == $score) { |
||||||
3087 | $this->view_max_score = $score; |
||||||
3088 | |||||||
3089 | return true; |
||||||
3090 | } |
||||||
3091 | |||||||
3092 | return false; |
||||||
3093 | } |
||||||
3094 | |||||||
3095 | /** |
||||||
3096 | * Sets the status for this item. |
||||||
3097 | * |
||||||
3098 | * @param string $status Status - must be one of the values defined in $this->possible_status |
||||||
3099 | * (this affects the status setting) |
||||||
3100 | * |
||||||
3101 | * @return bool True on success, false on error |
||||||
3102 | */ |
||||||
3103 | public function set_status($status) |
||||||
3104 | { |
||||||
3105 | if (self::DEBUG) { |
||||||
3106 | error_log('learnpathItem::set_status('.$status.')'); |
||||||
3107 | } |
||||||
3108 | |||||||
3109 | $found = false; |
||||||
3110 | foreach ($this->possible_status as $possible) { |
||||||
3111 | if (preg_match('/^'.$possible.'$/i', $status)) { |
||||||
3112 | $found = true; |
||||||
3113 | } |
||||||
3114 | } |
||||||
3115 | |||||||
3116 | if ($found) { |
||||||
3117 | $this->status = $status; |
||||||
3118 | if (self::DEBUG) { |
||||||
3119 | error_log( |
||||||
3120 | 'learnpathItem::set_status() - '. |
||||||
3121 | 'Updated object status of item '.$this->db_id. |
||||||
3122 | ' to '.$this->status |
||||||
3123 | ); |
||||||
3124 | } |
||||||
3125 | |||||||
3126 | return true; |
||||||
3127 | } |
||||||
3128 | |||||||
3129 | if (self::DEBUG) { |
||||||
3130 | error_log('Setting status: '.$this->possible_status[0]); |
||||||
3131 | } |
||||||
3132 | $this->status = $this->possible_status[0]; |
||||||
3133 | |||||||
3134 | return false; |
||||||
3135 | } |
||||||
3136 | |||||||
3137 | /** |
||||||
3138 | * Set the (indexing) terms for this learnpath item. |
||||||
3139 | * |
||||||
3140 | * @param string $terms Terms, as a comma-split list |
||||||
3141 | * |
||||||
3142 | * @return bool Always return true |
||||||
3143 | */ |
||||||
3144 | public function set_terms($terms) |
||||||
3145 | { |
||||||
3146 | global $charset; |
||||||
3147 | $lp_item = Database::get_course_table(TABLE_LP_ITEM); |
||||||
3148 | $a_terms = preg_split('/,/', $terms); |
||||||
3149 | $i_terms = preg_split('/,/', $this->get_terms()); |
||||||
3150 | foreach ($i_terms as $term) { |
||||||
3151 | if (!in_array($term, $a_terms)) { |
||||||
3152 | array_push($a_terms, $term); |
||||||
3153 | } |
||||||
3154 | } |
||||||
3155 | $new_terms = $a_terms; |
||||||
3156 | $new_terms_string = implode(',', $new_terms); |
||||||
3157 | |||||||
3158 | // TODO: Validate csv string. |
||||||
3159 | $terms = Database::escape_string(api_htmlentities($new_terms_string, ENT_QUOTES)); |
||||||
3160 | $sql = "UPDATE $lp_item |
||||||
3161 | SET terms = '$terms' |
||||||
3162 | WHERE iid=".$this->get_id(); |
||||||
3163 | Database::query($sql); |
||||||
3164 | // Save it to search engine. |
||||||
3165 | if ('true' == api_get_setting('search_enabled')) { |
||||||
3166 | $di = new ChamiloIndexer(); |
||||||
3167 | $di->update_terms($this->get_search_did(), $new_terms, 'T'); |
||||||
3168 | } |
||||||
3169 | |||||||
3170 | return true; |
||||||
3171 | } |
||||||
3172 | |||||||
3173 | /** |
||||||
3174 | * Get the document ID from inside the text index database. |
||||||
3175 | * |
||||||
3176 | * @return int Search index database document ID |
||||||
3177 | */ |
||||||
3178 | public function get_search_did() |
||||||
3179 | { |
||||||
3180 | return $this->search_did; |
||||||
3181 | } |
||||||
3182 | |||||||
3183 | /** |
||||||
3184 | * Sets the item viewing time in a usable form, given that SCORM packages |
||||||
3185 | * often give it as 00:00:00.0000. |
||||||
3186 | * |
||||||
3187 | * @param string Time as given by SCORM |
||||||
3188 | * @param string $format |
||||||
3189 | */ |
||||||
3190 | public function set_time($scorm_time, $format = 'scorm') |
||||||
3191 | { |
||||||
3192 | $debug = self::DEBUG; |
||||||
3193 | if ($debug) { |
||||||
3194 | error_log("learnpathItem::set_time($scorm_time, $format)"); |
||||||
3195 | error_log("this->type: ".$this->type); |
||||||
3196 | error_log("this->current_start_time: ".$this->current_start_time); |
||||||
3197 | } |
||||||
3198 | |||||||
3199 | if ('0' == $scorm_time && |
||||||
3200 | 'sco' !== $this->type && |
||||||
3201 | 0 != $this->current_start_time |
||||||
3202 | ) { |
||||||
3203 | $myTime = time() - $this->current_start_time; |
||||||
3204 | if ($myTime > 0) { |
||||||
3205 | $this->update_time($myTime); |
||||||
3206 | if ($debug) { |
||||||
3207 | error_log('found asset - set time to '.$myTime); |
||||||
3208 | } |
||||||
3209 | } else { |
||||||
3210 | if ($debug) { |
||||||
3211 | error_log('Time not set'); |
||||||
3212 | } |
||||||
3213 | } |
||||||
3214 | } else { |
||||||
3215 | switch ($format) { |
||||||
3216 | case 'scorm': |
||||||
3217 | $res = []; |
||||||
3218 | if (preg_match( |
||||||
3219 | '/^(\d{1,4}):(\d{2}):(\d{2})(\.\d{1,4})?/', |
||||||
3220 | $scorm_time, |
||||||
3221 | $res |
||||||
3222 | ) |
||||||
3223 | ) { |
||||||
3224 | $hour = $res[1]; |
||||||
3225 | $min = $res[2]; |
||||||
3226 | $sec = $res[3]; |
||||||
3227 | // Getting total number of seconds spent. |
||||||
3228 | $totalSec = $hour * 3600 + $min * 60 + $sec; |
||||||
3229 | if ($debug) { |
||||||
3230 | error_log("totalSec : $totalSec"); |
||||||
3231 | error_log("Now calling to scorm_update_time()"); |
||||||
3232 | } |
||||||
3233 | $this->scorm_update_time($totalSec); |
||||||
3234 | } |
||||||
3235 | break; |
||||||
3236 | case 'int': |
||||||
3237 | if ($debug) { |
||||||
3238 | error_log("scorm_time = $scorm_time"); |
||||||
3239 | error_log("Now calling to scorm_update_time()"); |
||||||
3240 | } |
||||||
3241 | $this->scorm_update_time($scorm_time); |
||||||
3242 | break; |
||||||
3243 | } |
||||||
3244 | } |
||||||
3245 | } |
||||||
3246 | |||||||
3247 | /** |
||||||
3248 | * Sets the item's title. |
||||||
3249 | * |
||||||
3250 | * @param string $string Title |
||||||
3251 | */ |
||||||
3252 | public function set_title($string = '') |
||||||
3253 | { |
||||||
3254 | if (!empty($string)) { |
||||||
3255 | $this->title = $string; |
||||||
3256 | } |
||||||
3257 | } |
||||||
3258 | |||||||
3259 | /** |
||||||
3260 | * Sets the item's type. |
||||||
3261 | * |
||||||
3262 | * @param string $string Type |
||||||
3263 | */ |
||||||
3264 | public function set_type($string = '') |
||||||
3265 | { |
||||||
3266 | if (!empty($string)) { |
||||||
3267 | $this->type = $string; |
||||||
3268 | } |
||||||
3269 | } |
||||||
3270 | |||||||
3271 | /** |
||||||
3272 | * Checks if the current status is part of the list of status given. |
||||||
3273 | * |
||||||
3274 | * @param array $list An array of status to check for. |
||||||
3275 | * If the current status is one of the strings, return true |
||||||
3276 | * |
||||||
3277 | * @return bool True if the status was one of the given strings, |
||||||
3278 | * false otherwise |
||||||
3279 | */ |
||||||
3280 | public function status_is($list = []) |
||||||
3281 | { |
||||||
3282 | if (self::DEBUG > 1) { |
||||||
3283 | error_log( |
||||||
3284 | 'learnpathItem::status_is('.print_r( |
||||||
0 ignored issues
–
show
Are you sure
print_r($list, true) of type string|true can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
3285 | $list, |
||||||
3286 | true |
||||||
3287 | ).') on item '.$this->db_id, |
||||||
3288 | 0 |
||||||
3289 | ); |
||||||
3290 | } |
||||||
3291 | $currentStatus = $this->get_status(true); |
||||||
3292 | if (empty($currentStatus)) { |
||||||
3293 | return false; |
||||||
3294 | } |
||||||
3295 | $found = false; |
||||||
3296 | foreach ($list as $status) { |
||||||
3297 | if (preg_match('/^'.$status.'$/i', $currentStatus)) { |
||||||
3298 | if (self::DEBUG > 2) { |
||||||
3299 | error_log( |
||||||
3300 | 'New LP - learnpathItem::status_is() - Found status '. |
||||||
3301 | $status.' corresponding to current status', |
||||||
3302 | 0 |
||||||
3303 | ); |
||||||
3304 | } |
||||||
3305 | $found = true; |
||||||
3306 | |||||||
3307 | return $found; |
||||||
3308 | } |
||||||
3309 | } |
||||||
3310 | if (self::DEBUG > 2) { |
||||||
3311 | error_log( |
||||||
3312 | 'New LP - learnpathItem::status_is() - Status '. |
||||||
3313 | $currentStatus.' did not match request', |
||||||
3314 | 0 |
||||||
3315 | ); |
||||||
3316 | } |
||||||
3317 | |||||||
3318 | return $found; |
||||||
3319 | } |
||||||
3320 | |||||||
3321 | /** |
||||||
3322 | * Updates the time info according to the given session_time. |
||||||
3323 | * |
||||||
3324 | * @param int $totalSec Time in seconds |
||||||
3325 | */ |
||||||
3326 | public function update_time($totalSec = 0) |
||||||
3327 | { |
||||||
3328 | if (self::DEBUG > 0) { |
||||||
3329 | error_log('learnpathItem::update_time('.$totalSec.')'); |
||||||
3330 | } |
||||||
3331 | if ($totalSec >= 0) { |
||||||
3332 | // Getting start time from finish time. The only problem in the calculation is it might be |
||||||
3333 | // modified by the scripts processing time. |
||||||
3334 | $now = time(); |
||||||
3335 | $start = $now - $totalSec; |
||||||
3336 | $this->current_start_time = $start; |
||||||
3337 | $this->current_stop_time = $now; |
||||||
3338 | } |
||||||
3339 | } |
||||||
3340 | |||||||
3341 | /** |
||||||
3342 | * Special scorm update time function. This function will update time |
||||||
3343 | * directly into db for scorm objects. |
||||||
3344 | * |
||||||
3345 | * @param int $total_sec Total number of seconds |
||||||
3346 | */ |
||||||
3347 | public function scorm_update_time($total_sec = 0) |
||||||
3348 | { |
||||||
3349 | $debug = self::DEBUG; |
||||||
3350 | if ($debug) { |
||||||
3351 | error_log('learnpathItem::scorm_update_time()'); |
||||||
3352 | error_log("total_sec: $total_sec"); |
||||||
3353 | } |
||||||
3354 | |||||||
3355 | // Step 1 : get actual total time stored in db |
||||||
3356 | $item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||||||
3357 | |||||||
3358 | $sql = 'SELECT total_time, status |
||||||
3359 | FROM '.$item_view_table.' |
||||||
3360 | WHERE |
||||||
3361 | lp_item_id = "'.$this->db_id.'" AND |
||||||
3362 | lp_view_id = "'.$this->view_id.'" AND |
||||||
3363 | view_count = "'.$this->get_attempt_id().'"'; |
||||||
3364 | $result = Database::query($sql); |
||||||
3365 | $row = Database::fetch_array($result); |
||||||
3366 | |||||||
3367 | if (!isset($row['total_time'])) { |
||||||
3368 | $total_time = 0; |
||||||
3369 | } else { |
||||||
3370 | $total_time = $row['total_time']; |
||||||
3371 | } |
||||||
3372 | if ($debug) { |
||||||
3373 | error_log("Original total_time: $total_time"); |
||||||
3374 | } |
||||||
3375 | |||||||
3376 | $lp_table = Database::get_course_table(TABLE_LP_MAIN); |
||||||
3377 | $lp_id = (int) $this->lp_id; |
||||||
3378 | $sql = "SELECT * FROM $lp_table WHERE iid = $lp_id"; |
||||||
3379 | $res = Database::query($sql); |
||||||
3380 | $accumulateScormTime = 'false'; |
||||||
3381 | if (Database::num_rows($res) > 0) { |
||||||
3382 | $row = Database::fetch_assoc($res); |
||||||
3383 | $accumulateScormTime = $row['accumulate_scorm_time']; |
||||||
3384 | } |
||||||
3385 | |||||||
3386 | // Step 2.1 : if normal mode total_time = total_time + total_sec |
||||||
3387 | if ('sco' === $this->type && 0 != $accumulateScormTime) { |
||||||
3388 | if ($debug) { |
||||||
3389 | error_log("accumulateScormTime is on. total_time modified: $total_time + $total_sec"); |
||||||
3390 | } |
||||||
3391 | $total_time += $total_sec; |
||||||
3392 | } else { |
||||||
3393 | // Step 2.2 : if not cumulative mode total_time = total_time - last_update + total_sec |
||||||
3394 | $total_sec = $this->fixAbusiveTime($total_sec); |
||||||
3395 | if ($debug) { |
||||||
3396 | error_log("after fix abusive: $total_sec"); |
||||||
3397 | error_log("total_time: $total_time"); |
||||||
3398 | error_log("this->last_scorm_session_time: ".$this->last_scorm_session_time); |
||||||
3399 | } |
||||||
3400 | |||||||
3401 | $total_time = $total_time - $this->last_scorm_session_time + $total_sec; |
||||||
3402 | $this->last_scorm_session_time = $total_sec; |
||||||
3403 | |||||||
3404 | if ($total_time < 0) { |
||||||
3405 | $total_time = $total_sec; |
||||||
3406 | } |
||||||
3407 | } |
||||||
3408 | |||||||
3409 | if ($debug) { |
||||||
3410 | error_log("accumulate_scorm_time: $accumulateScormTime"); |
||||||
3411 | error_log("total_time modified: $total_time"); |
||||||
3412 | } |
||||||
3413 | |||||||
3414 | // Step 3 update db only if status != completed, passed, browsed or seriousgamemode not activated |
||||||
3415 | // @todo complete |
||||||
3416 | $case_completed = [ |
||||||
3417 | 'completed', |
||||||
3418 | 'passed', |
||||||
3419 | 'browsed', |
||||||
3420 | 'failed', |
||||||
3421 | ]; |
||||||
3422 | |||||||
3423 | if (1 != $this->seriousgame_mode || |
||||||
3424 | !in_array($row['status'], $case_completed) |
||||||
3425 | ) { |
||||||
3426 | $sql = "UPDATE $item_view_table |
||||||
3427 | SET total_time = '$total_time' |
||||||
3428 | WHERE |
||||||
3429 | lp_item_id = {$this->db_id} AND |
||||||
3430 | lp_view_id = {$this->view_id} AND |
||||||
3431 | view_count = {$this->get_attempt_id()}"; |
||||||
3432 | if ($debug) { |
||||||
3433 | error_log('-------------total_time updated ------------------------'); |
||||||
3434 | error_log($sql); |
||||||
3435 | error_log('-------------------------------------'); |
||||||
3436 | } |
||||||
3437 | Database::query($sql); |
||||||
3438 | } |
||||||
3439 | } |
||||||
3440 | |||||||
3441 | /** |
||||||
3442 | * Write objectives to DB. This method is separate from write_to_db() because otherwise |
||||||
3443 | * objectives are lost as a side effect to AJAX and session concurrent access. |
||||||
3444 | * |
||||||
3445 | * @return bool True or false on error |
||||||
3446 | */ |
||||||
3447 | public function write_objectives_to_db() |
||||||
3448 | { |
||||||
3449 | if (self::DEBUG > 0) { |
||||||
3450 | error_log('learnpathItem::write_objectives_to_db()', 0); |
||||||
3451 | } |
||||||
3452 | if (api_is_invitee()) { |
||||||
3453 | // If the user is an invitee, we don't write anything to DB |
||||||
3454 | return true; |
||||||
3455 | } |
||||||
3456 | $courseId = api_get_course_int_id(); |
||||||
3457 | if (is_array($this->objectives) && count($this->objectives) > 0) { |
||||||
3458 | // Save objectives. |
||||||
3459 | $tbl = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||||||
3460 | $sql = "SELECT iid |
||||||
3461 | FROM $tbl |
||||||
3462 | WHERE |
||||||
3463 | lp_item_id = ".$this->db_id." AND |
||||||
3464 | lp_view_id = ".$this->view_id." AND |
||||||
3465 | view_count = ".$this->attempt_id; |
||||||
3466 | $res = Database::query($sql); |
||||||
3467 | if (Database::num_rows($res) > 0) { |
||||||
3468 | $row = Database::fetch_array($res); |
||||||
3469 | $lp_iv_id = $row[0]; |
||||||
3470 | if (self::DEBUG > 2) { |
||||||
3471 | error_log( |
||||||
3472 | 'learnpathItem::write_to_db() - Got item_view_id '. |
||||||
3473 | $lp_iv_id.', now checking objectives ', |
||||||
3474 | 0 |
||||||
3475 | ); |
||||||
3476 | } |
||||||
3477 | foreach ($this->objectives as $index => $objective) { |
||||||
3478 | $iva_table = Database::get_course_table( |
||||||
3479 | TABLE_LP_IV_OBJECTIVE |
||||||
3480 | ); |
||||||
3481 | $iva_sql = "SELECT iid FROM $iva_table |
||||||
3482 | WHERE |
||||||
3483 | c_id = $courseId AND |
||||||
3484 | lp_iv_id = $lp_iv_id AND |
||||||
3485 | objective_id = '".Database::escape_string($objective[0])."'"; |
||||||
3486 | $iva_res = Database::query($iva_sql); |
||||||
3487 | // id(0), type(1), time(2), weighting(3), |
||||||
3488 | // correct_responses(4), student_response(5), |
||||||
3489 | // result(6), latency(7) |
||||||
3490 | if (Database::num_rows($iva_res) > 0) { |
||||||
3491 | // Update (or don't). |
||||||
3492 | $iva_row = Database::fetch_array($iva_res); |
||||||
3493 | $iva_id = $iva_row[0]; |
||||||
3494 | $ivau_sql = "UPDATE $iva_table ". |
||||||
3495 | "SET objective_id = '".Database::escape_string($objective[0])."',". |
||||||
3496 | "status = '".Database::escape_string($objective[1])."',". |
||||||
3497 | "score_raw = '".Database::escape_string($objective[2])."',". |
||||||
3498 | "score_min = '".Database::escape_string($objective[4])."',". |
||||||
3499 | "score_max = '".Database::escape_string($objective[3])."' ". |
||||||
3500 | "WHERE c_id = $courseId AND iid = $iva_id"; |
||||||
3501 | Database::query($ivau_sql); |
||||||
3502 | } else { |
||||||
3503 | // Insert new one. |
||||||
3504 | $params = [ |
||||||
3505 | 'c_id' => $courseId, |
||||||
3506 | 'lp_iv_id' => $lp_iv_id, |
||||||
3507 | 'order_id' => $index, |
||||||
3508 | 'objective_id' => $objective[0], |
||||||
3509 | 'status' => $objective[1], |
||||||
3510 | 'score_raw' => $objective[2], |
||||||
3511 | 'score_min' => $objective[4], |
||||||
3512 | 'score_max' => $objective[3], |
||||||
3513 | ]; |
||||||
3514 | |||||||
3515 | $insertId = Database::insert($iva_table, $params); |
||||||
3516 | if ($insertId) { |
||||||
0 ignored issues
–
show
The expression
$insertId of type false|integer is loosely compared to true ; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
![]() |
|||||||
3517 | $sql = "UPDATE $iva_table SET id = iid |
||||||
3518 | WHERE iid = $insertId"; |
||||||
3519 | Database::query($sql); |
||||||
3520 | } |
||||||
3521 | } |
||||||
3522 | } |
||||||
3523 | } |
||||||
3524 | } |
||||||
3525 | } |
||||||
3526 | |||||||
3527 | /** |
||||||
3528 | * Writes the current data to the database. |
||||||
3529 | * |
||||||
3530 | * @return bool Query result |
||||||
3531 | */ |
||||||
3532 | public function write_to_db() |
||||||
3533 | { |
||||||
3534 | $debug = self::DEBUG; |
||||||
3535 | if ($debug) { |
||||||
3536 | error_log('------------------------'); |
||||||
3537 | error_log('learnpathItem::write_to_db()'); |
||||||
3538 | } |
||||||
3539 | |||||||
3540 | // Check the session visibility. |
||||||
3541 | if (!api_is_allowed_to_session_edit()) { |
||||||
3542 | if ($debug) { |
||||||
3543 | error_log('return false api_is_allowed_to_session_edit'); |
||||||
3544 | } |
||||||
3545 | |||||||
3546 | return false; |
||||||
3547 | } |
||||||
3548 | if (api_is_invitee()) { |
||||||
3549 | if ($debug) { |
||||||
3550 | error_log('api_is_invitee'); |
||||||
3551 | } |
||||||
3552 | // If the user is an invitee, we don't write anything to DB |
||||||
3553 | return true; |
||||||
3554 | } |
||||||
3555 | |||||||
3556 | $courseId = api_get_course_int_id(); |
||||||
3557 | $mode = $this->get_lesson_mode(); |
||||||
3558 | $credit = $this->get_credit(); |
||||||
3559 | $total_time = ' '; |
||||||
3560 | $my_status = ' '; |
||||||
3561 | $item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||||||
3562 | $sql = 'SELECT status, total_time |
||||||
3563 | FROM '.$item_view_table.' |
||||||
3564 | WHERE |
||||||
3565 | lp_item_id="'.$this->db_id.'" AND |
||||||
3566 | lp_view_id="'.$this->view_id.'" AND |
||||||
3567 | view_count="'.$this->get_attempt_id().'" '; |
||||||
3568 | $rs_verified = Database::query($sql); |
||||||
3569 | $row_verified = Database::fetch_array($rs_verified); |
||||||
3570 | $my_case_completed = [ |
||||||
3571 | 'completed', |
||||||
3572 | 'passed', |
||||||
3573 | 'browsed', |
||||||
3574 | 'failed', |
||||||
3575 | ]; |
||||||
3576 | |||||||
3577 | $save = true; |
||||||
3578 | |||||||
3579 | if (!empty($row_verified)) { |
||||||
3580 | $oldTotalTime = $row_verified['total_time']; |
||||||
3581 | $this->oldTotalTime = $oldTotalTime; |
||||||
3582 | if (isset($row_verified['status'])) { |
||||||
3583 | if (in_array($row_verified['status'], $my_case_completed)) { |
||||||
3584 | $save = false; |
||||||
3585 | } |
||||||
3586 | } |
||||||
3587 | } |
||||||
3588 | |||||||
3589 | if (((false === $save && 'sco' === $this->type) || |
||||||
0 ignored issues
–
show
|
|||||||
3590 | ('sco' === $this->type && ('no-credit' === $credit || 'review' === $mode || 'browse' === $mode))) && |
||||||
3591 | (1 != $this->seriousgame_mode && 'sco' === $this->type) |
||||||
3592 | ) { |
||||||
3593 | if ($debug) { |
||||||
3594 | error_log( |
||||||
3595 | "This info shouldn't be saved as the credit or lesson mode info prevent it" |
||||||
3596 | ); |
||||||
3597 | error_log( |
||||||
3598 | 'learnpathItem::write_to_db() - credit('.$credit.') or'. |
||||||
3599 | ' lesson_mode('.$mode.') prevent recording!', |
||||||
3600 | 0 |
||||||
3601 | ); |
||||||
3602 | } |
||||||
3603 | } else { |
||||||
3604 | // Check the row exists. |
||||||
3605 | $inserted = false; |
||||||
3606 | // This a special case for multiple attempts and Chamilo exercises. |
||||||
3607 | if ('quiz' === $this->type && |
||||||
3608 | 0 == $this->get_prevent_reinit() && |
||||||
3609 | 'completed' === $this->get_status() |
||||||
3610 | ) { |
||||||
3611 | // We force the item to be restarted. |
||||||
3612 | $this->restart(); |
||||||
3613 | $params = [ |
||||||
3614 | "c_id" => $courseId, |
||||||
3615 | "total_time" => $this->get_total_time(), |
||||||
3616 | "start_time" => $this->current_start_time, |
||||||
3617 | "score" => $this->get_score(), |
||||||
3618 | "status" => $this->get_status(false), |
||||||
3619 | "max_score" => $this->get_max(), |
||||||
3620 | "lp_item_id" => $this->db_id, |
||||||
3621 | "lp_view_id" => $this->view_id, |
||||||
3622 | "view_count" => $this->get_attempt_id(), |
||||||
3623 | "suspend_data" => $this->current_data, |
||||||
3624 | //"max_time_allowed" => , |
||||||
3625 | "lesson_location" => $this->lesson_location, |
||||||
3626 | ]; |
||||||
3627 | if ($debug) { |
||||||
3628 | error_log('learnpathItem::write_to_db() - Inserting into item_view forced: '.print_r($params, 1)); |
||||||
0 ignored issues
–
show
Are you sure
print_r($params, 1) of type string|true can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
3629 | } |
||||||
3630 | $this->db_item_view_id = Database::insert($item_view_table, $params); |
||||||
3631 | if ($this->db_item_view_id) { |
||||||
0 ignored issues
–
show
The expression
$this->db_item_view_id of type false|integer is loosely compared to true ; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
![]() |
|||||||
3632 | $inserted = true; |
||||||
3633 | } |
||||||
3634 | } |
||||||
3635 | |||||||
3636 | $sql = "SELECT * FROM $item_view_table |
||||||
3637 | WHERE |
||||||
3638 | lp_item_id = ".$this->db_id." AND |
||||||
3639 | lp_view_id = ".$this->view_id." AND |
||||||
3640 | view_count = ".$this->get_attempt_id(); |
||||||
3641 | if ($debug) { |
||||||
3642 | error_log('learnpathItem::write_to_db() - Querying item_view: '.$sql); |
||||||
3643 | } |
||||||
3644 | |||||||
3645 | $check_res = Database::query($sql); |
||||||
3646 | // Depending on what we want (really), we'll update or insert a new row |
||||||
3647 | // now save into DB. |
||||||
3648 | if (!$inserted && Database::num_rows($check_res) < 1) { |
||||||
3649 | $params = [ |
||||||
3650 | "c_id" => $courseId, |
||||||
3651 | "total_time" => $this->get_total_time(), |
||||||
3652 | "start_time" => $this->current_start_time, |
||||||
3653 | "score" => $this->get_score(), |
||||||
3654 | "status" => $this->get_status(false), |
||||||
3655 | "max_score" => $this->get_max(), |
||||||
3656 | "lp_item_id" => $this->db_id, |
||||||
3657 | "lp_view_id" => $this->view_id, |
||||||
3658 | "view_count" => $this->get_attempt_id(), |
||||||
3659 | "suspend_data" => $this->current_data, |
||||||
3660 | //"max_time_allowed" => ,$this->get_max_time_allowed() |
||||||
3661 | "lesson_location" => $this->lesson_location, |
||||||
3662 | ]; |
||||||
3663 | |||||||
3664 | if ($debug) { |
||||||
3665 | error_log( |
||||||
3666 | 'learnpathItem::write_to_db() - Inserting into item_view forced: '.print_r($params, 1), |
||||||
3667 | 0 |
||||||
3668 | ); |
||||||
3669 | } |
||||||
3670 | $this->db_item_view_id = Database::insert($item_view_table, $params); |
||||||
3671 | } else { |
||||||
3672 | if ('hotpotatoes' === $this->type) { |
||||||
3673 | $params = [ |
||||||
3674 | 'total_time' => $this->get_total_time(), |
||||||
3675 | 'start_time' => $this->get_current_start_time(), |
||||||
3676 | 'score' => $this->get_score(), |
||||||
3677 | 'status' => $this->get_status(false), |
||||||
3678 | 'max_score' => $this->get_max(), |
||||||
3679 | 'suspend_data' => $this->current_data, |
||||||
3680 | 'lesson_location' => $this->lesson_location, |
||||||
3681 | ]; |
||||||
3682 | $where = [ |
||||||
3683 | 'c_id = ? AND lp_item_id = ? AND lp_view_id = ? AND view_count = ?' => [ |
||||||
3684 | $courseId, |
||||||
3685 | $this->db_id, |
||||||
3686 | $this->view_id, |
||||||
3687 | $this->get_attempt_id(), |
||||||
3688 | ], |
||||||
3689 | ]; |
||||||
3690 | Database::update($item_view_table, $params, $where); |
||||||
3691 | } else { |
||||||
3692 | // For all other content types... |
||||||
3693 | if ('quiz' === $this->type) { |
||||||
3694 | $my_status = ' '; |
||||||
3695 | $total_time = ' '; |
||||||
3696 | if (!empty($_REQUEST['exeId'])) { |
||||||
3697 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||||||
3698 | $exeId = (int) $_REQUEST['exeId']; |
||||||
3699 | $sql = "SELECT exe_duration |
||||||
3700 | FROM $table |
||||||
3701 | WHERE exe_id = $exeId"; |
||||||
3702 | $res = Database::query($sql); |
||||||
3703 | $exeRow = Database::fetch_array($res); |
||||||
3704 | $duration = isset($exeRow['exe_duration']) ? (int) $exeRow['exe_duration'] : 0; |
||||||
3705 | $total_time = " total_time = ".$duration.", "; |
||||||
3706 | if ($debug) { |
||||||
3707 | error_log("quiz: $total_time"); |
||||||
3708 | } |
||||||
3709 | } |
||||||
3710 | } else { |
||||||
3711 | $my_type_lp = learnpath::get_type_static($this->lp_id); |
||||||
3712 | // This is a array containing values finished |
||||||
3713 | $case_completed = [ |
||||||
3714 | 'completed', |
||||||
3715 | 'passed', |
||||||
3716 | 'browsed', |
||||||
3717 | 'failed', |
||||||
3718 | ]; |
||||||
3719 | |||||||
3720 | // Is not multiple attempts |
||||||
3721 | if (1 == $this->seriousgame_mode && 'sco' === $this->type) { |
||||||
3722 | $total_time = " total_time = total_time +".$this->get_total_time().", "; |
||||||
3723 | $my_status = " status = '".$this->get_status(false)."' ,"; |
||||||
3724 | if ($debug) { |
||||||
3725 | error_log("seriousgame_mode time changed: $total_time"); |
||||||
3726 | } |
||||||
3727 | } elseif (1 == $this->get_prevent_reinit()) { |
||||||
3728 | // Process of status verified into data base. |
||||||
3729 | $sql = 'SELECT status FROM '.$item_view_table.' |
||||||
3730 | WHERE |
||||||
3731 | lp_item_id="'.$this->db_id.'" AND |
||||||
3732 | lp_view_id="'.$this->view_id.'" AND |
||||||
3733 | view_count="'.$this->get_attempt_id().'" |
||||||
3734 | '; |
||||||
3735 | $rs_verified = Database::query($sql); |
||||||
3736 | $row_verified = Database::fetch_array($rs_verified); |
||||||
3737 | |||||||
3738 | // Get type lp: 1=lp dokeos and 2=scorm. |
||||||
3739 | // If not is completed or passed or browsed and learning path is scorm. |
||||||
3740 | if (!in_array($this->get_status(false), $case_completed) && |
||||||
3741 | 2 == $my_type_lp |
||||||
3742 | ) { |
||||||
3743 | $total_time = " total_time = total_time +".$this->get_total_time().", "; |
||||||
3744 | $my_status = " status = '".$this->get_status(false)."' ,"; |
||||||
3745 | if ($debug) { |
||||||
3746 | error_log("get_prevent_reinit = 1 time changed: $total_time"); |
||||||
3747 | } |
||||||
3748 | } else { |
||||||
3749 | // Verified into database. |
||||||
3750 | if (!in_array($row_verified['status'], $case_completed) && |
||||||
3751 | 2 == $my_type_lp |
||||||
3752 | ) { |
||||||
3753 | $total_time = " total_time = total_time +".$this->get_total_time().", "; |
||||||
3754 | $my_status = " status = '".$this->get_status(false)."' ,"; |
||||||
3755 | if ($debug) { |
||||||
3756 | error_log("total_time time changed case 1: $total_time"); |
||||||
3757 | } |
||||||
3758 | } elseif (in_array($row_verified['status'], $case_completed) && |
||||||
3759 | 2 == $my_type_lp && 'sco' != $this->type |
||||||
3760 | ) { |
||||||
3761 | $total_time = " total_time = total_time +".$this->get_total_time().", "; |
||||||
3762 | $my_status = " status = '".$this->get_status(false)."' ,"; |
||||||
3763 | if ($debug) { |
||||||
3764 | error_log("total_time time changed case 2: $total_time"); |
||||||
3765 | } |
||||||
3766 | } else { |
||||||
3767 | if ((3 == $my_type_lp && 'au' == $this->type) || |
||||||
3768 | (1 == $my_type_lp && 'dir' != $this->type)) { |
||||||
3769 | // Is AICC or Chamilo LP |
||||||
3770 | $total_time = " total_time = total_time + ".$this->get_total_time().", "; |
||||||
3771 | $my_status = " status = '".$this->get_status(false)."' ,"; |
||||||
3772 | if ($debug) { |
||||||
3773 | error_log("total_time time changed case 3: $total_time"); |
||||||
3774 | } |
||||||
3775 | } |
||||||
3776 | } |
||||||
3777 | } |
||||||
3778 | } else { |
||||||
3779 | // Multiple attempts are allowed. |
||||||
3780 | if (in_array($this->get_status(false), $case_completed) && 2 == $my_type_lp) { |
||||||
3781 | // Reset zero new attempt ? |
||||||
3782 | $my_status = " status = '".$this->get_status(false)."' ,"; |
||||||
3783 | if ($debug) { |
||||||
3784 | error_log("total_time time changed Multiple attempt case 1: $total_time"); |
||||||
3785 | } |
||||||
3786 | } elseif (!in_array($this->get_status(false), $case_completed) && 2 == $my_type_lp) { |
||||||
3787 | $total_time = " total_time = ".$this->get_total_time().", "; |
||||||
3788 | $my_status = " status = '".$this->get_status(false)."' ,"; |
||||||
3789 | if ($debug) { |
||||||
3790 | error_log("total_time time changed Multiple attempt case 2: $total_time"); |
||||||
3791 | } |
||||||
3792 | } else { |
||||||
3793 | // It is chamilo LP. |
||||||
3794 | $total_time = " total_time = total_time +".$this->get_total_time().", "; |
||||||
3795 | $my_status = " status = '".$this->get_status(false)."' ,"; |
||||||
3796 | if ($debug) { |
||||||
3797 | error_log("total_time time changed Multiple attempt case 3: $total_time"); |
||||||
3798 | } |
||||||
3799 | } |
||||||
3800 | |||||||
3801 | // This code line fixes the problem of wrong status. |
||||||
3802 | if (2 == $my_type_lp) { |
||||||
3803 | // Verify current status in multiples attempts. |
||||||
3804 | $sql = 'SELECT status FROM '.$item_view_table.' |
||||||
3805 | WHERE |
||||||
3806 | c_id = '.$courseId.' AND |
||||||
3807 | lp_item_id="'.$this->db_id.'" AND |
||||||
3808 | lp_view_id="'.$this->view_id.'" AND |
||||||
3809 | view_count="'.$this->get_attempt_id().'" '; |
||||||
3810 | $rs_status = Database::query($sql); |
||||||
3811 | $current_status = Database::result($rs_status, 0, 'status'); |
||||||
3812 | if (in_array($current_status, $case_completed)) { |
||||||
3813 | $my_status = ''; |
||||||
3814 | $total_time = ''; |
||||||
3815 | } else { |
||||||
3816 | $total_time = " total_time = total_time + ".$this->get_total_time().", "; |
||||||
3817 | } |
||||||
3818 | |||||||
3819 | if ($debug) { |
||||||
3820 | error_log("total_time time my_type_lp: $total_time"); |
||||||
3821 | } |
||||||
3822 | } |
||||||
3823 | } |
||||||
3824 | } |
||||||
3825 | |||||||
3826 | if ('sco' === $this->type) { |
||||||
3827 | //IF scorm scorm_update_time has already updated total_time in db |
||||||
3828 | //" . //start_time = ".$this->get_current_start_time().", " . //scorm_init_time does it |
||||||
3829 | ////" max_time_allowed = '".$this->get_max_time_allowed()."'," . |
||||||
3830 | $sql = "UPDATE $item_view_table SET |
||||||
3831 | score = ".$this->get_score().", |
||||||
3832 | $my_status |
||||||
3833 | max_score = '".$this->get_max()."', |
||||||
3834 | suspend_data = '".Database::escape_string($this->current_data)."', |
||||||
3835 | lesson_location = '".$this->lesson_location."' |
||||||
3836 | WHERE |
||||||
3837 | lp_item_id = ".$this->db_id." AND |
||||||
3838 | lp_view_id = ".$this->view_id." AND |
||||||
3839 | view_count = ".$this->get_attempt_id(); |
||||||
3840 | } else { |
||||||
3841 | //" max_time_allowed = '".$this->get_max_time_allowed()."'," . |
||||||
3842 | $sql = "UPDATE $item_view_table SET |
||||||
3843 | $total_time |
||||||
3844 | start_time = ".$this->get_current_start_time().", |
||||||
3845 | score = ".$this->get_score().", |
||||||
3846 | $my_status |
||||||
3847 | max_score = '".$this->get_max()."', |
||||||
3848 | suspend_data = '".Database::escape_string($this->current_data)."', |
||||||
3849 | lesson_location = '".$this->lesson_location."' |
||||||
3850 | WHERE |
||||||
3851 | lp_item_id = ".$this->db_id." AND |
||||||
3852 | lp_view_id = ".$this->view_id." AND |
||||||
3853 | view_count = ".$this->get_attempt_id(); |
||||||
3854 | } |
||||||
3855 | $this->current_start_time = time(); |
||||||
3856 | } |
||||||
3857 | if ($debug) { |
||||||
3858 | error_log('-------------------------------------------'); |
||||||
3859 | error_log('learnpathItem::write_to_db() - Updating item_view:'); |
||||||
3860 | error_log($sql); |
||||||
3861 | error_log('-------------------------------------------'); |
||||||
3862 | } |
||||||
3863 | Database::query($sql); |
||||||
3864 | } |
||||||
3865 | |||||||
3866 | if (is_array($this->interactions) && |
||||||
3867 | count($this->interactions) > 0 |
||||||
3868 | ) { |
||||||
3869 | $sql = "SELECT iid FROM $item_view_table |
||||||
3870 | WHERE |
||||||
3871 | lp_item_id = ".$this->db_id." AND |
||||||
3872 | lp_view_id = ".$this->view_id." AND |
||||||
3873 | view_count = ".$this->get_attempt_id(); |
||||||
3874 | $res = Database::query($sql); |
||||||
3875 | if (Database::num_rows($res) > 0) { |
||||||
3876 | $row = Database::fetch_array($res); |
||||||
3877 | $lp_iv_id = $row[0]; |
||||||
3878 | if ($debug) { |
||||||
3879 | error_log( |
||||||
3880 | 'learnpathItem::write_to_db() - Got item_view_id '. |
||||||
3881 | $lp_iv_id.', now checking interactions ', |
||||||
3882 | 0 |
||||||
3883 | ); |
||||||
3884 | } |
||||||
3885 | foreach ($this->interactions as $index => $interaction) { |
||||||
3886 | $correct_resp = ''; |
||||||
3887 | if (is_array($interaction[4]) && !empty($interaction[4][0])) { |
||||||
3888 | foreach ($interaction[4] as $resp) { |
||||||
3889 | $correct_resp .= $resp.','; |
||||||
3890 | } |
||||||
3891 | $correct_resp = substr( |
||||||
3892 | $correct_resp, |
||||||
3893 | 0, |
||||||
3894 | strlen($correct_resp) - 1 |
||||||
3895 | ); |
||||||
3896 | } |
||||||
3897 | $iva_table = Database::get_course_table( |
||||||
3898 | TABLE_LP_IV_INTERACTION |
||||||
3899 | ); |
||||||
3900 | |||||||
3901 | //also check for the interaction ID as it must be unique for this SCO view |
||||||
3902 | $iva_sql = "SELECT iid FROM $iva_table |
||||||
3903 | WHERE |
||||||
3904 | c_id = $courseId AND |
||||||
3905 | lp_iv_id = $lp_iv_id AND |
||||||
3906 | ( |
||||||
3907 | order_id = $index OR |
||||||
3908 | interaction_id = '".Database::escape_string($interaction[0])."' |
||||||
3909 | ) |
||||||
3910 | "; |
||||||
3911 | $iva_res = Database::query($iva_sql); |
||||||
3912 | |||||||
3913 | $interaction[0] = $interaction[0] ?? ''; |
||||||
3914 | $interaction[1] = $interaction[1] ?? ''; |
||||||
3915 | $interaction[2] = $interaction[2] ?? ''; |
||||||
3916 | $interaction[3] = $interaction[3] ?? ''; |
||||||
3917 | $interaction[4] = $interaction[4] ?? ''; |
||||||
3918 | $interaction[5] = $interaction[5] ?? ''; |
||||||
3919 | $interaction[6] = $interaction[6] ?? ''; |
||||||
3920 | $interaction[7] = $interaction[7] ?? ''; |
||||||
3921 | |||||||
3922 | // id(0), type(1), time(2), weighting(3), correct_responses(4), student_response(5), result(6), latency(7) |
||||||
3923 | if (Database::num_rows($iva_res) > 0) { |
||||||
3924 | // Update (or don't). |
||||||
3925 | $iva_row = Database::fetch_array($iva_res); |
||||||
3926 | $iva_id = $iva_row[0]; |
||||||
3927 | // Insert new one. |
||||||
3928 | $params = [ |
||||||
3929 | 'interaction_id' => $interaction[0], |
||||||
3930 | 'interaction_type' => $interaction[1], |
||||||
3931 | 'weighting' => $interaction[3], |
||||||
3932 | 'completion_time' => $interaction[2], |
||||||
3933 | 'correct_responses' => $correct_resp, |
||||||
3934 | 'student_response' => $interaction[5], |
||||||
3935 | 'result' => $interaction[6], |
||||||
3936 | 'latency' => $interaction[7], |
||||||
3937 | ]; |
||||||
3938 | Database::update( |
||||||
3939 | $iva_table, |
||||||
3940 | $params, |
||||||
3941 | [ |
||||||
3942 | 'c_id = ? AND iid = ?' => [ |
||||||
3943 | $courseId, |
||||||
3944 | $iva_id, |
||||||
3945 | ], |
||||||
3946 | ] |
||||||
3947 | ); |
||||||
3948 | } else { |
||||||
3949 | // Insert new one. |
||||||
3950 | $params = [ |
||||||
3951 | 'c_id' => $courseId, |
||||||
3952 | 'order_id' => $index, |
||||||
3953 | 'lp_iv_id' => $lp_iv_id, |
||||||
3954 | 'interaction_id' => $interaction[0], |
||||||
3955 | 'interaction_type' => $interaction[1], |
||||||
3956 | 'weighting' => $interaction[3], |
||||||
3957 | 'completion_time' => $interaction[2], |
||||||
3958 | 'correct_responses' => $correct_resp, |
||||||
3959 | 'student_response' => $interaction[5], |
||||||
3960 | 'result' => $interaction[6], |
||||||
3961 | 'latency' => $interaction[7], |
||||||
3962 | ]; |
||||||
3963 | |||||||
3964 | $insertId = Database::insert($iva_table, $params); |
||||||
3965 | if ($insertId) { |
||||||
0 ignored issues
–
show
The expression
$insertId of type false|integer is loosely compared to true ; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
![]() |
|||||||
3966 | $sql = "UPDATE $iva_table SET id = iid |
||||||
3967 | WHERE iid = $insertId"; |
||||||
3968 | Database::query($sql); |
||||||
3969 | } |
||||||
3970 | } |
||||||
3971 | } |
||||||
3972 | } |
||||||
3973 | } |
||||||
3974 | } |
||||||
3975 | |||||||
3976 | if ($debug) { |
||||||
3977 | error_log('End of learnpathItem::write_to_db()', 0); |
||||||
3978 | } |
||||||
3979 | |||||||
3980 | return true; |
||||||
3981 | } |
||||||
3982 | |||||||
3983 | /** |
||||||
3984 | * Adds an audio file attached to the current item (store on disk and in db). |
||||||
3985 | * |
||||||
3986 | * @return bool |
||||||
3987 | */ |
||||||
3988 | public function addAudio() |
||||||
3989 | { |
||||||
3990 | $course_info = api_get_course_info(); |
||||||
3991 | $userId = api_get_user_id(); |
||||||
3992 | |||||||
3993 | $folderDocument = create_unexisting_directory( |
||||||
3994 | $course_info, |
||||||
3995 | $userId, |
||||||
3996 | 0, |
||||||
3997 | 0, |
||||||
3998 | 0, |
||||||
3999 | null, |
||||||
4000 | '/audio', |
||||||
4001 | get_lang('Audio'), |
||||||
4002 | 0, |
||||||
4003 | false, |
||||||
4004 | false |
||||||
4005 | ); |
||||||
4006 | |||||||
4007 | /*$filepath = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document/'; |
||||||
4008 | if (!is_dir($filepath.'audio')) { |
||||||
4009 | mkdir( |
||||||
4010 | $filepath.'audio', |
||||||
4011 | api_get_permissions_for_new_directories() |
||||||
4012 | ); |
||||||
4013 | DocumentManager::addDocument( |
||||||
4014 | $course_info, |
||||||
4015 | '/audio', |
||||||
4016 | 'folder', |
||||||
4017 | 0, |
||||||
4018 | 'audio' |
||||||
4019 | ); |
||||||
4020 | }*/ |
||||||
4021 | |||||||
4022 | $key = 'file'; |
||||||
4023 | if (!isset($_FILES[$key]['name']) || !isset($_FILES[$key]['tmp_name'])) { |
||||||
4024 | return false; |
||||||
4025 | } |
||||||
4026 | |||||||
4027 | $document = null; |
||||||
4028 | /*$document = DocumentManager::upload_document( |
||||||
4029 | $_FILES, |
||||||
4030 | null, |
||||||
4031 | null, |
||||||
4032 | null, |
||||||
4033 | 0, |
||||||
4034 | 'rename', |
||||||
4035 | false, |
||||||
4036 | true, |
||||||
4037 | 'file', |
||||||
4038 | false, |
||||||
4039 | $folderDocument->getIid(), |
||||||
4040 | );*/ |
||||||
4041 | |||||||
4042 | if ($document) { |
||||||
0 ignored issues
–
show
|
|||||||
4043 | $name = '/audio/'.$document->getResourceNode()->getResourceFiles()->first()->getOriginalName(); |
||||||
4044 | // Store the mp3 file in the lp_item table. |
||||||
4045 | $table = Database::get_course_table(TABLE_LP_ITEM); |
||||||
4046 | $sql = "UPDATE $table SET |
||||||
4047 | audio = '".Database::escape_string($name)."' |
||||||
4048 | WHERE iid = ".intval($this->db_id); |
||||||
4049 | Database::query($sql); |
||||||
4050 | |||||||
4051 | return true; |
||||||
4052 | } |
||||||
4053 | |||||||
4054 | return false; |
||||||
4055 | } |
||||||
4056 | |||||||
4057 | /** |
||||||
4058 | * Removes the relation between the current item and an audio file. The file |
||||||
4059 | * is only removed from the lp_item table, but remains in the document table |
||||||
4060 | * and directory. |
||||||
4061 | * |
||||||
4062 | * @return bool |
||||||
4063 | */ |
||||||
4064 | public function removeAudio() |
||||||
4065 | { |
||||||
4066 | $courseInfo = api_get_course_info(); |
||||||
4067 | |||||||
4068 | if (empty($this->db_id) || empty($courseInfo)) { |
||||||
4069 | return false; |
||||||
4070 | } |
||||||
4071 | |||||||
4072 | $table = Database::get_course_table(TABLE_LP_ITEM); |
||||||
4073 | $sql = "UPDATE $table SET |
||||||
4074 | audio = '' |
||||||
4075 | WHERE iid = ".$this->db_id; |
||||||
4076 | Database::query($sql); |
||||||
4077 | } |
||||||
4078 | |||||||
4079 | /** |
||||||
4080 | * Adds an audio file to the current item, using a file already in documents. |
||||||
4081 | * |
||||||
4082 | * @param int $documentId |
||||||
4083 | * |
||||||
4084 | * @return string |
||||||
4085 | */ |
||||||
4086 | public function add_audio_from_documents($documentId) |
||||||
4087 | { |
||||||
4088 | $courseInfo = api_get_course_info(); |
||||||
4089 | $documentData = DocumentManager::get_document_data_by_id($documentId, $courseInfo['code']); |
||||||
0 ignored issues
–
show
The function
DocumentManager::get_document_data_by_id() has been deprecated: use $repo->find()
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||
4090 | |||||||
4091 | $path = ''; |
||||||
4092 | if (!empty($documentData)) { |
||||||
4093 | $path = $documentData['path']; |
||||||
4094 | // Store the mp3 file in the lp_item table. |
||||||
4095 | $table = Database::get_course_table(TABLE_LP_ITEM); |
||||||
4096 | $sql = "UPDATE $table SET |
||||||
4097 | audio = '".Database::escape_string($path)."' |
||||||
4098 | WHERE iid = ".$this->db_id; |
||||||
4099 | Database::query($sql); |
||||||
4100 | } |
||||||
4101 | |||||||
4102 | return $path; |
||||||
4103 | } |
||||||
4104 | |||||||
4105 | /** |
||||||
4106 | * Transform the SCORM status to a string that can be translated by Chamilo |
||||||
4107 | * in different user languages. |
||||||
4108 | * |
||||||
4109 | * @param $status |
||||||
4110 | * @param bool $decorate |
||||||
4111 | * @param string $type classic|simple |
||||||
4112 | * |
||||||
4113 | * @return array|string |
||||||
4114 | */ |
||||||
4115 | public static function humanize_status($status, $decorate = true, $type = 'classic') |
||||||
4116 | { |
||||||
4117 | $statusList = [ |
||||||
4118 | 'completed' => 'Completed', |
||||||
4119 | 'incomplete' => 'Incomplete', |
||||||
4120 | 'failed' => 'Failed', |
||||||
4121 | 'passed' => 'Passed', |
||||||
4122 | 'browsed' => 'Browsed', |
||||||
4123 | 'not attempted' => 'Not attempted', |
||||||
4124 | ]; |
||||||
4125 | |||||||
4126 | $myLessonStatus = get_lang($statusList[$status]); |
||||||
4127 | |||||||
4128 | switch ($status) { |
||||||
4129 | case 'completed': |
||||||
4130 | case 'browsed': |
||||||
4131 | $classStatus = 'info'; |
||||||
4132 | break; |
||||||
4133 | case 'incomplete': |
||||||
4134 | $classStatus = 'warning'; |
||||||
4135 | break; |
||||||
4136 | case 'passed': |
||||||
4137 | $classStatus = 'success'; |
||||||
4138 | break; |
||||||
4139 | case 'failed': |
||||||
4140 | $classStatus = 'important'; |
||||||
4141 | break; |
||||||
4142 | default: |
||||||
4143 | $classStatus = 'default'; |
||||||
4144 | break; |
||||||
4145 | } |
||||||
4146 | |||||||
4147 | if ('simple' === $type) { |
||||||
4148 | if (in_array($status, ['failed', 'passed', 'browsed'])) { |
||||||
4149 | $myLessonStatus = get_lang('Incomplete'); |
||||||
4150 | |||||||
4151 | $classStatus = 'warning'; |
||||||
4152 | } |
||||||
4153 | } |
||||||
4154 | |||||||
4155 | if ($decorate) { |
||||||
4156 | return Display::label($myLessonStatus, $classStatus); |
||||||
4157 | } |
||||||
4158 | |||||||
4159 | return $myLessonStatus; |
||||||
4160 | } |
||||||
4161 | |||||||
4162 | /** |
||||||
4163 | * @return float |
||||||
4164 | */ |
||||||
4165 | public function getPrerequisiteMaxScore() |
||||||
4166 | { |
||||||
4167 | return $this->prerequisiteMaxScore; |
||||||
4168 | } |
||||||
4169 | |||||||
4170 | /** |
||||||
4171 | * @param float $prerequisiteMaxScore |
||||||
4172 | */ |
||||||
4173 | public function setPrerequisiteMaxScore($prerequisiteMaxScore) |
||||||
4174 | { |
||||||
4175 | $this->prerequisiteMaxScore = $prerequisiteMaxScore; |
||||||
4176 | } |
||||||
4177 | |||||||
4178 | /** |
||||||
4179 | * @return float |
||||||
4180 | */ |
||||||
4181 | public function getPrerequisiteMinScore() |
||||||
4182 | { |
||||||
4183 | return $this->prerequisiteMinScore; |
||||||
4184 | } |
||||||
4185 | |||||||
4186 | /** |
||||||
4187 | * @param float $prerequisiteMinScore |
||||||
4188 | */ |
||||||
4189 | public function setPrerequisiteMinScore($prerequisiteMinScore) |
||||||
4190 | { |
||||||
4191 | $this->prerequisiteMinScore = $prerequisiteMinScore; |
||||||
4192 | } |
||||||
4193 | |||||||
4194 | /** |
||||||
4195 | * @return int |
||||||
4196 | */ |
||||||
4197 | public function getLastScormSessionTime() |
||||||
4198 | { |
||||||
4199 | return $this->last_scorm_session_time; |
||||||
4200 | } |
||||||
4201 | |||||||
4202 | /** |
||||||
4203 | * @return int |
||||||
4204 | */ |
||||||
4205 | public function getIid() |
||||||
4206 | { |
||||||
4207 | return $this->iId; |
||||||
4208 | } |
||||||
4209 | |||||||
4210 | /** |
||||||
4211 | * @param int $user_id |
||||||
4212 | * @param string $prereqs_string |
||||||
4213 | * @param array $refs_list |
||||||
4214 | * |
||||||
4215 | * @return bool |
||||||
4216 | */ |
||||||
4217 | public function getStatusFromOtherSessions($user_id, $prereqs_string, $refs_list) |
||||||
4218 | { |
||||||
4219 | $lp_item_view = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||||||
4220 | $lp_view = Database::get_course_table(TABLE_LP_VIEW); |
||||||
4221 | $courseId = api_get_course_int_id(); |
||||||
4222 | $user_id = (int) $user_id; |
||||||
4223 | |||||||
4224 | // Check results from another sessions: |
||||||
4225 | $checkOtherSessions = ('true' === api_get_setting('lp.validate_lp_prerequisite_from_other_session')); |
||||||
4226 | if ($checkOtherSessions) { |
||||||
4227 | // Check items |
||||||
4228 | $sql = "SELECT iid FROM $lp_view |
||||||
4229 | WHERE |
||||||
4230 | c_id = $courseId AND |
||||||
4231 | user_id = $user_id AND |
||||||
4232 | lp_id = $this->lp_id AND |
||||||
4233 | session_id <> 0 |
||||||
4234 | "; |
||||||
4235 | $result = Database::query($sql); |
||||||
4236 | $resultFromOtherSessions = false; |
||||||
4237 | while ($row = Database::fetch_array($result)) { |
||||||
4238 | $lpIid = $row['iid']; |
||||||
4239 | $sql = "SELECT status FROM $lp_item_view |
||||||
4240 | WHERE |
||||||
4241 | lp_view_id = $lpIid AND |
||||||
4242 | lp_item_id = $refs_list[$prereqs_string] |
||||||
4243 | LIMIT 1"; |
||||||
4244 | $resultRow = Database::query($sql); |
||||||
4245 | if (Database::num_rows($resultRow)) { |
||||||
4246 | $statusResult = Database::fetch_array($resultRow); |
||||||
4247 | $status = $statusResult['status']; |
||||||
4248 | $checked = $status == $this->possible_status[2] || $status == $this->possible_status[3]; |
||||||
4249 | if ($checked) { |
||||||
4250 | $resultFromOtherSessions = true; |
||||||
4251 | break; |
||||||
4252 | } |
||||||
4253 | } |
||||||
4254 | } |
||||||
4255 | |||||||
4256 | return $resultFromOtherSessions; |
||||||
4257 | } |
||||||
4258 | } |
||||||
4259 | } |
||||||
4260 |