Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]

   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   * Choice module external API
  19   *
  20   * @package    mod_choice
  21   * @category   external
  22   * @copyright  2015 Costantino Cito <ccito@cvaconsulting.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   * @since      Moodle 3.0
  25   */
  26  
  27  defined('MOODLE_INTERNAL') || die;
  28  require_once($CFG->libdir . '/externallib.php');
  29  require_once($CFG->dirroot . '/mod/choice/lib.php');
  30  
  31  /**
  32   * Choice module external functions
  33   *
  34   * @package    mod_choice
  35   * @category   external
  36   * @copyright  2015 Costantino Cito <ccito@cvaconsulting.com>
  37   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  38   * @since      Moodle 3.0
  39   */
  40  class mod_choice_external extends external_api {
  41  
  42      /**
  43       * Describes the parameters for get_choices_by_courses.
  44       *
  45       * @return external_function_parameters
  46       * @since Moodle 3.0
  47       */
  48      public static function get_choice_results_parameters() {
  49          return new external_function_parameters (array('choiceid' => new external_value(PARAM_INT, 'choice instance id')));
  50      }
  51      /**
  52       * Returns user's results for a specific choice
  53       * and a list of those users that did not answered yet.
  54       *
  55       * @param int $choiceid the choice instance id
  56       * @return array of responses details
  57       * @since Moodle 3.0
  58       */
  59      public static function get_choice_results($choiceid) {
  60          global $USER, $PAGE;
  61  
  62          $params = self::validate_parameters(self::get_choice_results_parameters(), array('choiceid' => $choiceid));
  63  
  64          if (!$choice = choice_get_choice($params['choiceid'])) {
  65              throw new moodle_exception("invalidcoursemodule", "error");
  66          }
  67          list($course, $cm) = get_course_and_cm_from_instance($choice, 'choice');
  68  
  69          $context = context_module::instance($cm->id);
  70          self::validate_context($context);
  71  
  72          $groupmode = groups_get_activity_groupmode($cm);
  73          // Check if we have to include responses from inactive users.
  74          $onlyactive = $choice->includeinactive ? false : true;
  75          $users = choice_get_response_data($choice, $cm, $groupmode, $onlyactive);
  76          // Show those who haven't answered the question.
  77          if (!empty($choice->showunanswered)) {
  78              $choice->option[0] = get_string('notanswered', 'choice');
  79              $choice->maxanswers[0] = 0;
  80          }
  81          $results = prepare_choice_show_results($choice, $course, $cm, $users);
  82  
  83          $options = array();
  84          $fullnamecap = has_capability('moodle/site:viewfullnames', $context);
  85          foreach ($results->options as $optionid => $option) {
  86  
  87              $userresponses = array();
  88              $numberofuser = 0;
  89              $percentageamount = 0;
  90              if (property_exists($option, 'user') and
  91                  (has_capability('mod/choice:readresponses', $context) or choice_can_view_results($choice))) {
  92                  $numberofuser = count($option->user);
  93                  $percentageamount = ((float)$numberofuser / (float)$results->numberofuser) * 100.0;
  94                  if ($choice->publish) {
  95                      foreach ($option->user as $userresponse) {
  96                          $response = array();
  97                          $response['userid'] = $userresponse->id;
  98                          $response['fullname'] = fullname($userresponse, $fullnamecap);
  99  
 100                          $userpicture = new user_picture($userresponse);
 101                          $userpicture->size = 1; // Size f1.
 102                          $response['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
 103  
 104                          // Add optional properties.
 105                          foreach (array('answerid', 'timemodified') as $field) {
 106                              if (property_exists($userresponse, 'answerid')) {
 107                                  $response[$field] = $userresponse->$field;
 108                              }
 109                          }
 110                          $userresponses[] = $response;
 111                      }
 112                  }
 113              }
 114  
 115              $options[] = array('id'               => $optionid,
 116                                 'text'             => external_format_string($option->text, $context->id),
 117                                 'maxanswer'        => $option->maxanswer,
 118                                 'userresponses'    => $userresponses,
 119                                 'numberofuser'     => $numberofuser,
 120                                 'percentageamount' => $percentageamount
 121                                );
 122          }
 123  
 124          $warnings = array();
 125          return array(
 126              'options' => $options,
 127              'warnings' => $warnings
 128          );
 129      }
 130  
 131      /**
 132       * Describes the get_choice_results return value.
 133       *
 134       * @return external_single_structure
 135       * @since Moodle 3.0
 136       */
 137      public static function get_choice_results_returns() {
 138          return new external_single_structure(
 139              array(
 140                  'options' => new external_multiple_structure(
 141                      new external_single_structure(
 142                          array(
 143                              'id' => new external_value(PARAM_INT, 'choice instance id'),
 144                              'text' => new external_value(PARAM_RAW, 'text of the choice'),
 145                              'maxanswer' => new external_value(PARAM_INT, 'maximum number of answers'),
 146                              'userresponses' => new external_multiple_structure(
 147                                   new external_single_structure(
 148                                       array(
 149                                          'userid' => new external_value(PARAM_INT, 'user id'),
 150                                          'fullname' => new external_value(PARAM_NOTAGS, 'user full name'),
 151                                          'profileimageurl' => new external_value(PARAM_URL, 'profile user image url'),
 152                                          'answerid' => new external_value(PARAM_INT, 'answer id', VALUE_OPTIONAL),
 153                                          'timemodified' => new external_value(PARAM_INT, 'time of modification', VALUE_OPTIONAL),
 154                                       ), 'User responses'
 155                                   )
 156                              ),
 157                              'numberofuser' => new external_value(PARAM_INT, 'number of users answers'),
 158                              'percentageamount' => new external_value(PARAM_FLOAT, 'percentage of users answers')
 159                          ), 'Options'
 160                      )
 161                  ),
 162                  'warnings' => new external_warnings(),
 163              )
 164          );
 165      }
 166  
 167      /**
 168       * Describes the parameters for mod_choice_get_choice_options.
 169       *
 170       * @return external_function_parameters
 171       * @since Moodle 3.0
 172       */
 173      public static function get_choice_options_parameters() {
 174          return new external_function_parameters (array('choiceid' => new external_value(PARAM_INT, 'choice instance id')));
 175      }
 176  
 177      /**
 178       * Returns options for a specific choice
 179       *
 180       * @param int $choiceid the choice instance id
 181       * @return array of options details
 182       * @since Moodle 3.0
 183       */
 184      public static function get_choice_options($choiceid) {
 185          global $USER;
 186          $warnings = array();
 187          $params = self::validate_parameters(self::get_choice_options_parameters(), array('choiceid' => $choiceid));
 188  
 189          if (!$choice = choice_get_choice($params['choiceid'])) {
 190              throw new moodle_exception("invalidcoursemodule", "error");
 191          }
 192          list($course, $cm) = get_course_and_cm_from_instance($choice, 'choice');
 193  
 194          $context = context_module::instance($cm->id);
 195          self::validate_context($context);
 196  
 197          require_capability('mod/choice:choose', $context);
 198  
 199          $groupmode = groups_get_activity_groupmode($cm);
 200          $onlyactive = $choice->includeinactive ? false : true;
 201          $allresponses = choice_get_response_data($choice, $cm, $groupmode, $onlyactive);
 202  
 203          $timenow = time();
 204          $choiceopen = true;
 205          $showpreview = false;
 206  
 207          if (!empty($choice->timeopen) && ($choice->timeopen > $timenow)) {
 208              $choiceopen = false;
 209              $warnings[1] = get_string("notopenyet", "choice", userdate($choice->timeopen));
 210              if ($choice->showpreview) {
 211                  $warnings[2] = get_string('previewonly', 'choice', userdate($choice->timeopen));
 212                  $showpreview = true;
 213              }
 214          }
 215          if (!empty($choice->timeclose) && ($timenow > $choice->timeclose)) {
 216              $choiceopen = false;
 217              $warnings[3] = get_string("expired", "choice", userdate($choice->timeclose));
 218          }
 219  
 220          $optionsarray = array();
 221  
 222          if ($choiceopen or $showpreview) {
 223  
 224              $options = choice_prepare_options($choice, $USER, $cm, $allresponses);
 225  
 226              foreach ($options['options'] as $option) {
 227                  $optionarr = array();
 228                  $optionarr['id']            = $option->attributes->value;
 229                  $optionarr['text']          = external_format_string($option->text, $context->id);
 230                  $optionarr['maxanswers']    = $option->maxanswers;
 231                  $optionarr['displaylayout'] = $option->displaylayout;
 232                  $optionarr['countanswers']  = $option->countanswers;
 233                  foreach (array('checked', 'disabled') as $field) {
 234                      if (property_exists($option->attributes, $field) and $option->attributes->$field == 1) {
 235                          $optionarr[$field] = 1;
 236                      } else {
 237                          $optionarr[$field] = 0;
 238                      }
 239                  }
 240                  // When showpreview is active, we show options as disabled.
 241                  if ($showpreview or ($optionarr['checked'] == 1 and !$choice->allowupdate)) {
 242                      $optionarr['disabled'] = 1;
 243                  }
 244                  $optionsarray[] = $optionarr;
 245              }
 246          }
 247          foreach ($warnings as $key => $message) {
 248              $warnings[$key] = array(
 249                  'item' => 'choice',
 250                  'itemid' => $cm->id,
 251                  'warningcode' => $key,
 252                  'message' => $message
 253              );
 254          }
 255          return array(
 256              'options' => $optionsarray,
 257              'warnings' => $warnings
 258          );
 259      }
 260  
 261      /**
 262       * Describes the get_choice_results return value.
 263       *
 264       * @return external_multiple_structure
 265       * @since Moodle 3.0
 266       */
 267      public static function get_choice_options_returns() {
 268          return new external_single_structure(
 269              array(
 270                  'options' => new external_multiple_structure(
 271                      new external_single_structure(
 272                          array(
 273                              'id' => new external_value(PARAM_INT, 'option id'),
 274                              'text' => new external_value(PARAM_RAW, 'text of the choice'),
 275                              'maxanswers' => new external_value(PARAM_INT, 'maximum number of answers'),
 276                              'displaylayout' => new external_value(PARAM_BOOL, 'true for orizontal, otherwise vertical'),
 277                              'countanswers' => new external_value(PARAM_INT, 'number of answers'),
 278                              'checked' => new external_value(PARAM_BOOL, 'we already answered'),
 279                              'disabled' => new external_value(PARAM_BOOL, 'option disabled'),
 280                              )
 281                      ), 'Options'
 282                  ),
 283                  'warnings' => new external_warnings(),
 284              )
 285          );
 286      }
 287  
 288      /**
 289       * Describes the parameters for submit_choice_response.
 290       *
 291       * @return external_function_parameters
 292       * @since Moodle 3.0
 293       */
 294      public static function submit_choice_response_parameters() {
 295          return new external_function_parameters (
 296              array(
 297                  'choiceid' => new external_value(PARAM_INT, 'choice instance id'),
 298                  'responses' => new external_multiple_structure(
 299                      new external_value(PARAM_INT, 'answer id'),
 300                      'Array of response ids'
 301                  ),
 302              )
 303          );
 304      }
 305  
 306      /**
 307       * Submit choice responses
 308       *
 309       * @param int $choiceid the choice instance id
 310       * @param array $responses the response ids
 311       * @return array answers information and warnings
 312       * @since Moodle 3.0
 313       */
 314      public static function submit_choice_response($choiceid, $responses) {
 315          global $USER;
 316  
 317          $warnings = array();
 318          $params = self::validate_parameters(self::submit_choice_response_parameters(),
 319                                              array(
 320                                                  'choiceid' => $choiceid,
 321                                                  'responses' => $responses
 322                                              ));
 323  
 324          if (!$choice = choice_get_choice($params['choiceid'])) {
 325              throw new moodle_exception("invalidcoursemodule", "error");
 326          }
 327          list($course, $cm) = get_course_and_cm_from_instance($choice, 'choice');
 328  
 329          $context = context_module::instance($cm->id);
 330          self::validate_context($context);
 331  
 332          require_capability('mod/choice:choose', $context);
 333  
 334          $timenow = time();
 335          if (!empty($choice->timeopen) && ($choice->timeopen > $timenow)) {
 336              throw new moodle_exception("notopenyet", "choice", '', userdate($choice->timeopen));
 337          } else if (!empty($choice->timeclose) && ($timenow > $choice->timeclose)) {
 338              throw new moodle_exception("expired", "choice", '', userdate($choice->timeclose));
 339          }
 340  
 341          if (!choice_get_my_response($choice) or $choice->allowupdate) {
 342              // When a single response is given, we convert the array to a simple variable
 343              // in order to avoid choice_user_submit_response to check with allowmultiple even
 344              // for a single response.
 345              if (count($params['responses']) == 1) {
 346                  $params['responses'] = reset($params['responses']);
 347              }
 348              choice_user_submit_response($params['responses'], $choice, $USER->id, $course, $cm);
 349          } else {
 350              throw new moodle_exception('missingrequiredcapability', 'webservice', '', 'allowupdate');
 351          }
 352          $answers = choice_get_my_response($choice);
 353  
 354          return array(
 355              'answers' => $answers,
 356              'warnings' => $warnings
 357          );
 358      }
 359  
 360      /**
 361       * Describes the submit_choice_response return value.
 362       *
 363       * @return external_multiple_structure
 364       * @since Moodle 3.0
 365       */
 366      public static function submit_choice_response_returns() {
 367          return new external_single_structure(
 368              array(
 369                  'answers' => new external_multiple_structure(
 370                       new external_single_structure(
 371                           array(
 372                               'id'           => new external_value(PARAM_INT, 'answer id'),
 373                               'choiceid'     => new external_value(PARAM_INT, 'choiceid'),
 374                               'userid'       => new external_value(PARAM_INT, 'user id'),
 375                               'optionid'     => new external_value(PARAM_INT, 'optionid'),
 376                               'timemodified' => new external_value(PARAM_INT, 'time of last modification')
 377                           ), 'Answers'
 378                       )
 379                  ),
 380                  'warnings' => new external_warnings(),
 381              )
 382          );
 383      }
 384  
 385      /**
 386       * Returns description of method parameters
 387       *
 388       * @return external_function_parameters
 389       * @since Moodle 3.0
 390       */
 391      public static function view_choice_parameters() {
 392          return new external_function_parameters(
 393              array(
 394                  'choiceid' => new external_value(PARAM_INT, 'choice instance id')
 395              )
 396          );
 397      }
 398  
 399      /**
 400       * Trigger the course module viewed event and update the module completion status.
 401       *
 402       * @param int $choiceid the choice instance id
 403       * @return array of warnings and status result
 404       * @since Moodle 3.0
 405       * @throws moodle_exception
 406       */
 407      public static function view_choice($choiceid) {
 408          global $CFG;
 409  
 410          $params = self::validate_parameters(self::view_choice_parameters(),
 411                                              array(
 412                                                  'choiceid' => $choiceid
 413                                              ));
 414          $warnings = array();
 415  
 416          // Request and permission validation.
 417          if (!$choice = choice_get_choice($params['choiceid'])) {
 418              throw new moodle_exception("invalidcoursemodule", "error");
 419          }
 420          list($course, $cm) = get_course_and_cm_from_instance($choice, 'choice');
 421  
 422          $context = context_module::instance($cm->id);
 423          self::validate_context($context);
 424  
 425          // Trigger course_module_viewed event and completion.
 426          choice_view($choice, $course, $cm, $context);
 427  
 428          $result = array();
 429          $result['status'] = true;
 430          $result['warnings'] = $warnings;
 431          return $result;
 432      }
 433  
 434      /**
 435       * Returns description of method result value
 436       *
 437       * @return external_description
 438       * @since Moodle 3.0
 439       */
 440      public static function view_choice_returns() {
 441          return new external_single_structure(
 442              array(
 443                  'status' => new external_value(PARAM_BOOL, 'status: true if success'),
 444                  'warnings' => new external_warnings()
 445              )
 446          );
 447      }
 448  
 449      /**
 450       * Describes the parameters for get_choices_by_courses.
 451       *
 452       * @return external_function_parameters
 453       * @since Moodle 3.0
 454       */
 455      public static function get_choices_by_courses_parameters() {
 456          return new external_function_parameters (
 457              array(
 458                  'courseids' => new external_multiple_structure(
 459                      new external_value(PARAM_INT, 'course id'), 'Array of course ids', VALUE_DEFAULT, array()
 460                  ),
 461              )
 462          );
 463      }
 464  
 465      /**
 466       * Returns a list of choices in a provided list of courses,
 467       * if no list is provided all choices that the user can view will be returned.
 468       *
 469       * @param array $courseids the course ids
 470       * @return array of choices details
 471       * @since Moodle 3.0
 472       */
 473      public static function get_choices_by_courses($courseids = array()) {
 474          global $CFG;
 475  
 476          $returnedchoices = array();
 477          $warnings = array();
 478  
 479          $params = self::validate_parameters(self::get_choices_by_courses_parameters(), array('courseids' => $courseids));
 480  
 481          $courses = array();
 482          if (empty($params['courseids'])) {
 483              $courses = enrol_get_my_courses();
 484              $params['courseids'] = array_keys($courses);
 485          }
 486  
 487          // Ensure there are courseids to loop through.
 488          if (!empty($params['courseids'])) {
 489  
 490              list($courses, $warnings) = external_util::validate_courses($params['courseids'], $courses);
 491  
 492              // Get the choices in this course, this function checks users visibility permissions.
 493              // We can avoid then additional validate_context calls.
 494              $choices = get_all_instances_in_courses("choice", $courses);
 495              foreach ($choices as $choice) {
 496                  $context = context_module::instance($choice->coursemodule);
 497                  // Entry to return.
 498                  $choicedetails = array();
 499                  // First, we return information that any user can see in the web interface.
 500                  $choicedetails['id'] = $choice->id;
 501                  $choicedetails['coursemodule'] = $choice->coursemodule;
 502                  $choicedetails['course'] = $choice->course;
 503                  $choicedetails['name']  = external_format_string($choice->name, $context->id);
 504                  // Format intro.
 505                  $options = array('noclean' => true);
 506                  list($choicedetails['intro'], $choicedetails['introformat']) =
 507                      external_format_text($choice->intro, $choice->introformat, $context->id, 'mod_choice', 'intro', null, $options);
 508                  $choicedetails['introfiles'] = external_util::get_area_files($context->id, 'mod_choice', 'intro', false, false);
 509  
 510                  if (has_capability('mod/choice:choose', $context)) {
 511                      $choicedetails['publish']  = $choice->publish;
 512                      $choicedetails['showresults']  = $choice->showresults;
 513                      $choicedetails['showpreview']  = $choice->showpreview;
 514                      $choicedetails['timeopen']  = $choice->timeopen;
 515                      $choicedetails['timeclose']  = $choice->timeclose;
 516                      $choicedetails['display']  = $choice->display;
 517                      $choicedetails['allowupdate']  = $choice->allowupdate;
 518                      $choicedetails['allowmultiple']  = $choice->allowmultiple;
 519                      $choicedetails['limitanswers']  = $choice->limitanswers;
 520                      $choicedetails['showunanswered']  = $choice->showunanswered;
 521                      $choicedetails['includeinactive']  = $choice->includeinactive;
 522                      $choicedetails['showavailable']  = $choice->showavailable;
 523                  }
 524  
 525                  if (has_capability('moodle/course:manageactivities', $context)) {
 526                      $choicedetails['timemodified']  = $choice->timemodified;
 527                      $choicedetails['completionsubmit']  = $choice->completionsubmit;
 528                      $choicedetails['section']  = $choice->section;
 529                      $choicedetails['visible']  = $choice->visible;
 530                      $choicedetails['groupmode']  = $choice->groupmode;
 531                      $choicedetails['groupingid']  = $choice->groupingid;
 532                  }
 533                  $returnedchoices[] = $choicedetails;
 534              }
 535          }
 536          $result = array();
 537          $result['choices'] = $returnedchoices;
 538          $result['warnings'] = $warnings;
 539          return $result;
 540      }
 541  
 542      /**
 543       * Describes the mod_choice_get_choices_by_courses return value.
 544       *
 545       * @return external_single_structure
 546       * @since Moodle 3.0
 547       */
 548      public static function get_choices_by_courses_returns() {
 549          return new external_single_structure(
 550              array(
 551                  'choices' => new external_multiple_structure(
 552                      new external_single_structure(
 553                          array(
 554                              'id' => new external_value(PARAM_INT, 'Choice instance id'),
 555                              'coursemodule' => new external_value(PARAM_INT, 'Course module id'),
 556                              'course' => new external_value(PARAM_INT, 'Course id'),
 557                              'name' => new external_value(PARAM_RAW, 'Choice name'),
 558                              'intro' => new external_value(PARAM_RAW, 'The choice intro'),
 559                              'introformat' => new external_format_value('intro'),
 560                              'introfiles' => new external_files('Files in the introduction text', VALUE_OPTIONAL),
 561                              'publish' => new external_value(PARAM_BOOL, 'If choice is published', VALUE_OPTIONAL),
 562                              'showresults' => new external_value(PARAM_INT, '0 never, 1 after answer, 2 after close, 3 always',
 563                                                                  VALUE_OPTIONAL),
 564                              'display' => new external_value(PARAM_INT, 'Display mode (vertical, horizontal)', VALUE_OPTIONAL),
 565                              'allowupdate' => new external_value(PARAM_BOOL, 'Allow update', VALUE_OPTIONAL),
 566                              'allowmultiple' => new external_value(PARAM_BOOL, 'Allow multiple choices', VALUE_OPTIONAL),
 567                              'showunanswered' => new external_value(PARAM_BOOL, 'Show users who not answered yet', VALUE_OPTIONAL),
 568                              'includeinactive' => new external_value(PARAM_BOOL, 'Include inactive users', VALUE_OPTIONAL),
 569                              'limitanswers' => new external_value(PARAM_BOOL, 'Limit unswers', VALUE_OPTIONAL),
 570                              'timeopen' => new external_value(PARAM_INT, 'Date of opening validity', VALUE_OPTIONAL),
 571                              'timeclose' => new external_value(PARAM_INT, 'Date of closing validity', VALUE_OPTIONAL),
 572                              'showpreview' => new external_value(PARAM_BOOL, 'Show preview before timeopen', VALUE_OPTIONAL),
 573                              'timemodified' => new external_value(PARAM_INT, 'Time of last modification', VALUE_OPTIONAL),
 574                              'completionsubmit' => new external_value(PARAM_BOOL, 'Completion on user submission', VALUE_OPTIONAL),
 575                              'showavailable' => new external_value(PARAM_BOOL, 'Show available spaces', VALUE_OPTIONAL),
 576                              'section' => new external_value(PARAM_INT, 'Course section id', VALUE_OPTIONAL),
 577                              'visible' => new external_value(PARAM_BOOL, 'Visible', VALUE_OPTIONAL),
 578                              'groupmode' => new external_value(PARAM_INT, 'Group mode', VALUE_OPTIONAL),
 579                              'groupingid' => new external_value(PARAM_INT, 'Group id', VALUE_OPTIONAL),
 580                          ), 'Choices'
 581                      )
 582                  ),
 583                  'warnings' => new external_warnings(),
 584              )
 585          );
 586      }
 587  
 588      /**
 589       * Describes the parameters for delete_choice_responses.
 590       *
 591       * @return external_function_parameters
 592       * @since Moodle 3.0
 593       */
 594      public static function delete_choice_responses_parameters() {
 595          return new external_function_parameters (
 596              array(
 597                  'choiceid' => new external_value(PARAM_INT, 'choice instance id'),
 598                  'responses' => new external_multiple_structure(
 599                      new external_value(PARAM_INT, 'response id'),
 600                      'Array of response ids, empty for deleting all the current user responses.',
 601                      VALUE_DEFAULT,
 602                      array()
 603                  ),
 604              )
 605          );
 606      }
 607  
 608      /**
 609       * Delete the given submitted responses in a choice
 610       *
 611       * @param int $choiceid the choice instance id
 612       * @param array $responses the response ids,  empty for deleting all the current user responses
 613       * @return array status information and warnings
 614       * @throws moodle_exception
 615       * @since Moodle 3.0
 616       */
 617      public static function delete_choice_responses($choiceid, $responses = array()) {
 618  
 619          $status = false;
 620          $warnings = array();
 621          $params = self::validate_parameters(self::delete_choice_responses_parameters(),
 622                                              array(
 623                                                  'choiceid' => $choiceid,
 624                                                  'responses' => $responses
 625                                              ));
 626  
 627          if (!$choice = choice_get_choice($params['choiceid'])) {
 628              throw new moodle_exception("invalidcoursemodule", "error");
 629          }
 630          list($course, $cm) = get_course_and_cm_from_instance($choice, 'choice');
 631  
 632          $context = context_module::instance($cm->id);
 633          self::validate_context($context);
 634  
 635          require_capability('mod/choice:choose', $context);
 636  
 637          $candeleteall = has_capability('mod/choice:deleteresponses', $context);
 638          if ($candeleteall || $choice->allowupdate) {
 639  
 640              // Check if we can delete our own responses.
 641              if (!$candeleteall) {
 642                  $timenow = time();
 643                  if (!empty($choice->timeclose) && ($timenow > $choice->timeclose)) {
 644                      throw new moodle_exception("expired", "choice", '', userdate($choice->timeclose));
 645                  }
 646              }
 647  
 648              if (empty($params['responses'])) {
 649                  // No responses indicated so delete only my responses.
 650                  $todelete = array_keys(choice_get_my_response($choice));
 651              } else {
 652                  // Fill an array with the responses that can be deleted for this choice.
 653                  if ($candeleteall) {
 654                      // Teacher/managers can delete any.
 655                      $allowedresponses = array_keys(choice_get_all_responses($choice));
 656                  } else {
 657                      // Students can delete only their own responses.
 658                      $allowedresponses = array_keys(choice_get_my_response($choice));
 659                  }
 660  
 661                  $todelete = array();
 662                  foreach ($params['responses'] as $response) {
 663                      if (!in_array($response, $allowedresponses)) {
 664                          $warnings[] = array(
 665                              'item' => 'response',
 666                              'itemid' => $response,
 667                              'warningcode' => 'nopermissions',
 668                              'message' => 'Invalid response id, the response does not exist or you are not allowed to delete it.'
 669                          );
 670                      } else {
 671                          $todelete[] = $response;
 672                      }
 673                  }
 674              }
 675  
 676              $status = choice_delete_responses($todelete, $choice, $cm, $course);
 677          } else {
 678              // The user requires the capability to delete responses.
 679              throw new required_capability_exception($context, 'mod/choice:deleteresponses', 'nopermissions', '');
 680          }
 681  
 682          return array(
 683              'status' => $status,
 684              'warnings' => $warnings
 685          );
 686      }
 687  
 688      /**
 689       * Describes the delete_choice_responses return value.
 690       *
 691       * @return external_multiple_structure
 692       * @since Moodle 3.0
 693       */
 694      public static function delete_choice_responses_returns() {
 695          return new external_single_structure(
 696              array(
 697                  'status' => new external_value(PARAM_BOOL, 'status, true if everything went right'),
 698                  'warnings' => new external_warnings(),
 699              )
 700          );
 701      }
 702  
 703  }