Merge branch 'MDL-58412-master' of git://github.com/jleyva/moodle
[moodle.git] / mod / feedback / classes / external.php
blobfaa58c0eca565191c625fecff66497bcb7675f95
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.
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/>.
17 /**
18 * Feedback external API
20 * @package mod_feedback
21 * @category external
22 * @copyright 2017 Juan Leyva <juan@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 * @since Moodle 3.3
27 defined('MOODLE_INTERNAL') || die;
29 require_once("$CFG->libdir/externallib.php");
31 use mod_feedback\external\feedback_summary_exporter;
32 use mod_feedback\external\feedback_completedtmp_exporter;
33 use mod_feedback\external\feedback_item_exporter;
34 use mod_feedback\external\feedback_valuetmp_exporter;
35 use mod_feedback\external\feedback_value_exporter;
36 use mod_feedback\external\feedback_completed_exporter;
38 /**
39 * Feedback external functions
41 * @package mod_feedback
42 * @category external
43 * @copyright 2017 Juan Leyva <juan@moodle.com>
44 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
45 * @since Moodle 3.3
47 class mod_feedback_external extends external_api {
49 /**
50 * Describes the parameters for get_feedbacks_by_courses.
52 * @return external_function_parameters
53 * @since Moodle 3.3
55 public static function get_feedbacks_by_courses_parameters() {
56 return new external_function_parameters (
57 array(
58 'courseids' => new external_multiple_structure(
59 new external_value(PARAM_INT, 'Course id'), 'Array of course ids', VALUE_DEFAULT, array()
65 /**
66 * Returns a list of feedbacks in a provided list of courses.
67 * If no list is provided all feedbacks that the user can view will be returned.
69 * @param array $courseids course ids
70 * @return array of warnings and feedbacks
71 * @since Moodle 3.3
73 public static function get_feedbacks_by_courses($courseids = array()) {
74 global $PAGE;
76 $warnings = array();
77 $returnedfeedbacks = array();
79 $params = array(
80 'courseids' => $courseids,
82 $params = self::validate_parameters(self::get_feedbacks_by_courses_parameters(), $params);
84 $mycourses = array();
85 if (empty($params['courseids'])) {
86 $mycourses = enrol_get_my_courses();
87 $params['courseids'] = array_keys($mycourses);
90 // Ensure there are courseids to loop through.
91 if (!empty($params['courseids'])) {
93 list($courses, $warnings) = external_util::validate_courses($params['courseids'], $mycourses);
94 $output = $PAGE->get_renderer('core');
96 // Get the feedbacks in this course, this function checks users visibility permissions.
97 // We can avoid then additional validate_context calls.
98 $feedbacks = get_all_instances_in_courses("feedback", $courses);
99 foreach ($feedbacks as $feedback) {
101 $context = context_module::instance($feedback->coursemodule);
103 // Remove fields that are not from the feedback (added by get_all_instances_in_courses).
104 unset($feedback->coursemodule, $feedback->context, $feedback->visible, $feedback->section, $feedback->groupmode,
105 $feedback->groupingid);
107 // Check permissions.
108 if (!has_capability('mod/feedback:edititems', $context)) {
109 // Don't return the optional properties.
110 $properties = feedback_summary_exporter::properties_definition();
111 foreach ($properties as $property => $config) {
112 if (!empty($config['optional'])) {
113 unset($feedback->{$property});
117 $exporter = new feedback_summary_exporter($feedback, array('context' => $context));
118 $returnedfeedbacks[] = $exporter->export($output);
122 $result = array(
123 'feedbacks' => $returnedfeedbacks,
124 'warnings' => $warnings
126 return $result;
130 * Describes the get_feedbacks_by_courses return value.
132 * @return external_single_structure
133 * @since Moodle 3.3
135 public static function get_feedbacks_by_courses_returns() {
136 return new external_single_structure(
137 array(
138 'feedbacks' => new external_multiple_structure(
139 feedback_summary_exporter::get_read_structure()
141 'warnings' => new external_warnings(),
147 * Utility function for validating a feedback.
149 * @param int $feedbackid feedback instance id
150 * @return array array containing the feedback persistent, course, context and course module objects
151 * @since Moodle 3.3
153 protected static function validate_feedback($feedbackid) {
154 global $DB, $USER;
156 // Request and permission validation.
157 $feedback = $DB->get_record('feedback', array('id' => $feedbackid), '*', MUST_EXIST);
158 list($course, $cm) = get_course_and_cm_from_instance($feedback, 'feedback');
160 $context = context_module::instance($cm->id);
161 self::validate_context($context);
163 return array($feedback, $course, $cm, $context);
167 * Utility function for validating access to feedback.
169 * @param stdClass $feedback feedback object
170 * @param stdClass $course course object
171 * @param stdClass $cm course module
172 * @param stdClass $context context object
173 * @throws moodle_exception
174 * @return feedback_completion feedback completion instance
175 * @since Moodle 3.3
177 protected static function validate_feedback_access($feedback, $course, $cm, $context, $checksubmit = false) {
178 $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $course->id);
180 if (!$feedbackcompletion->can_complete()) {
181 throw new required_capability_exception($context, 'mod/feedback:complete', 'nopermission', '');
184 if (!$feedbackcompletion->is_open()) {
185 throw new moodle_exception('feedback_is_not_open', 'feedback');
188 if ($feedbackcompletion->is_empty()) {
189 throw new moodle_exception('no_items_available_yet', 'feedback');
192 if ($checksubmit && !$feedbackcompletion->can_submit()) {
193 throw new moodle_exception('this_feedback_is_already_submitted', 'feedback');
195 return $feedbackcompletion;
199 * Describes the parameters for get_feedback_access_information.
201 * @return external_external_function_parameters
202 * @since Moodle 3.3
204 public static function get_feedback_access_information_parameters() {
205 return new external_function_parameters (
206 array(
207 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id.')
213 * Return access information for a given feedback.
215 * @param int $feedbackid feedback instance id
216 * @return array of warnings and the access information
217 * @since Moodle 3.3
218 * @throws moodle_exception
220 public static function get_feedback_access_information($feedbackid) {
221 global $PAGE;
223 $params = array(
224 'feedbackid' => $feedbackid
226 $params = self::validate_parameters(self::get_feedback_access_information_parameters(), $params);
228 list($feedback, $course, $cm, $context) = self::validate_feedback($params['feedbackid']);
229 $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $course->id);
231 $result = array();
232 // Capabilities first.
233 $result['canviewanalysis'] = $feedbackcompletion->can_view_analysis();
234 $result['cancomplete'] = $feedbackcompletion->can_complete();
235 $result['cansubmit'] = $feedbackcompletion->can_submit();
236 $result['candeletesubmissions'] = has_capability('mod/feedback:deletesubmissions', $context);
237 $result['canviewreports'] = has_capability('mod/feedback:viewreports', $context);
238 $result['canedititems'] = has_capability('mod/feedback:edititems', $context);
240 // Status information.
241 $result['isempty'] = $feedbackcompletion->is_empty();
242 $result['isopen'] = $feedbackcompletion->is_open();
243 $anycourse = ($course->id == SITEID);
244 $result['isalreadysubmitted'] = $feedbackcompletion->is_already_submitted($anycourse);
245 $result['isanonymous'] = $feedbackcompletion->is_anonymous();
247 $result['warnings'] = [];
248 return $result;
252 * Describes the get_feedback_access_information return value.
254 * @return external_single_structure
255 * @since Moodle 3.3
257 public static function get_feedback_access_information_returns() {
258 return new external_single_structure(
259 array(
260 'canviewanalysis' => new external_value(PARAM_BOOL, 'Whether the user can view the analysis or not.'),
261 'cancomplete' => new external_value(PARAM_BOOL, 'Whether the user can complete the feedback or not.'),
262 'cansubmit' => new external_value(PARAM_BOOL, 'Whether the user can submit the feedback or not.'),
263 'candeletesubmissions' => new external_value(PARAM_BOOL, 'Whether the user can delete submissions or not.'),
264 'canviewreports' => new external_value(PARAM_BOOL, 'Whether the user can view the feedback reports or not.'),
265 'canedititems' => new external_value(PARAM_BOOL, 'Whether the user can edit feedback items or not.'),
266 'isempty' => new external_value(PARAM_BOOL, 'Whether the feedback has questions or not.'),
267 'isopen' => new external_value(PARAM_BOOL, 'Whether the feedback has active access time restrictions or not.'),
268 'isalreadysubmitted' => new external_value(PARAM_BOOL, 'Whether the feedback is already submitted or not.'),
269 'isanonymous' => new external_value(PARAM_BOOL, 'Whether the feedback is anonymous or not.'),
270 'warnings' => new external_warnings(),
276 * Describes the parameters for view_feedback.
278 * @return external_function_parameters
279 * @since Moodle 3.3
281 public static function view_feedback_parameters() {
282 return new external_function_parameters (
283 array(
284 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
285 'moduleviewed' => new external_value(PARAM_BOOL, 'If we need to mark the module as viewed for completion',
286 VALUE_DEFAULT, false),
292 * Trigger the course module viewed event and update the module completion status.
294 * @param int $feedbackid feedback instance id
295 * @param bool $moduleviewed If we need to mark the module as viewed for completion
296 * @return array of warnings and status result
297 * @since Moodle 3.3
298 * @throws moodle_exception
300 public static function view_feedback($feedbackid, $moduleviewed = false) {
302 $params = array('feedbackid' => $feedbackid, 'moduleviewed' => $moduleviewed);
303 $params = self::validate_parameters(self::view_feedback_parameters(), $params);
304 $warnings = array();
306 list($feedback, $course, $cm, $context) = self::validate_feedback($params['feedbackid']);
307 $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $course->id);
309 // Trigger module viewed event.
310 $feedbackcompletion->trigger_module_viewed();
311 if ($params['moduleviewed']) {
312 if (!$feedbackcompletion->is_open()) {
313 throw new moodle_exception('feedback_is_not_open', 'feedback');
315 // Mark activity viewed for completion-tracking.
316 $feedbackcompletion->set_module_viewed();
319 $result = array(
320 'status' => true,
321 'warnings' => $warnings,
323 return $result;
327 * Describes the view_feedback return value.
329 * @return external_single_structure
330 * @since Moodle 3.3
332 public static function view_feedback_returns() {
333 return new external_single_structure(
334 array(
335 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
336 'warnings' => new external_warnings(),
342 * Describes the parameters for get_current_completed_tmp.
344 * @return external_function_parameters
345 * @since Moodle 3.3
347 public static function get_current_completed_tmp_parameters() {
348 return new external_function_parameters (
349 array(
350 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
356 * Returns the temporary completion record for the current user.
358 * @param int $feedbackid feedback instance id
359 * @return array of warnings and status result
360 * @since Moodle 3.3
361 * @throws moodle_exception
363 public static function get_current_completed_tmp($feedbackid) {
364 global $PAGE;
366 $params = array('feedbackid' => $feedbackid);
367 $params = self::validate_parameters(self::get_current_completed_tmp_parameters(), $params);
368 $warnings = array();
370 list($feedback, $course, $cm, $context) = self::validate_feedback($params['feedbackid']);
371 $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $course->id);
373 if ($completed = $feedbackcompletion->get_current_completed_tmp()) {
374 $exporter = new feedback_completedtmp_exporter($completed);
375 return array(
376 'feedback' => $exporter->export($PAGE->get_renderer('core')),
377 'warnings' => $warnings,
380 throw new moodle_exception('not_started', 'feedback');
384 * Describes the get_current_completed_tmp return value.
386 * @return external_single_structure
387 * @since Moodle 3.3
389 public static function get_current_completed_tmp_returns() {
390 return new external_single_structure(
391 array(
392 'feedback' => feedback_completedtmp_exporter::get_read_structure(),
393 'warnings' => new external_warnings(),
399 * Describes the parameters for get_items.
401 * @return external_function_parameters
402 * @since Moodle 3.3
404 public static function get_items_parameters() {
405 return new external_function_parameters (
406 array(
407 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
413 * Returns the items (questions) in the given feedback.
415 * @param int $feedbackid feedback instance id
416 * @return array of warnings and feedbacks
417 * @since Moodle 3.3
419 public static function get_items($feedbackid) {
420 global $PAGE;
422 $params = array('feedbackid' => $feedbackid);
423 $params = self::validate_parameters(self::get_items_parameters(), $params);
424 $warnings = array();
426 list($feedback, $course, $cm, $context) = self::validate_feedback($params['feedbackid']);
428 $feedbackstructure = new mod_feedback_structure($feedback, $cm, $course->id);
429 $returneditems = array();
430 if ($items = $feedbackstructure->get_items()) {
431 foreach ($items as $item) {
432 $itemnumber = empty($item->itemnr) ? null : $item->itemnr;
433 unset($item->itemnr); // Added by the function, not part of the record.
434 $exporter = new feedback_item_exporter($item, array('context' => $context, 'itemnumber' => $itemnumber));
435 $returneditems[] = $exporter->export($PAGE->get_renderer('core'));
439 $result = array(
440 'items' => $returneditems,
441 'warnings' => $warnings
443 return $result;
447 * Describes the get_items return value.
449 * @return external_single_structure
450 * @since Moodle 3.3
452 public static function get_items_returns() {
453 return new external_single_structure(
454 array(
455 'items' => new external_multiple_structure(
456 feedback_item_exporter::get_read_structure()
458 'warnings' => new external_warnings(),
464 * Describes the parameters for launch_feedback.
466 * @return external_function_parameters
467 * @since Moodle 3.3
469 public static function launch_feedback_parameters() {
470 return new external_function_parameters (
471 array(
472 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
478 * Starts or continues a feedback submission
480 * @param array $feedbackid feedback instance id
481 * @return array of warnings and launch information
482 * @since Moodle 3.3
484 public static function launch_feedback($feedbackid) {
485 global $PAGE;
487 $params = array('feedbackid' => $feedbackid);
488 $params = self::validate_parameters(self::launch_feedback_parameters(), $params);
489 $warnings = array();
491 list($feedback, $course, $cm, $context) = self::validate_feedback($params['feedbackid']);
492 // Check we can do a new submission (or continue an existing).
493 $feedbackcompletion = self::validate_feedback_access($feedback, $course, $cm, $context, true);
495 $gopage = $feedbackcompletion->get_resume_page();
496 if ($gopage === null) {
497 $gopage = -1; // Last page.
500 $result = array(
501 'gopage' => $gopage,
502 'warnings' => $warnings
504 return $result;
508 * Describes the launch_feedback return value.
510 * @return external_single_structure
511 * @since Moodle 3.3
513 public static function launch_feedback_returns() {
514 return new external_single_structure(
515 array(
516 'gopage' => new external_value(PARAM_INT, 'The next page to go (-1 if we were already in the last page). 0 for first page.'),
517 'warnings' => new external_warnings(),
523 * Describes the parameters for get_page_items.
525 * @return external_function_parameters
526 * @since Moodle 3.3
528 public static function get_page_items_parameters() {
529 return new external_function_parameters (
530 array(
531 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
532 'page' => new external_value(PARAM_INT, 'The page to get starting by 0'),
538 * Get a single feedback page items.
540 * @param int $feedbackid feedback instance id
541 * @param int $page the page to get starting by 0
542 * @return array of warnings and launch information
543 * @since Moodle 3.3
545 public static function get_page_items($feedbackid, $page) {
546 global $PAGE;
548 $params = array('feedbackid' => $feedbackid, 'page' => $page);
549 $params = self::validate_parameters(self::get_page_items_parameters(), $params);
550 $warnings = array();
552 list($feedback, $course, $cm, $context) = self::validate_feedback($params['feedbackid']);
554 $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $course->id);
556 $page = $params['page'];
557 $pages = $feedbackcompletion->get_pages();
558 $pageitems = $pages[$page];
559 $hasnextpage = $page < count($pages) - 1; // Until we complete this page we can not trust get_next_page().
560 $hasprevpage = $page && ($feedbackcompletion->get_previous_page($page, false) !== null);
562 $returneditems = array();
563 foreach ($pageitems as $item) {
564 $itemnumber = empty($item->itemnr) ? null : $item->itemnr;
565 unset($item->itemnr); // Added by the function, not part of the record.
566 $exporter = new feedback_item_exporter($item, array('context' => $context, 'itemnumber' => $itemnumber));
567 $returneditems[] = $exporter->export($PAGE->get_renderer('core'));
570 $result = array(
571 'items' => $returneditems,
572 'hasprevpage' => $hasprevpage,
573 'hasnextpage' => $hasnextpage,
574 'warnings' => $warnings
576 return $result;
580 * Describes the get_page_items return value.
582 * @return external_single_structure
583 * @since Moodle 3.3
585 public static function get_page_items_returns() {
586 return new external_single_structure(
587 array(
588 'items' => new external_multiple_structure(
589 feedback_item_exporter::get_read_structure()
591 'hasprevpage' => new external_value(PARAM_BOOL, 'Whether is a previous page.'),
592 'hasnextpage' => new external_value(PARAM_BOOL, 'Whether there are more pages.'),
593 'warnings' => new external_warnings(),
599 * Describes the parameters for process_page.
601 * @return external_function_parameters
602 * @since Moodle 3.3
604 public static function process_page_parameters() {
605 return new external_function_parameters (
606 array(
607 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id.'),
608 'page' => new external_value(PARAM_INT, 'The page being processed.'),
609 'responses' => new external_multiple_structure(
610 new external_single_structure(
611 array(
612 'name' => new external_value(PARAM_NOTAGS, 'The response name (usually type[index]_id).'),
613 'value' => new external_value(PARAM_RAW, 'The response value.'),
615 ), 'The data to be processed.', VALUE_DEFAULT, array()
617 'goprevious' => new external_value(PARAM_BOOL, 'Whether we want to jump to previous page.', VALUE_DEFAULT, false),
623 * Process a jump between pages.
625 * @param array $feedbackid feedback instance id
626 * @param array $page the page being processed
627 * @param array $responses the responses to be processed
628 * @param bool $goprevious whether we want to jump to previous page
629 * @return array of warnings and launch information
630 * @since Moodle 3.3
632 public static function process_page($feedbackid, $page, $responses = [], $goprevious = false) {
633 global $USER, $SESSION;
635 $params = array('feedbackid' => $feedbackid, 'page' => $page, 'responses' => $responses, 'goprevious' => $goprevious);
636 $params = self::validate_parameters(self::process_page_parameters(), $params);
637 $warnings = array();
638 $siteaftersubmit = $completionpagecontents = '';
640 list($feedback, $course, $cm, $context) = self::validate_feedback($params['feedbackid']);
641 // Check we can do a new submission (or continue an existing).
642 $feedbackcompletion = self::validate_feedback_access($feedback, $course, $cm, $context, true);
644 // Create the $_POST object required by the feedback question engine.
645 $_POST = array();
646 foreach ($responses as $response) {
647 // First check if we are handling array parameters.
648 if (preg_match('/(.+)\[(.+)\]$/', $response['name'], $matches)) {
649 $_POST[$matches[1]][$matches[2]] = $response['value'];
650 } else {
651 $_POST[$response['name']] = $response['value'];
654 // Force fields.
655 $_POST['id'] = $cm->id;
656 $_POST['courseid'] = $course->id;
657 $_POST['gopage'] = $params['page'];
658 $_POST['_qf__mod_feedback_complete_form'] = 1;
660 // Determine where to go, backwards or forward.
661 if (!$params['goprevious']) {
662 $_POST['gonextpage'] = 1; // Even if we are saving values we need this set.
663 if ($feedbackcompletion->get_next_page($params['page'], false) === null) {
664 $_POST['savevalues'] = 1; // If there is no next page, it means we are finishing the feedback.
668 // Ignore sesskey (deep in some APIs), the request is already validated.
669 $USER->ignoresesskey = true;
670 feedback_init_feedback_session();
671 $SESSION->feedback->is_started = true;
673 $feedbackcompletion->process_page($params['page'], $params['goprevious']);
674 $completed = $feedbackcompletion->just_completed();
675 if ($completed) {
676 $jumpto = 0;
677 if ($feedback->page_after_submit) {
678 $completionpagecontents = $feedbackcompletion->page_after_submit();
681 if ($feedback->site_after_submit) {
682 $siteaftersubmit = feedback_encode_target_url($feedback->site_after_submit);
684 } else {
685 $jumpto = $feedbackcompletion->get_jumpto();
688 $result = array(
689 'jumpto' => $jumpto,
690 'completed' => $completed,
691 'completionpagecontents' => $completionpagecontents,
692 'siteaftersubmit' => $siteaftersubmit,
693 'warnings' => $warnings
695 return $result;
699 * Describes the process_page return value.
701 * @return external_single_structure
702 * @since Moodle 3.3
704 public static function process_page_returns() {
705 return new external_single_structure(
706 array(
707 'jumpto' => new external_value(PARAM_INT, 'The page to jump to.'),
708 'completed' => new external_value(PARAM_BOOL, 'If the user completed the feedback.'),
709 'completionpagecontents' => new external_value(PARAM_RAW, 'The completion page contents.'),
710 'siteaftersubmit' => new external_value(PARAM_RAW, 'The link (could be relative) to show after submit.'),
711 'warnings' => new external_warnings(),
717 * Describes the parameters for get_analysis.
719 * @return external_function_parameters
720 * @since Moodle 3.3
722 public static function get_analysis_parameters() {
723 return new external_function_parameters (
724 array(
725 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
726 'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group',
727 VALUE_DEFAULT, 0),
733 * Retrieves the feedback analysis.
735 * @param array $feedbackid feedback instance id
736 * @return array of warnings and launch information
737 * @since Moodle 3.3
739 public static function get_analysis($feedbackid, $groupid = 0) {
740 global $PAGE;
742 $params = array('feedbackid' => $feedbackid, 'groupid' => $groupid);
743 $params = self::validate_parameters(self::get_analysis_parameters(), $params);
744 $warnings = $itemsdata = array();
746 list($feedback, $course, $cm, $context) = self::validate_feedback($params['feedbackid']);
748 // Check permissions.
749 $feedbackstructure = new mod_feedback_structure($feedback, $cm);
750 if (!$feedbackstructure->can_view_analysis()) {
751 throw new required_capability_exception($context, 'mod/feedback:viewanalysepage', 'nopermission', '');
754 if (!empty($params['groupid'])) {
755 $groupid = $params['groupid'];
756 // Determine is the group is visible to user.
757 if (!groups_group_visible($groupid, $course, $cm)) {
758 throw new moodle_exception('notingroup');
760 } else {
761 // Check to see if groups are being used here.
762 if ($groupmode = groups_get_activity_groupmode($cm)) {
763 $groupid = groups_get_activity_group($cm);
764 // Determine is the group is visible to user (this is particullary for the group 0 -> all groups).
765 if (!groups_group_visible($groupid, $course, $cm)) {
766 throw new moodle_exception('notingroup');
768 } else {
769 $groupid = 0;
773 // Summary data.
774 $summary = new mod_feedback\output\summary($feedbackstructure, $groupid);
775 $summarydata = $summary->export_for_template($PAGE->get_renderer('core'));
777 $checkanonymously = true;
778 if ($groupid > 0 AND $feedback->anonymous == FEEDBACK_ANONYMOUS_YES) {
779 $completedcount = $feedbackstructure->count_completed_responses($groupid);
780 if ($completedcount < FEEDBACK_MIN_ANONYMOUS_COUNT_IN_GROUP) {
781 $checkanonymously = false;
785 if ($checkanonymously) {
786 // Get the items of the feedback.
787 $items = $feedbackstructure->get_items(true);
788 foreach ($items as $item) {
789 $itemobj = feedback_get_item_class($item->typ);
790 $itemnumber = empty($item->itemnr) ? null : $item->itemnr;
791 unset($item->itemnr); // Added by the function, not part of the record.
792 $exporter = new feedback_item_exporter($item, array('context' => $context, 'itemnumber' => $itemnumber));
794 $itemsdata[] = array(
795 'item' => $exporter->export($PAGE->get_renderer('core')),
796 'data' => $itemobj->get_analysed_for_external($item, $groupid),
799 } else {
800 $warnings[] = array(
801 'item' => 'feedback',
802 'itemid' => $feedback->id,
803 'warningcode' => 'insufficientresponsesforthisgroup',
804 'message' => s(get_string('insufficient_responses_for_this_group', 'feedback'))
808 $result = array(
809 'completedcount' => $summarydata->completedcount,
810 'itemscount' => $summarydata->itemscount,
811 'itemsdata' => $itemsdata,
812 'warnings' => $warnings
814 return $result;
818 * Describes the get_analysis return value.
820 * @return external_single_structure
821 * @since Moodle 3.3
823 public static function get_analysis_returns() {
824 return new external_single_structure(
825 array(
826 'completedcount' => new external_value(PARAM_INT, 'Number of completed submissions.'),
827 'itemscount' => new external_value(PARAM_INT, 'Number of items (questions).'),
828 'itemsdata' => new external_multiple_structure(
829 new external_single_structure(
830 array(
831 'item' => feedback_item_exporter::get_read_structure(),
832 'data' => new external_multiple_structure(
833 new external_value(PARAM_RAW, 'The analysis data (can be json encoded)')
838 'warnings' => new external_warnings(),
844 * Describes the parameters for get_unfinished_responses.
846 * @return external_function_parameters
847 * @since Moodle 3.3
849 public static function get_unfinished_responses_parameters() {
850 return new external_function_parameters (
851 array(
852 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id.'),
858 * Retrieves responses from the current unfinished attempt.
860 * @param array $feedbackid feedback instance id
861 * @return array of warnings and launch information
862 * @since Moodle 3.3
864 public static function get_unfinished_responses($feedbackid) {
865 global $PAGE;
867 $params = array('feedbackid' => $feedbackid);
868 $params = self::validate_parameters(self::get_unfinished_responses_parameters(), $params);
869 $warnings = $itemsdata = array();
871 list($feedback, $course, $cm, $context) = self::validate_feedback($params['feedbackid']);
872 $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $course->id);
874 $responses = array();
875 $unfinished = $feedbackcompletion->get_unfinished_responses();
876 foreach ($unfinished as $u) {
877 $exporter = new feedback_valuetmp_exporter($u);
878 $responses[] = $exporter->export($PAGE->get_renderer('core'));
881 $result = array(
882 'responses' => $responses,
883 'warnings' => $warnings
885 return $result;
889 * Describes the get_unfinished_responses return value.
891 * @return external_single_structure
892 * @since Moodle 3.3
894 public static function get_unfinished_responses_returns() {
895 return new external_single_structure(
896 array(
897 'responses' => new external_multiple_structure(
898 feedback_valuetmp_exporter::get_read_structure()
900 'warnings' => new external_warnings(),
906 * Describes the parameters for get_finished_responses.
908 * @return external_function_parameters
909 * @since Moodle 3.3
911 public static function get_finished_responses_parameters() {
912 return new external_function_parameters (
913 array(
914 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id.'),
920 * Retrieves responses from the last finished attempt.
922 * @param array $feedbackid feedback instance id
923 * @return array of warnings and the responses
924 * @since Moodle 3.3
926 public static function get_finished_responses($feedbackid) {
927 global $PAGE;
929 $params = array('feedbackid' => $feedbackid);
930 $params = self::validate_parameters(self::get_finished_responses_parameters(), $params);
931 $warnings = $itemsdata = array();
933 list($feedback, $course, $cm, $context) = self::validate_feedback($params['feedbackid']);
934 $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $course->id);
936 $responses = array();
937 // Load and get the responses from the last completed feedback.
938 $feedbackcompletion->find_last_completed();
939 $unfinished = $feedbackcompletion->get_finished_responses();
940 foreach ($unfinished as $u) {
941 $exporter = new feedback_value_exporter($u);
942 $responses[] = $exporter->export($PAGE->get_renderer('core'));
945 $result = array(
946 'responses' => $responses,
947 'warnings' => $warnings
949 return $result;
953 * Describes the get_finished_responses return value.
955 * @return external_single_structure
956 * @since Moodle 3.3
958 public static function get_finished_responses_returns() {
959 return new external_single_structure(
960 array(
961 'responses' => new external_multiple_structure(
962 feedback_value_exporter::get_read_structure()
964 'warnings' => new external_warnings(),
970 * Describes the parameters for get_non_respondents.
972 * @return external_function_parameters
973 * @since Moodle 3.3
975 public static function get_non_respondents_parameters() {
976 return new external_function_parameters (
977 array(
978 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
979 'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group.',
980 VALUE_DEFAULT, 0),
981 'sort' => new external_value(PARAM_ALPHA, 'Sort param, must be firstname, lastname or lastaccess (default).',
982 VALUE_DEFAULT, 'lastaccess'),
983 'page' => new external_value(PARAM_INT, 'The page of records to return.', VALUE_DEFAULT, 0),
984 'perpage' => new external_value(PARAM_INT, 'The number of records to return per page.', VALUE_DEFAULT, 0),
990 * Retrieves a list of students who didn't submit the feedback.
992 * @param int $feedbackid feedback instance id
993 * @param int $groupid Group id, 0 means that the function will determine the user group'
994 * @param str $sort sort param, must be firstname, lastname or lastaccess (default)
995 * @param int $page the page of records to return
996 * @param int $perpage the number of records to return per page
997 * @return array of warnings and users ids
998 * @since Moodle 3.3
1000 public static function get_non_respondents($feedbackid, $groupid = 0, $sort = 'lastaccess', $page = 0, $perpage = 0) {
1001 global $CFG;
1002 require_once($CFG->dirroot . '/mod/feedback/lib.php');
1004 $params = array('feedbackid' => $feedbackid, 'groupid' => $groupid, 'sort' => $sort, 'page' => $page, 'perpage' => $perpage);
1005 $params = self::validate_parameters(self::get_non_respondents_parameters(), $params);
1006 $warnings = $nonrespondents = array();
1008 list($feedback, $course, $cm, $context) = self::validate_feedback($params['feedbackid']);
1010 if ($feedback->anonymous != FEEDBACK_ANONYMOUS_NO || $feedback->course == SITEID) {
1011 throw new moodle_exception('anonymous', 'feedback');
1014 // Check permissions.
1015 require_capability('mod/feedback:viewreports', $context);
1017 if (!empty($params['groupid'])) {
1018 $groupid = $params['groupid'];
1019 // Determine is the group is visible to user.
1020 if (!groups_group_visible($groupid, $course, $cm)) {
1021 throw new moodle_exception('notingroup');
1023 } else {
1024 // Check to see if groups are being used here.
1025 if ($groupmode = groups_get_activity_groupmode($cm)) {
1026 $groupid = groups_get_activity_group($cm);
1027 // Determine is the group is visible to user (this is particullary for the group 0 -> all groups).
1028 if (!groups_group_visible($groupid, $course, $cm)) {
1029 throw new moodle_exception('notingroup');
1031 } else {
1032 $groupid = 0;
1036 if ($params['sort'] !== 'firstname' && $params['sort'] !== 'lastname' && $params['sort'] !== 'lastaccess') {
1037 throw new invalid_parameter_exception('Invalid sort param, must be firstname, lastname or lastaccess.');
1040 // Check if we are page filtering.
1041 if ($params['perpage'] == 0) {
1042 $page = $params['page'];
1043 $perpage = FEEDBACK_DEFAULT_PAGE_COUNT;
1044 } else {
1045 $perpage = $params['perpage'];
1046 $page = $perpage * $params['page'];
1048 $users = feedback_get_incomplete_users($cm, $groupid, $params['sort'], $page, $perpage, true);
1049 foreach ($users as $user) {
1050 $nonrespondents[] = [
1051 'courseid' => $course->id,
1052 'userid' => $user->id,
1053 'fullname' => fullname($user),
1054 'started' => $user->feedbackstarted
1058 $result = array(
1059 'users' => $nonrespondents,
1060 'total' => feedback_count_incomplete_users($cm, $groupid),
1061 'warnings' => $warnings
1063 return $result;
1067 * Describes the get_non_respondents return value.
1069 * @return external_single_structure
1070 * @since Moodle 3.3
1072 public static function get_non_respondents_returns() {
1073 return new external_single_structure(
1074 array(
1075 'users' => new external_multiple_structure(
1076 new external_single_structure(
1077 array(
1078 'courseid' => new external_value(PARAM_INT, 'Course id'),
1079 'userid' => new external_value(PARAM_INT, 'The user id'),
1080 'fullname' => new external_value(PARAM_TEXT, 'User full name'),
1081 'started' => new external_value(PARAM_BOOL, 'If the user has started the attempt'),
1085 'total' => new external_value(PARAM_INT, 'Total number of non respondents'),
1086 'warnings' => new external_warnings(),
1092 * Describes the parameters for get_responses_analysis.
1094 * @return external_function_parameters
1095 * @since Moodle 3.3
1097 public static function get_responses_analysis_parameters() {
1098 return new external_function_parameters (
1099 array(
1100 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
1101 'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group',
1102 VALUE_DEFAULT, 0),
1103 'page' => new external_value(PARAM_INT, 'The page of records to return.', VALUE_DEFAULT, 0),
1104 'perpage' => new external_value(PARAM_INT, 'The number of records to return per page', VALUE_DEFAULT, 0),
1110 * Return the feedback user responses.
1112 * @param int $feedbackid feedback instance id
1113 * @param int $groupid Group id, 0 means that the function will determine the user group
1114 * @param int $page the page of records to return
1115 * @param int $perpage the number of records to return per page
1116 * @return array of warnings and users attemps and responses
1117 * @throws moodle_exception
1118 * @since Moodle 3.3
1120 public static function get_responses_analysis($feedbackid, $groupid = 0, $page = 0, $perpage = 0) {
1122 $params = array('feedbackid' => $feedbackid, 'groupid' => $groupid, 'page' => $page, 'perpage' => $perpage);
1123 $params = self::validate_parameters(self::get_responses_analysis_parameters(), $params);
1124 $warnings = $itemsdata = array();
1126 list($feedback, $course, $cm, $context) = self::validate_feedback($params['feedbackid']);
1128 // Check permissions.
1129 require_capability('mod/feedback:viewreports', $context);
1131 if (!empty($params['groupid'])) {
1132 $groupid = $params['groupid'];
1133 // Determine is the group is visible to user.
1134 if (!groups_group_visible($groupid, $course, $cm)) {
1135 throw new moodle_exception('notingroup');
1137 } else {
1138 // Check to see if groups are being used here.
1139 if ($groupmode = groups_get_activity_groupmode($cm)) {
1140 $groupid = groups_get_activity_group($cm);
1141 // Determine is the group is visible to user (this is particullary for the group 0 -> all groups).
1142 if (!groups_group_visible($groupid, $course, $cm)) {
1143 throw new moodle_exception('notingroup');
1145 } else {
1146 $groupid = 0;
1150 $feedbackstructure = new mod_feedback_structure($feedback, $cm, $course->id);
1151 $responsestable = new mod_feedback_responses_table($feedbackstructure, $groupid);
1152 $anonresponsestable = new mod_feedback_responses_anon_table($feedbackstructure, $groupid);
1154 $result = array(
1155 'attempts' => $responsestable->export_external_structure($params['page'], $params['perpage']),
1156 'totalattempts' => $responsestable->get_total_responses_count(),
1157 'anonattempts' => $anonresponsestable->export_external_structure($params['page'], $params['perpage']),
1158 'totalanonattempts' => $anonresponsestable->get_total_responses_count(),
1159 'warnings' => $warnings
1161 return $result;
1165 * Describes the get_responses_analysis return value.
1167 * @return external_single_structure
1168 * @since Moodle 3.3
1170 public static function get_responses_analysis_returns() {
1171 $responsestructure = new external_multiple_structure(
1172 new external_single_structure(
1173 array(
1174 'id' => new external_value(PARAM_INT, 'Response id'),
1175 'name' => new external_value(PARAM_RAW, 'Response name'),
1176 'printval' => new external_value(PARAM_RAW, 'Response ready for output'),
1177 'rawval' => new external_value(PARAM_RAW, 'Response raw value'),
1182 return new external_single_structure(
1183 array(
1184 'attempts' => new external_multiple_structure(
1185 new external_single_structure(
1186 array(
1187 'id' => new external_value(PARAM_INT, 'Completed id'),
1188 'courseid' => new external_value(PARAM_INT, 'Course id'),
1189 'userid' => new external_value(PARAM_INT, 'User who responded'),
1190 'timemodified' => new external_value(PARAM_INT, 'Time modified for the response'),
1191 'fullname' => new external_value(PARAM_TEXT, 'User full name'),
1192 'responses' => $responsestructure
1196 'totalattempts' => new external_value(PARAM_INT, 'Total responses count.'),
1197 'anonattempts' => new external_multiple_structure(
1198 new external_single_structure(
1199 array(
1200 'id' => new external_value(PARAM_INT, 'Completed id'),
1201 'courseid' => new external_value(PARAM_INT, 'Course id'),
1202 'number' => new external_value(PARAM_INT, 'Response number'),
1203 'responses' => $responsestructure
1207 'totalanonattempts' => new external_value(PARAM_INT, 'Total anonymous responses count.'),
1208 'warnings' => new external_warnings(),
1214 * Describes the parameters for get_last_completed.
1216 * @return external_function_parameters
1217 * @since Moodle 3.3
1219 public static function get_last_completed_parameters() {
1220 return new external_function_parameters (
1221 array(
1222 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
1228 * Retrieves the last completion record for the current user.
1230 * @param int $feedbackid feedback instance id
1231 * @return array of warnings and the last completed record
1232 * @since Moodle 3.3
1233 * @throws moodle_exception
1235 public static function get_last_completed($feedbackid) {
1236 global $PAGE;
1238 $params = array('feedbackid' => $feedbackid);
1239 $params = self::validate_parameters(self::get_last_completed_parameters(), $params);
1240 $warnings = array();
1242 list($feedback, $course, $cm, $context) = self::validate_feedback($params['feedbackid']);
1243 $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $course->id);
1245 if ($feedbackcompletion->is_anonymous()) {
1246 throw new moodle_exception('anonymous', 'feedback');
1248 if ($completed = $feedbackcompletion->find_last_completed()) {
1249 $exporter = new feedback_completed_exporter($completed);
1250 return array(
1251 'completed' => $exporter->export($PAGE->get_renderer('core')),
1252 'warnings' => $warnings,
1255 throw new moodle_exception('not_completed_yet', 'feedback');
1259 * Describes the get_last_completed return value.
1261 * @return external_single_structure
1262 * @since Moodle 3.3
1264 public static function get_last_completed_returns() {
1265 return new external_single_structure(
1266 array(
1267 'completed' => feedback_completed_exporter::get_read_structure(),
1268 'warnings' => new external_warnings(),