Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * Collects information and methods about feedback completion (either complete.php or show_entries.php)
19
 *
20
 * @package   mod_feedback
21
 * @copyright 2016 Marina Glancy
22
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
class mod_feedback_completion extends mod_feedback_structure {
25
    /** @var stdClass */
26
    protected $completed;
27
    /** @var stdClass */
28
    protected $completedtmp = null;
29
    /** @var stdClass[] */
30
    protected $valuestmp = null;
31
    /** @var stdClass[] */
32
    protected $values = null;
33
    /** @var bool */
34
    protected $iscompleted = false;
35
    /** @var mod_feedback_complete_form the form used for completing the feedback */
36
    protected $form = null;
37
    /** @var bool true when the feedback has been completed during the request */
38
    protected $justcompleted = false;
39
    /** @var int the next page the user should jump after processing the form */
40
    protected $jumpto = null;
41
 
42
 
43
    /**
44
     * Constructor
45
     *
46
     * @param stdClass $feedback feedback object
47
     * @param cm_info $cm course module object corresponding to the $feedback
48
     *     (at least one of $feedback or $cm is required)
49
     * @param int $courseid current course (for site feedbacks only)
50
     * @param bool $iscompleted has feedback been already completed? If yes either completedid or userid must be specified.
51
     * @param int $completedid id in the table feedback_completed, may be omitted if userid is specified
52
     *     but it is highly recommended because the same user may have multiple responses to the same feedback
53
     *     for different courses
54
     * @param int $nonanonymouseuserid - Return only anonymous results or specified user's results.
55
     *     If null only anonymous replies will be returned and the $completedid is mandatory.
56
     *     If specified only non-anonymous replies of $nonanonymouseuserid will be returned.
57
     * @param int $userid User id to use for all capability checks, etc. Set to 0 for current user (default).
58
     */
59
    public function __construct($feedback, $cm, $courseid, $iscompleted = false, $completedid = null,
60
                                $nonanonymouseuserid = null, $userid = 0) {
61
        global $DB;
62
 
63
        parent::__construct($feedback, $cm, $courseid, 0, $userid);
64
        // Make sure courseid is always set for site feedback.
65
        if ($this->feedback->course == SITEID && !$this->courseid) {
66
            $this->courseid = SITEID;
67
        }
68
        if ($iscompleted) {
69
            // Retrieve information about the completion.
70
            $this->iscompleted = true;
71
            $params = array('feedback' => $this->feedback->id);
72
            if (!$nonanonymouseuserid && !$completedid) {
73
                throw new coding_exception('Either $completedid or $nonanonymouseuserid must be specified for completed feedbacks');
74
            }
75
            if ($completedid) {
76
                $params['id'] = $completedid;
77
            }
78
            if ($nonanonymouseuserid) {
79
                // We must respect the anonymousity of the reply that the user saw when they were completing the feedback,
80
                // not the current state that may have been changed later by the teacher.
81
                $params['anonymous_response'] = FEEDBACK_ANONYMOUS_NO;
82
                $params['userid'] = $nonanonymouseuserid;
83
            }
84
            $this->completed = $DB->get_record('feedback_completed', $params, '*', MUST_EXIST);
1441 ariadna 85
 
86
            if (!groups_user_groups_visible($this->feedback->course, $this->completed->userid, $cm)) {
87
                throw new moodle_exception('nopermissiontoshow');
88
            }
89
 
1 efrain 90
            $this->courseid = $this->completed->courseid;
91
        }
92
    }
93
 
94
    /**
95
     * Returns a record from 'feedback_completed' table
96
     * @return stdClass
97
     */
98
    public function get_completed() {
99
        return $this->completed;
100
    }
101
 
102
    /**
103
     * Check if the feedback was just completed.
104
     *
105
     * @return bool true if the feedback was just completed.
106
     * @since  Moodle 3.3
107
     */
108
    public function just_completed() {
109
        return $this->justcompleted;
110
    }
111
 
112
    /**
113
     * Return the jumpto property.
114
     *
115
     * @return int the next page to jump.
116
     * @since  Moodle 3.3
117
     */
118
    public function get_jumpto() {
119
        return $this->jumpto;
120
    }
121
 
122
    /**
123
     * Returns the temporary completion record for the current user or guest session
124
     *
125
     * @return stdClass|false record from feedback_completedtmp or false if not found
126
     */
127
    public function get_current_completed_tmp() {
128
        global $DB, $USER;
129
        if ($this->completedtmp === null) {
130
            $params = array('feedback' => $this->get_feedback()->id);
131
            if ($courseid = $this->get_courseid()) {
132
                $params['courseid'] = $courseid;
133
            }
134
            if ((isloggedin() || $USER->id != $this->userid) && !isguestuser($this->userid)) {
135
                $params['userid'] = $this->userid;
136
            } else {
137
                $params['guestid'] = sesskey();
138
            }
139
            $this->completedtmp = $DB->get_record('feedback_completedtmp', $params);
140
        }
141
        return $this->completedtmp;
142
    }
143
 
144
    /**
145
     * Can the current user see the item, if dependency is met?
146
     *
147
     * @param stdClass $item
148
     * @return bool whether user can see item or not,
149
     *     true if there is no dependency or dependency is met,
150
     *     false if dependent question is visible or broken
151
     *        and further it is either not answered or the dependency is not met,
152
     *     null if dependency is broken.
153
     */
154
    protected function can_see_item($item) {
155
        if (empty($item->dependitem)) {
156
            return true;
157
        }
158
        if ($this->dependency_has_error($item)) {
159
            return null;
160
        }
161
        $allitems = $this->get_items();
162
        $ditem = $allitems[$item->dependitem];
163
        $itemobj = feedback_get_item_class($ditem->typ);
164
        if ($this->iscompleted) {
165
            $value = $this->get_values($ditem);
166
        } else {
167
            $value = $this->get_values_tmp($ditem);
168
        }
169
        if ($value === null) {
170
            // Cyclic dependencies are no problem here, since they will throw an dependency error above.
171
            if ($this->can_see_item($ditem) === false) {
172
                return false;
173
            }
174
            return null;
175
        }
176
        $check = $itemobj->compare_value($ditem, $value, $item->dependvalue) ? true : false;
177
        if ($check) {
178
            return $this->can_see_item($ditem);
179
        }
180
        return false;
181
    }
182
 
183
    /**
184
     * Dependency condition has an error
185
     * @param stdClass $item
186
     * @return bool
187
     */
188
    protected function dependency_has_error($item) {
189
        if (empty($item->dependitem)) {
190
            // No dependency - no error.
191
            return false;
192
        }
193
        $allitems = $this->get_items();
194
        if (!array_key_exists($item->dependitem, $allitems)) {
195
            // Looks like dependent item has been removed.
196
            return true;
197
        }
198
        $itemids = array_keys($allitems);
199
        $index1 = array_search($item->dependitem, $itemids);
200
        $index2 = array_search($item->id, $itemids);
201
        if ($index1 >= $index2) {
202
            // Dependent item is after the current item in the feedback.
203
            return true;
204
        }
205
        for ($i = $index1 + 1; $i < $index2; $i++) {
206
            if ($allitems[$itemids[$i]]->typ === 'pagebreak') {
207
                return false;
208
            }
209
        }
210
        // There are no page breaks between dependent items.
211
        return true;
212
    }
213
 
214
    /**
215
     * Returns a value stored for this item in the feedback (temporary or not, depending on the mode)
216
     * @param stdClass $item
217
     * @return string
218
     */
219
    public function get_item_value($item) {
220
        if ($this->iscompleted) {
221
            return $this->get_values($item);
222
        } else {
223
            return $this->get_values_tmp($item);
224
        }
225
    }
226
 
227
    /**
228
     * Retrieves responses from an unfinished attempt.
229
     *
230
     * @return array the responses (from the feedback_valuetmp table)
231
     * @since  Moodle 3.3
232
     */
233
    public function get_unfinished_responses() {
234
        global $DB;
235
        $responses = array();
236
 
237
        $completedtmp = $this->get_current_completed_tmp();
238
        if ($completedtmp) {
239
            $responses = $DB->get_records('feedback_valuetmp', ['completed' => $completedtmp->id]);
240
        }
241
        return $responses;
242
    }
243
 
244
    /**
245
     * Returns all temporary values for this feedback or just a value for an item
246
     * @param stdClass $item
247
     * @return array
248
     */
249
    protected function get_values_tmp($item = null) {
250
        global $DB;
251
        if ($this->valuestmp === null) {
252
            $this->valuestmp = array();
253
            $responses = $this->get_unfinished_responses();
254
            foreach ($responses as $r) {
255
                $this->valuestmp[$r->item] = $r->value;
256
            }
257
        }
258
        if ($item) {
259
            return array_key_exists($item->id, $this->valuestmp) ? $this->valuestmp[$item->id] : null;
260
        }
261
        return $this->valuestmp;
262
    }
263
 
264
    /**
265
     * Retrieves responses from an finished attempt.
266
     *
267
     * @return array the responses (from the feedback_value table)
268
     * @since  Moodle 3.3
269
     */
270
    public function get_finished_responses() {
271
        global $DB;
272
        $responses = array();
273
 
274
        if ($this->completed) {
275
            $responses = $DB->get_records('feedback_value', ['completed' => $this->completed->id]);
276
        }
277
        return $responses;
278
    }
279
 
280
    /**
281
     * Returns all completed values for this feedback or just a value for an item
282
     * @param stdClass $item
283
     * @return array
284
     */
285
    protected function get_values($item = null) {
286
        global $DB;
287
        if ($this->values === null) {
288
            $this->values = array();
289
            $responses = $this->get_finished_responses();
290
            foreach ($responses as $r) {
291
                $this->values[$r->item] = $r->value;
292
            }
293
        }
294
        if ($item) {
295
            return array_key_exists($item->id, $this->values) ? $this->values[$item->id] : null;
296
        }
297
        return $this->values;
298
    }
299
 
300
    /**
301
     * Splits the feedback items into pages
302
     *
303
     * Items that we definitely know at this stage as not applicable are excluded.
304
     * Items that are dependent on something that has not yet been answered are
305
     * still present, as well as items with broken dependencies.
306
     *
307
     * @return array array of arrays of items
308
     */
309
    public function get_pages() {
310
        $pages = [[]]; // The first page always exists.
311
        $items = $this->get_items();
312
        foreach ($items as $item) {
313
            if ($item->typ === 'pagebreak') {
314
                $pages[] = [];
315
            } else if ($this->can_see_item($item) !== false) {
316
                $pages[count($pages) - 1][] = $item;
317
            }
318
        }
319
        return $pages;
320
    }
321
 
322
    /**
323
     * Returns the last page that has items with the value (i.e. not label) which have been answered
324
     * as well as the first page that has items with the values that have not been answered.
325
     *
326
     * Either of the two return values may be null if there are no answered page or there are no
327
     * unanswered pages left respectively.
328
     *
329
     * Two pages may not be directly following each other because there may be empty pages
330
     * or pages with information texts only between them
331
     *
332
     * @return array array of two elements [$lastcompleted, $firstincompleted]
333
     */
334
    protected function get_last_completed_page() {
335
        $completed = [];
336
        $incompleted = [];
337
        $pages = $this->get_pages();
338
        foreach ($pages as $pageidx => $pageitems) {
339
            foreach ($pageitems as $item) {
340
                if ($item->hasvalue) {
341
                    if ($this->get_values_tmp($item) !== null) {
342
                        $completed[$pageidx] = true;
343
                    } else {
344
                        $incompleted[$pageidx] = true;
345
                    }
346
                }
347
            }
348
        }
349
        $completed = array_keys($completed);
350
        $incompleted = array_keys($incompleted);
351
        // If some page has both completed and incompleted items it is considered incompleted.
352
        $completed = array_diff($completed, $incompleted);
353
        // If the completed page follows an incompleted page, it does not count.
354
        $firstincompleted = $incompleted ? min($incompleted) : null;
355
        if ($firstincompleted !== null) {
356
            $completed = array_filter($completed, function($a) use ($firstincompleted) {
357
                return $a < $firstincompleted;
358
            });
359
        }
360
        $lastcompleted = $completed ? max($completed) : null;
361
        return [$lastcompleted, $firstincompleted];
362
    }
363
 
364
    /**
365
     * Get the next page for the feedback
366
     *
367
     * This is normally $gopage+1 but may be bigger if there are empty pages or
368
     * pages without visible questions.
369
     *
370
     * This method can only be called when questions on the current page are
371
     * already answered, otherwise it may be inaccurate.
372
     *
373
     * @param int $gopage current page
374
     * @param bool $strictcheck when gopage is the user-input value, make sure we do not jump over unanswered questions
375
     * @return int|null the index of the next page or null if this is the last page
376
     */
377
    public function get_next_page($gopage, $strictcheck = true) {
378
        if ($strictcheck) {
379
            list($lastcompleted, $firstincompleted) = $this->get_last_completed_page();
380
            if ($firstincompleted !== null && $firstincompleted <= $gopage) {
381
                return $firstincompleted;
382
            }
383
        }
384
        $pages = $this->get_pages();
385
        for ($pageidx = $gopage + 1; $pageidx < count($pages); $pageidx++) {
386
            if (!empty($pages[$pageidx])) {
387
                return $pageidx;
388
            }
389
        }
390
        // No further pages in the feedback have any visible items.
391
        return null;
392
    }
393
 
394
    /**
395
     * Get the previous page for the feedback
396
     *
397
     * This is normally $gopage-1 but may be smaller if there are empty pages or
398
     * pages without visible questions.
399
     *
400
     * @param int $gopage current page
401
     * @param bool $strictcheck when gopage is the user-input value, make sure we do not jump over unanswered questions
402
     * @return int|null the index of the next page or null if this is the first page with items
403
     */
404
    public function get_previous_page($gopage, $strictcheck = true) {
405
        if (!$gopage) {
406
            // If we are already on the first (0) page, there is definitely no previous page.
407
            return null;
408
        }
409
        $pages = $this->get_pages();
410
        $rv = null;
411
        // Iterate through previous pages and find the closest one that has any items on it.
412
        for ($pageidx = $gopage - 1; $pageidx >= 0; $pageidx--) {
413
            if (!empty($pages[$pageidx])) {
414
                $rv = $pageidx;
415
                break;
416
            }
417
        }
418
        if ($rv === null) {
419
            // We are on the very first page that has items.
420
            return null;
421
        }
422
        if ($rv > 0 && $strictcheck) {
423
            // Check if this page is actually not past than first incompleted page.
424
            list($lastcompleted, $firstincompleted) = $this->get_last_completed_page();
425
            if ($firstincompleted !== null && $firstincompleted < $rv) {
426
                return $firstincompleted;
427
            }
428
        }
429
        return $rv;
430
    }
431
 
432
    /**
433
     * Page index to resume the feedback
434
     *
435
     * When user abandones answering feedback and then comes back to it we should send him
436
     * to the first page after the last page he fully completed.
437
     * @return int
438
     */
439
    public function get_resume_page() {
440
        list($lastcompleted, $firstincompleted) = $this->get_last_completed_page();
441
        return $lastcompleted === null ? 0 : $this->get_next_page($lastcompleted, false);
442
    }
443
 
444
    /**
445
     * Creates a new record in the 'feedback_completedtmp' table for the current user/guest session
446
     *
447
     * @return stdClass record from feedback_completedtmp or false if not found
448
     */
449
    protected function create_current_completed_tmp() {
450
        global $DB, $USER;
451
        $record = (object)['feedback' => $this->feedback->id];
452
        if ($this->get_courseid()) {
453
            $record->courseid = $this->get_courseid();
454
        }
455
        if ((isloggedin() || $USER->id != $this->userid) && !isguestuser($this->userid)) {
456
            $record->userid = $this->userid;
457
        } else {
458
            $record->guestid = sesskey();
459
        }
460
        $record->timemodified = time();
461
        $record->anonymous_response = $this->feedback->anonymous;
462
        $id = $DB->insert_record('feedback_completedtmp', $record);
463
        $this->completedtmp = $DB->get_record('feedback_completedtmp', ['id' => $id]);
464
        $this->valuestmp = null;
465
        return $this->completedtmp;
466
    }
467
 
468
    /**
469
     * If user has already completed the feedback, create the temproray values from last completed attempt
470
     *
471
     * @return stdClass record from feedback_completedtmp or false if not found
472
     */
473
    public function create_completed_tmp_from_last_completed() {
474
        if (!$this->get_current_completed_tmp()) {
475
            $lastcompleted = $this->find_last_completed();
476
            if ($lastcompleted) {
477
                $this->completedtmp = feedback_set_tmp_values($lastcompleted);
478
            }
479
        }
480
        return $this->completedtmp;
481
    }
482
 
483
    /**
484
     * Saves unfinished response to the temporary table
485
     *
486
     * This is called when user proceeds to the next/previous page in the complete form
487
     * and also right after the form submit.
488
     * After the form submit the {@link save_response()} is called to
489
     * move response from temporary table to completion table.
490
     *
491
     * @param stdClass $data data from the form mod_feedback_complete_form
492
     */
493
    public function save_response_tmp($data) {
494
        global $DB;
495
        if (!$completedtmp = $this->get_current_completed_tmp()) {
496
            $completedtmp = $this->create_current_completed_tmp();
497
        } else {
498
            $currentime = time();
499
            $DB->update_record('feedback_completedtmp',
500
                    ['id' => $completedtmp->id, 'timemodified' => $currentime]);
501
            $completedtmp->timemodified = $currentime;
502
        }
503
 
504
        // Find all existing values.
505
        $existingvalues = $DB->get_records_menu('feedback_valuetmp',
506
                ['completed' => $completedtmp->id], '', 'item, id');
507
 
508
        // Loop through all feedback items and save the ones that are present in $data.
509
        $allitems = $this->get_items();
510
        foreach ($allitems as $item) {
511
            if (!$item->hasvalue) {
512
                continue;
513
            }
514
            $keyname = $item->typ . '_' . $item->id;
515
            if (!isset($data->$keyname)) {
516
                // This item is either on another page or dependency was not met - nothing to save.
517
                continue;
518
            }
519
 
520
            $newvalue = ['item' => $item->id, 'completed' => $completedtmp->id, 'course_id' => $completedtmp->courseid];
521
 
522
            // Convert the value to string that can be stored in 'feedback_valuetmp' or 'feedback_value'.
523
            $itemobj = feedback_get_item_class($item->typ);
524
            $newvalue['value'] = $itemobj->create_value($data->$keyname);
525
 
526
            // Update or insert the value in the 'feedback_valuetmp' table.
527
            if (array_key_exists($item->id, $existingvalues)) {
528
                $newvalue['id'] = $existingvalues[$item->id];
529
                $DB->update_record('feedback_valuetmp', $newvalue);
530
            } else {
531
                $DB->insert_record('feedback_valuetmp', $newvalue);
532
            }
533
        }
534
 
535
        // Reset valuestmp cache.
536
        $this->valuestmp = null;
537
    }
538
 
539
    /**
540
     * Saves the response
541
     *
542
     * The form data has already been stored in the temporary table in
543
     * {@link save_response_tmp()}. This function copies the values
544
     * from the temporary table to the completion table.
545
     * It is also responsible for sending email notifications when applicable.
546
     */
547
    public function save_response() {
1441 ariadna 548
        global $DB, $USER;
1 efrain 549
 
550
        $feedbackcompleted = $this->find_last_completed();
551
        // If no record is found, change false to null for safe use in feedback_save_tmp_values.
552
        $feedbackcompleted = !$feedbackcompleted ? null : $feedbackcompleted;
553
        $feedbackcompletedtmp = $this->get_current_completed_tmp();
554
 
555
        // Save values.
556
        $completedid = feedback_save_tmp_values($feedbackcompletedtmp, $feedbackcompleted);
557
        $this->completed = $DB->get_record('feedback_completed', array('id' => $completedid));
558
 
559
        // Send email.
560
        if ($this->feedback->anonymous == FEEDBACK_ANONYMOUS_NO) {
561
            feedback_send_email($this->cm, $this->feedback, $this->cm->get_course(), $this->userid, $this->completed);
562
        } else {
563
            feedback_send_email_anonym($this->cm, $this->feedback, $this->cm->get_course());
564
        }
565
 
566
        // Update completion state.
567
        $completion = new completion_info($this->cm->get_course());
568
        if ((isloggedin() || $USER->id != $this->userid) && $completion->is_enabled($this->cm) &&
569
                $this->cm->completion == COMPLETION_TRACKING_AUTOMATIC && $this->feedback->completionsubmit) {
570
            $completion->update_state($this->cm, COMPLETION_COMPLETE, $this->userid);
571
        }
572
    }
573
 
574
    /**
575
     * Retrieves the last completion record for the current user
576
     *
577
     * @return stdClass record from feedback_completed or false if not found
578
     */
579
    public function find_last_completed() {
580
        global $DB, $USER;
581
        if ((!isloggedin() && $USER->id == $this->userid) || isguestuser($this->userid)) {
582
            // Not possible to retrieve completed feedback for guests.
583
            return false;
584
        }
585
        if ($this->is_anonymous()) {
586
            // Not possible to retrieve completed anonymous feedback.
587
            return false;
588
        }
589
        $params = array('feedback' => $this->feedback->id,
590
            'userid' => $this->userid,
591
            'anonymous_response' => FEEDBACK_ANONYMOUS_NO
592
        );
593
        if ($this->get_courseid()) {
594
            $params['courseid'] = $this->get_courseid();
595
        }
596
        $this->completed = $DB->get_record('feedback_completed', $params);
597
        return $this->completed;
598
    }
599
 
600
    /**
601
     * Checks if user has capability to submit the feedback
602
     *
603
     * There is an exception for fully anonymous feedbacks when guests can complete
604
     * feedback without the proper capability.
605
     *
606
     * This should be followed by checking {@link can_submit()} because even if
607
     * user has capablity to complete, they may have already submitted feedback
608
     * and can not re-submit
609
     *
610
     * @return bool
611
     */
612
    public function can_complete() {
613
        global $CFG, $USER;
614
 
615
        $context = context_module::instance($this->cm->id);
616
        if (has_capability('mod/feedback:complete', $context, $this->userid)) {
617
            return true;
618
        }
619
 
620
        if (!empty($CFG->feedback_allowfullanonymous)
621
                    AND $this->feedback->course == SITEID
622
                    AND $this->feedback->anonymous == FEEDBACK_ANONYMOUS_YES
623
                    AND ((!isloggedin() && $USER->id == $this->userid) || isguestuser($this->userid))) {
624
            // Guests are allowed to complete fully anonymous feedback without having 'mod/feedback:complete' capability.
625
            return true;
626
        }
627
 
628
        return false;
629
    }
630
 
631
    /**
632
     * Checks if user is prevented from re-submission.
633
     *
634
     * This must be called after {@link can_complete()}
635
     *
636
     * @return bool
637
     */
638
    public function can_submit() {
639
        if ($this->get_feedback()->multiple_submit == 0 ) {
640
            if ($this->is_already_submitted()) {
641
                return false;
642
            }
643
        }
644
        return true;
645
    }
646
 
647
    /**
648
     * Trigger module viewed event.
649
     *
650
     * @since Moodle 3.3
651
     */
652
    public function trigger_module_viewed() {
653
        $event = \mod_feedback\event\course_module_viewed::create_from_record($this->feedback, $this->cm, $this->cm->get_course());
654
        $event->trigger();
655
    }
656
 
657
    /**
658
     * Mark activity viewed for completion-tracking.
659
     *
660
     * @since Moodle 3.3
661
     */
662
    public function set_module_viewed() {
663
        global $CFG;
664
        require_once($CFG->libdir . '/completionlib.php');
665
 
666
        $completion = new completion_info($this->cm->get_course());
667
        $completion->set_module_viewed($this->cm, $this->userid);
668
    }
669
 
670
    /**
671
     * Process a page jump via the mod_feedback_complete_form.
672
     *
673
     * This function initializes the form and process the submission.
674
     *
675
     * @param  int $gopage         the current page
676
     * @param  int $gopreviouspage if the user chose to go to the previous page
677
     * @return string the url to redirect the user (if any)
678
     * @since  Moodle 3.3
679
     */
680
    public function process_page($gopage, $gopreviouspage = false) {
1441 ariadna 681
        global $PAGE;
1 efrain 682
 
683
        $urltogo = null;
684
 
685
        // Save the form for later during the request.
686
        $this->create_completed_tmp_from_last_completed();
687
        $this->form = new mod_feedback_complete_form(mod_feedback_complete_form::MODE_COMPLETE,
688
            $this, 'feedback_complete_form', array('gopage' => $gopage));
689
 
690
        if ($this->form->is_cancelled()) {
691
            // Form was cancelled - return to the course page.
692
            $urltogo = new moodle_url('/mod/feedback/view.php', ['id' => $this->get_cm()->id]);
693
        } else if ($this->form->is_submitted() &&
694
                ($this->form->is_validated() || $gopreviouspage)) {
695
            // Form was submitted (skip validation for "Previous page" button).
696
            $data = $this->form->get_submitted_data();
697
            $this->save_response_tmp($data);
698
            if (!empty($data->savevalues) || !empty($data->gonextpage)) {
699
                if (($nextpage = $this->get_next_page($gopage)) !== null) {
700
                    if ($PAGE->has_set_url()) {
701
                        $urltogo = new moodle_url($PAGE->url, array('gopage' => $nextpage));
702
                    }
703
                    $this->jumpto = $nextpage;
704
                } else {
705
                    $this->save_response();
706
                    if (!$this->get_feedback()->page_after_submit) {
707
                        \core\notification::success(get_string('entries_saved', 'feedback'));
708
                    }
709
                    $this->justcompleted = true;
710
                }
711
            } else if (!empty($gopreviouspage)) {
712
                $prevpage = intval($this->get_previous_page($gopage));
713
                if ($PAGE->has_set_url()) {
714
                    $urltogo = new moodle_url($PAGE->url, array('gopage' => $prevpage));
715
                }
716
                $this->jumpto = $prevpage;
717
            }
718
        }
719
        return $urltogo;
720
    }
721
 
722
    /**
723
     * Render the form with the questions.
724
     *
725
     * @return string the form rendered
726
     * @since Moodle 3.3
727
     */
728
    public function render_items() {
729
        return $this->form->render();
730
    }
1441 ariadna 731
}