[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/mod/feedback/ -> lib.php (source)

   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   * Library of functions and constants for module feedback
  19   * includes the main-part of feedback-functions
  20   *
  21   * @package mod_feedback
  22   * @copyright Andreas Grabs
  23   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  /** Include eventslib.php */
  27  require_once($CFG->libdir.'/eventslib.php');
  28  /** Include calendar/lib.php */
  29  require_once($CFG->dirroot.'/calendar/lib.php');
  30  // Include forms lib.
  31  require_once($CFG->libdir.'/formslib.php');
  32  
  33  define('FEEDBACK_ANONYMOUS_YES', 1);
  34  define('FEEDBACK_ANONYMOUS_NO', 2);
  35  define('FEEDBACK_MIN_ANONYMOUS_COUNT_IN_GROUP', 2);
  36  define('FEEDBACK_DECIMAL', '.');
  37  define('FEEDBACK_THOUSAND', ',');
  38  define('FEEDBACK_RESETFORM_RESET', 'feedback_reset_data_');
  39  define('FEEDBACK_RESETFORM_DROP', 'feedback_drop_feedback_');
  40  define('FEEDBACK_MAX_PIX_LENGTH', '400'); //max. Breite des grafischen Balkens in der Auswertung
  41  define('FEEDBACK_DEFAULT_PAGE_COUNT', 20);
  42  
  43  /**
  44   * Returns all other caps used in module.
  45   *
  46   * @return array
  47   */
  48  function feedback_get_extra_capabilities() {
  49      return array('moodle/site:accessallgroups');
  50  }
  51  
  52  /**
  53   * @uses FEATURE_GROUPS
  54   * @uses FEATURE_GROUPINGS
  55   * @uses FEATURE_MOD_INTRO
  56   * @uses FEATURE_COMPLETION_TRACKS_VIEWS
  57   * @uses FEATURE_GRADE_HAS_GRADE
  58   * @uses FEATURE_GRADE_OUTCOMES
  59   * @param string $feature FEATURE_xx constant for requested feature
  60   * @return mixed True if module supports feature, null if doesn't know
  61   */
  62  function feedback_supports($feature) {
  63      switch($feature) {
  64          case FEATURE_GROUPS:                  return true;
  65          case FEATURE_GROUPINGS:               return true;
  66          case FEATURE_MOD_INTRO:               return true;
  67          case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
  68          case FEATURE_COMPLETION_HAS_RULES:    return true;
  69          case FEATURE_GRADE_HAS_GRADE:         return false;
  70          case FEATURE_GRADE_OUTCOMES:          return false;
  71          case FEATURE_BACKUP_MOODLE2:          return true;
  72          case FEATURE_SHOW_DESCRIPTION:        return true;
  73  
  74          default: return null;
  75      }
  76  }
  77  
  78  /**
  79   * this will create a new instance and return the id number
  80   * of the new instance.
  81   *
  82   * @global object
  83   * @param object $feedback the object given by mod_feedback_mod_form
  84   * @return int
  85   */
  86  function feedback_add_instance($feedback) {
  87      global $DB;
  88  
  89      $feedback->timemodified = time();
  90      $feedback->id = '';
  91  
  92      if (empty($feedback->site_after_submit)) {
  93          $feedback->site_after_submit = '';
  94      }
  95  
  96      //saving the feedback in db
  97      $feedbackid = $DB->insert_record("feedback", $feedback);
  98  
  99      $feedback->id = $feedbackid;
 100  
 101      feedback_set_events($feedback);
 102  
 103      if (!isset($feedback->coursemodule)) {
 104          $cm = get_coursemodule_from_id('feedback', $feedback->id);
 105          $feedback->coursemodule = $cm->id;
 106      }
 107      $context = context_module::instance($feedback->coursemodule);
 108  
 109      $editoroptions = feedback_get_editor_options();
 110  
 111      // process the custom wysiwyg editor in page_after_submit
 112      if ($draftitemid = $feedback->page_after_submit_editor['itemid']) {
 113          $feedback->page_after_submit = file_save_draft_area_files($draftitemid, $context->id,
 114                                                      'mod_feedback', 'page_after_submit',
 115                                                      0, $editoroptions,
 116                                                      $feedback->page_after_submit_editor['text']);
 117  
 118          $feedback->page_after_submitformat = $feedback->page_after_submit_editor['format'];
 119      }
 120      $DB->update_record('feedback', $feedback);
 121  
 122      return $feedbackid;
 123  }
 124  
 125  /**
 126   * this will update a given instance
 127   *
 128   * @global object
 129   * @param object $feedback the object given by mod_feedback_mod_form
 130   * @return boolean
 131   */
 132  function feedback_update_instance($feedback) {
 133      global $DB;
 134  
 135      $feedback->timemodified = time();
 136      $feedback->id = $feedback->instance;
 137  
 138      if (empty($feedback->site_after_submit)) {
 139          $feedback->site_after_submit = '';
 140      }
 141  
 142      //save the feedback into the db
 143      $DB->update_record("feedback", $feedback);
 144  
 145      //create or update the new events
 146      feedback_set_events($feedback);
 147  
 148      $context = context_module::instance($feedback->coursemodule);
 149  
 150      $editoroptions = feedback_get_editor_options();
 151  
 152      // process the custom wysiwyg editor in page_after_submit
 153      if ($draftitemid = $feedback->page_after_submit_editor['itemid']) {
 154          $feedback->page_after_submit = file_save_draft_area_files($draftitemid, $context->id,
 155                                                      'mod_feedback', 'page_after_submit',
 156                                                      0, $editoroptions,
 157                                                      $feedback->page_after_submit_editor['text']);
 158  
 159          $feedback->page_after_submitformat = $feedback->page_after_submit_editor['format'];
 160      }
 161      $DB->update_record('feedback', $feedback);
 162  
 163      return true;
 164  }
 165  
 166  /**
 167   * Serves the files included in feedback items like label. Implements needed access control ;-)
 168   *
 169   * There are two situations in general where the files will be sent.
 170   * 1) filearea = item, 2) filearea = template
 171   *
 172   * @package  mod_feedback
 173   * @category files
 174   * @param stdClass $course course object
 175   * @param stdClass $cm course module object
 176   * @param stdClass $context context object
 177   * @param string $filearea file area
 178   * @param array $args extra arguments
 179   * @param bool $forcedownload whether or not force download
 180   * @param array $options additional options affecting the file serving
 181   * @return bool false if file not found, does not return if found - justsend the file
 182   */
 183  function feedback_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
 184      global $CFG, $DB;
 185  
 186      if ($filearea === 'item' or $filearea === 'template') {
 187          $itemid = (int)array_shift($args);
 188          //get the item what includes the file
 189          if (!$item = $DB->get_record('feedback_item', array('id'=>$itemid))) {
 190              return false;
 191          }
 192          $feedbackid = $item->feedback;
 193          $templateid = $item->template;
 194      }
 195  
 196      if ($filearea === 'page_after_submit' or $filearea === 'item') {
 197          if (! $feedback = $DB->get_record("feedback", array("id"=>$cm->instance))) {
 198              return false;
 199          }
 200  
 201          $feedbackid = $feedback->id;
 202  
 203          //if the filearea is "item" so we check the permissions like view/complete the feedback
 204          $canload = false;
 205          //first check whether the user has the complete capability
 206          if (has_capability('mod/feedback:complete', $context)) {
 207              $canload = true;
 208          }
 209  
 210          //now we check whether the user has the view capability
 211          if (has_capability('mod/feedback:view', $context)) {
 212              $canload = true;
 213          }
 214  
 215          //if the feedback is on frontpage and anonymous and the fullanonymous is allowed
 216          //so the file can be loaded too.
 217          if (isset($CFG->feedback_allowfullanonymous)
 218                      AND $CFG->feedback_allowfullanonymous
 219                      AND $course->id == SITEID
 220                      AND $feedback->anonymous == FEEDBACK_ANONYMOUS_YES ) {
 221              $canload = true;
 222          }
 223  
 224          if (!$canload) {
 225              return false;
 226          }
 227      } else if ($filearea === 'template') { //now we check files in templates
 228          if (!$template = $DB->get_record('feedback_template', array('id'=>$templateid))) {
 229              return false;
 230          }
 231  
 232          //if the file is not public so the capability edititems has to be there
 233          if (!$template->ispublic) {
 234              if (!has_capability('mod/feedback:edititems', $context)) {
 235                  return false;
 236              }
 237          } else { //on public templates, at least the user has to be logged in
 238              if (!isloggedin()) {
 239                  return false;
 240              }
 241          }
 242      } else {
 243          return false;
 244      }
 245  
 246      if ($context->contextlevel == CONTEXT_MODULE) {
 247          if ($filearea !== 'item' and $filearea !== 'page_after_submit') {
 248              return false;
 249          }
 250      }
 251  
 252      if ($context->contextlevel == CONTEXT_COURSE || $context->contextlevel == CONTEXT_SYSTEM) {
 253          if ($filearea !== 'template') {
 254              return false;
 255          }
 256      }
 257  
 258      $relativepath = implode('/', $args);
 259      if ($filearea === 'page_after_submit') {
 260          $fullpath = "/{$context->id}/mod_feedback/$filearea/$relativepath";
 261      } else {
 262          $fullpath = "/{$context->id}/mod_feedback/$filearea/{$item->id}/$relativepath";
 263      }
 264  
 265      $fs = get_file_storage();
 266  
 267      if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
 268          return false;
 269      }
 270  
 271      // finally send the file
 272      send_stored_file($file, 0, 0, true, $options); // download MUST be forced - security!
 273  
 274      return false;
 275  }
 276  
 277  /**
 278   * this will delete a given instance.
 279   * all referenced data also will be deleted
 280   *
 281   * @global object
 282   * @param int $id the instanceid of feedback
 283   * @return boolean
 284   */
 285  function feedback_delete_instance($id) {
 286      global $DB;
 287  
 288      //get all referenced items
 289      $feedbackitems = $DB->get_records('feedback_item', array('feedback'=>$id));
 290  
 291      //deleting all referenced items and values
 292      if (is_array($feedbackitems)) {
 293          foreach ($feedbackitems as $feedbackitem) {
 294              $DB->delete_records("feedback_value", array("item"=>$feedbackitem->id));
 295              $DB->delete_records("feedback_valuetmp", array("item"=>$feedbackitem->id));
 296          }
 297          if ($delitems = $DB->get_records("feedback_item", array("feedback"=>$id))) {
 298              foreach ($delitems as $delitem) {
 299                  feedback_delete_item($delitem->id, false);
 300              }
 301          }
 302      }
 303  
 304      //deleting the referenced tracking data
 305      $DB->delete_records('feedback_tracking', array('feedback'=>$id));
 306  
 307      //deleting the completeds
 308      $DB->delete_records("feedback_completed", array("feedback"=>$id));
 309  
 310      //deleting the unfinished completeds
 311      $DB->delete_records("feedback_completedtmp", array("feedback"=>$id));
 312  
 313      //deleting old events
 314      $DB->delete_records('event', array('modulename'=>'feedback', 'instance'=>$id));
 315      return $DB->delete_records("feedback", array("id"=>$id));
 316  }
 317  
 318  /**
 319   * this is called after deleting all instances if the course will be deleted.
 320   * only templates have to be deleted
 321   *
 322   * @global object
 323   * @param object $course
 324   * @return boolean
 325   */
 326  function feedback_delete_course($course) {
 327      global $DB;
 328  
 329      //delete all templates of given course
 330      return $DB->delete_records('feedback_template', array('course'=>$course->id));
 331  }
 332  
 333  /**
 334   * Return a small object with summary information about what a
 335   * user has done with a given particular instance of this module
 336   * Used for user activity reports.
 337   * $return->time = the time they did it
 338   * $return->info = a short text description
 339   *
 340   * @param object $course
 341   * @param object $user
 342   * @param object $mod
 343   * @param object $feedback
 344   * @return object
 345   */
 346  function feedback_user_outline($course, $user, $mod, $feedback) {
 347      return null;
 348  }
 349  
 350  /**
 351   * Returns all users who has completed a specified feedback since a given time
 352   * many thanks to Manolescu Dorel, who contributed these two functions
 353   *
 354   * @global object
 355   * @global object
 356   * @global object
 357   * @global object
 358   * @uses CONTEXT_MODULE
 359   * @param array $activities Passed by reference
 360   * @param int $index Passed by reference
 361   * @param int $timemodified Timestamp
 362   * @param int $courseid
 363   * @param int $cmid
 364   * @param int $userid
 365   * @param int $groupid
 366   * @return void
 367   */
 368  function feedback_get_recent_mod_activity(&$activities, &$index,
 369                                            $timemodified, $courseid,
 370                                            $cmid, $userid="", $groupid="") {
 371  
 372      global $CFG, $COURSE, $USER, $DB;
 373  
 374      if ($COURSE->id == $courseid) {
 375          $course = $COURSE;
 376      } else {
 377          $course = $DB->get_record('course', array('id'=>$courseid));
 378      }
 379  
 380      $modinfo = get_fast_modinfo($course);
 381  
 382      $cm = $modinfo->cms[$cmid];
 383  
 384      $sqlargs = array();
 385  
 386      $userfields = user_picture::fields('u', null, 'useridagain');
 387      $sql = " SELECT fk . * , fc . * , $userfields
 388                  FROM {feedback_completed} fc
 389                      JOIN {feedback} fk ON fk.id = fc.feedback
 390                      JOIN {user} u ON u.id = fc.userid ";
 391  
 392      if ($groupid) {
 393          $sql .= " JOIN {groups_members} gm ON  gm.userid=u.id ";
 394      }
 395  
 396      $sql .= " WHERE fc.timemodified > ? AND fk.id = ? ";
 397      $sqlargs[] = $timemodified;
 398      $sqlargs[] = $cm->instance;
 399  
 400      if ($userid) {
 401          $sql .= " AND u.id = ? ";
 402          $sqlargs[] = $userid;
 403      }
 404  
 405      if ($groupid) {
 406          $sql .= " AND gm.groupid = ? ";
 407          $sqlargs[] = $groupid;
 408      }
 409  
 410      if (!$feedbackitems = $DB->get_records_sql($sql, $sqlargs)) {
 411          return;
 412      }
 413  
 414      $cm_context = context_module::instance($cm->id);
 415  
 416      if (!has_capability('mod/feedback:view', $cm_context)) {
 417          return;
 418      }
 419  
 420      $accessallgroups = has_capability('moodle/site:accessallgroups', $cm_context);
 421      $viewfullnames   = has_capability('moodle/site:viewfullnames', $cm_context);
 422      $groupmode       = groups_get_activity_groupmode($cm, $course);
 423  
 424      $aname = format_string($cm->name, true);
 425      foreach ($feedbackitems as $feedbackitem) {
 426          if ($feedbackitem->userid != $USER->id) {
 427  
 428              if ($groupmode == SEPARATEGROUPS and !$accessallgroups) {
 429                  $usersgroups = groups_get_all_groups($course->id,
 430                                                       $feedbackitem->userid,
 431                                                       $cm->groupingid);
 432                  if (!is_array($usersgroups)) {
 433                      continue;
 434                  }
 435                  $usersgroups = array_keys($usersgroups);
 436                  $intersect = array_intersect($usersgroups, $modinfo->get_groups($cm->groupingid));
 437                  if (empty($intersect)) {
 438                      continue;
 439                  }
 440              }
 441          }
 442  
 443          $tmpactivity = new stdClass();
 444  
 445          $tmpactivity->type      = 'feedback';
 446          $tmpactivity->cmid      = $cm->id;
 447          $tmpactivity->name      = $aname;
 448          $tmpactivity->sectionnum= $cm->sectionnum;
 449          $tmpactivity->timestamp = $feedbackitem->timemodified;
 450  
 451          $tmpactivity->content = new stdClass();
 452          $tmpactivity->content->feedbackid = $feedbackitem->id;
 453          $tmpactivity->content->feedbackuserid = $feedbackitem->userid;
 454  
 455          $tmpactivity->user = user_picture::unalias($feedbackitem, null, 'useridagain');
 456          $tmpactivity->user->fullname = fullname($feedbackitem, $viewfullnames);
 457  
 458          $activities[$index++] = $tmpactivity;
 459      }
 460  
 461      return;
 462  }
 463  
 464  /**
 465   * Prints all users who has completed a specified feedback since a given time
 466   * many thanks to Manolescu Dorel, who contributed these two functions
 467   *
 468   * @global object
 469   * @param object $activity
 470   * @param int $courseid
 471   * @param string $detail
 472   * @param array $modnames
 473   * @return void Output is echo'd
 474   */
 475  function feedback_print_recent_mod_activity($activity, $courseid, $detail, $modnames) {
 476      global $CFG, $OUTPUT;
 477  
 478      echo '<table border="0" cellpadding="3" cellspacing="0" class="forum-recent">';
 479  
 480      echo "<tr><td class=\"userpicture\" valign=\"top\">";
 481      echo $OUTPUT->user_picture($activity->user, array('courseid'=>$courseid));
 482      echo "</td><td>";
 483  
 484      if ($detail) {
 485          $modname = $modnames[$activity->type];
 486          echo '<div class="title">';
 487          echo "<img src=\"" . $OUTPUT->pix_url('icon', $activity->type) . "\" ".
 488               "class=\"icon\" alt=\"$modname\" />";
 489          echo "<a href=\"$CFG->wwwroot/mod/feedback/view.php?id={$activity->cmid}\">{$activity->name}</a>";
 490          echo '</div>';
 491      }
 492  
 493      echo '<div class="title">';
 494      echo '</div>';
 495  
 496      echo '<div class="user">';
 497      echo "<a href=\"$CFG->wwwroot/user/view.php?id={$activity->user->id}&amp;course=$courseid\">"
 498           ."{$activity->user->fullname}</a> - ".userdate($activity->timestamp);
 499      echo '</div>';
 500  
 501      echo "</td></tr></table>";
 502  
 503      return;
 504  }
 505  
 506  /**
 507   * Obtains the automatic completion state for this feedback based on the condition
 508   * in feedback settings.
 509   *
 510   * @param object $course Course
 511   * @param object $cm Course-module
 512   * @param int $userid User ID
 513   * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)
 514   * @return bool True if completed, false if not, $type if conditions not set.
 515   */
 516  function feedback_get_completion_state($course, $cm, $userid, $type) {
 517      global $CFG, $DB;
 518  
 519      // Get feedback details
 520      $feedback = $DB->get_record('feedback', array('id'=>$cm->instance), '*', MUST_EXIST);
 521  
 522      // If completion option is enabled, evaluate it and return true/false
 523      if ($feedback->completionsubmit) {
 524          $params = array('userid'=>$userid, 'feedback'=>$feedback->id);
 525          return $DB->record_exists('feedback_tracking', $params);
 526      } else {
 527          // Completion option is not enabled so just return $type
 528          return $type;
 529      }
 530  }
 531  
 532  
 533  /**
 534   * Print a detailed representation of what a  user has done with
 535   * a given particular instance of this module, for user activity reports.
 536   *
 537   * @param object $course
 538   * @param object $user
 539   * @param object $mod
 540   * @param object $feedback
 541   * @return bool
 542   */
 543  function feedback_user_complete($course, $user, $mod, $feedback) {
 544      return true;
 545  }
 546  
 547  /**
 548   * @return bool true
 549   */
 550  function feedback_cron () {
 551      return true;
 552  }
 553  
 554  /**
 555   * @return bool false
 556   */
 557  function feedback_scale_used ($feedbackid, $scaleid) {
 558      return false;
 559  }
 560  
 561  /**
 562   * Checks if scale is being used by any instance of feedback
 563   *
 564   * This is used to find out if scale used anywhere
 565   * @param $scaleid int
 566   * @return boolean True if the scale is used by any assignment
 567   */
 568  function feedback_scale_used_anywhere($scaleid) {
 569      return false;
 570  }
 571  
 572  /**
 573   * List the actions that correspond to a view of this module.
 574   * This is used by the participation report.
 575   *
 576   * Note: This is not used by new logging system. Event with
 577   *       crud = 'r' and edulevel = LEVEL_PARTICIPATING will
 578   *       be considered as view action.
 579   *
 580   * @return array
 581   */
 582  function feedback_get_view_actions() {
 583      return array('view', 'view all');
 584  }
 585  
 586  /**
 587   * List the actions that correspond to a post of this module.
 588   * This is used by the participation report.
 589   *
 590   * Note: This is not used by new logging system. Event with
 591   *       crud = ('c' || 'u' || 'd') and edulevel = LEVEL_PARTICIPATING
 592   *       will be considered as post action.
 593   *
 594   * @return array
 595   */
 596  function feedback_get_post_actions() {
 597      return array('submit');
 598  }
 599  
 600  /**
 601   * This function is used by the reset_course_userdata function in moodlelib.
 602   * This function will remove all responses from the specified feedback
 603   * and clean up any related data.
 604   *
 605   * @global object
 606   * @global object
 607   * @uses FEEDBACK_RESETFORM_RESET
 608   * @uses FEEDBACK_RESETFORM_DROP
 609   * @param object $data the data submitted from the reset course.
 610   * @return array status array
 611   */
 612  function feedback_reset_userdata($data) {
 613      global $CFG, $DB;
 614  
 615      $resetfeedbacks = array();
 616      $dropfeedbacks = array();
 617      $status = array();
 618      $componentstr = get_string('modulenameplural', 'feedback');
 619  
 620      //get the relevant entries from $data
 621      foreach ($data as $key => $value) {
 622          switch(true) {
 623              case substr($key, 0, strlen(FEEDBACK_RESETFORM_RESET)) == FEEDBACK_RESETFORM_RESET:
 624                  if ($value == 1) {
 625                      $templist = explode('_', $key);
 626                      if (isset($templist[3])) {
 627                          $resetfeedbacks[] = intval($templist[3]);
 628                      }
 629                  }
 630              break;
 631              case substr($key, 0, strlen(FEEDBACK_RESETFORM_DROP)) == FEEDBACK_RESETFORM_DROP:
 632                  if ($value == 1) {
 633                      $templist = explode('_', $key);
 634                      if (isset($templist[3])) {
 635                          $dropfeedbacks[] = intval($templist[3]);
 636                      }
 637                  }
 638              break;
 639          }
 640      }
 641  
 642      //reset the selected feedbacks
 643      foreach ($resetfeedbacks as $id) {
 644          $feedback = $DB->get_record('feedback', array('id'=>$id));
 645          feedback_delete_all_completeds($id);
 646          $status[] = array('component'=>$componentstr.':'.$feedback->name,
 647                          'item'=>get_string('resetting_data', 'feedback'),
 648                          'error'=>false);
 649      }
 650  
 651      return $status;
 652  }
 653  
 654  /**
 655   * Called by course/reset.php
 656   *
 657   * @global object
 658   * @uses FEEDBACK_RESETFORM_RESET
 659   * @param object $mform form passed by reference
 660   */
 661  function feedback_reset_course_form_definition(&$mform) {
 662      global $COURSE, $DB;
 663  
 664      $mform->addElement('header', 'feedbackheader', get_string('modulenameplural', 'feedback'));
 665  
 666      if (!$feedbacks = $DB->get_records('feedback', array('course'=>$COURSE->id), 'name')) {
 667          return;
 668      }
 669  
 670      $mform->addElement('static', 'hint', get_string('resetting_data', 'feedback'));
 671      foreach ($feedbacks as $feedback) {
 672          $mform->addElement('checkbox', FEEDBACK_RESETFORM_RESET.$feedback->id, $feedback->name);
 673      }
 674  }
 675  
 676  /**
 677   * Course reset form defaults.
 678   *
 679   * @global object
 680   * @uses FEEDBACK_RESETFORM_RESET
 681   * @param object $course
 682   */
 683  function feedback_reset_course_form_defaults($course) {
 684      global $DB;
 685  
 686      $return = array();
 687      if (!$feedbacks = $DB->get_records('feedback', array('course'=>$course->id), 'name')) {
 688          return;
 689      }
 690      foreach ($feedbacks as $feedback) {
 691          $return[FEEDBACK_RESETFORM_RESET.$feedback->id] = true;
 692      }
 693      return $return;
 694  }
 695  
 696  /**
 697   * Called by course/reset.php and shows the formdata by coursereset.
 698   * it prints checkboxes for each feedback available at the given course
 699   * there are two checkboxes:
 700   * 1) delete userdata and keep the feedback
 701   * 2) delete userdata and drop the feedback
 702   *
 703   * @global object
 704   * @uses FEEDBACK_RESETFORM_RESET
 705   * @uses FEEDBACK_RESETFORM_DROP
 706   * @param object $course
 707   * @return void
 708   */
 709  function feedback_reset_course_form($course) {
 710      global $DB, $OUTPUT;
 711  
 712      echo get_string('resetting_feedbacks', 'feedback'); echo ':<br />';
 713      if (!$feedbacks = $DB->get_records('feedback', array('course'=>$course->id), 'name')) {
 714          return;
 715      }
 716  
 717      foreach ($feedbacks as $feedback) {
 718          echo '<p>';
 719          echo get_string('name', 'feedback').': '.$feedback->name.'<br />';
 720          echo html_writer::checkbox(FEEDBACK_RESETFORM_RESET.$feedback->id,
 721                                  1, true,
 722                                  get_string('resetting_data', 'feedback'));
 723          echo '<br />';
 724          echo html_writer::checkbox(FEEDBACK_RESETFORM_DROP.$feedback->id,
 725                                  1, false,
 726                                  get_string('drop_feedback', 'feedback'));
 727          echo '</p>';
 728      }
 729  }
 730  
 731  /**
 732   * This gets an array with default options for the editor
 733   *
 734   * @return array the options
 735   */
 736  function feedback_get_editor_options() {
 737      return array('maxfiles' => EDITOR_UNLIMITED_FILES,
 738                  'trusttext'=>true);
 739  }
 740  
 741  /**
 742   * This creates new events given as timeopen and closeopen by $feedback.
 743   *
 744   * @global object
 745   * @param object $feedback
 746   * @return void
 747   */
 748  function feedback_set_events($feedback) {
 749      global $DB;
 750  
 751      // adding the feedback to the eventtable (I have seen this at quiz-module)
 752      $DB->delete_records('event', array('modulename'=>'feedback', 'instance'=>$feedback->id));
 753  
 754      if (!isset($feedback->coursemodule)) {
 755          $cm = get_coursemodule_from_id('feedback', $feedback->id);
 756          $feedback->coursemodule = $cm->id;
 757      }
 758  
 759      // the open-event
 760      if ($feedback->timeopen > 0) {
 761          $event = new stdClass();
 762          $event->name         = get_string('start', 'feedback').' '.$feedback->name;
 763          $event->description  = format_module_intro('feedback', $feedback, $feedback->coursemodule);
 764          $event->courseid     = $feedback->course;
 765          $event->groupid      = 0;
 766          $event->userid       = 0;
 767          $event->modulename   = 'feedback';
 768          $event->instance     = $feedback->id;
 769          $event->eventtype    = 'open';
 770          $event->timestart    = $feedback->timeopen;
 771          $event->visible      = instance_is_visible('feedback', $feedback);
 772          if ($feedback->timeclose > 0) {
 773              $event->timeduration = ($feedback->timeclose - $feedback->timeopen);
 774          } else {
 775              $event->timeduration = 0;
 776          }
 777  
 778          calendar_event::create($event);
 779      }
 780  
 781      // the close-event
 782      if ($feedback->timeclose > 0) {
 783          $event = new stdClass();
 784          $event->name         = get_string('stop', 'feedback').' '.$feedback->name;
 785          $event->description  = format_module_intro('feedback', $feedback, $feedback->coursemodule);
 786          $event->courseid     = $feedback->course;
 787          $event->groupid      = 0;
 788          $event->userid       = 0;
 789          $event->modulename   = 'feedback';
 790          $event->instance     = $feedback->id;
 791          $event->eventtype    = 'close';
 792          $event->timestart    = $feedback->timeclose;
 793          $event->visible      = instance_is_visible('feedback', $feedback);
 794          $event->timeduration = 0;
 795  
 796          calendar_event::create($event);
 797      }
 798  }
 799  
 800  /**
 801   * this function is called by {@link feedback_delete_userdata()}
 802   * it drops the feedback-instance from the course_module table
 803   *
 804   * @global object
 805   * @param int $id the id from the coursemodule
 806   * @return boolean
 807   */
 808  function feedback_delete_course_module($id) {
 809      global $DB;
 810  
 811      if (!$cm = $DB->get_record('course_modules', array('id'=>$id))) {
 812          return true;
 813      }
 814      return $DB->delete_records('course_modules', array('id'=>$cm->id));
 815  }
 816  
 817  
 818  
 819  ////////////////////////////////////////////////
 820  //functions to handle capabilities
 821  ////////////////////////////////////////////////
 822  
 823  /**
 824   * returns the context-id related to the given coursemodule-id
 825   *
 826   * @staticvar object $context
 827   * @param int $cmid the coursemodule-id
 828   * @return object $context
 829   */
 830  function feedback_get_context($cmid) {
 831      static $context;
 832  
 833      if (isset($context)) {
 834          return $context;
 835      }
 836  
 837      $context = context_module::instance($cmid);
 838      return $context;
 839  }
 840  
 841  /**
 842   *  returns true if the current role is faked by switching role feature
 843   *
 844   * @global object
 845   * @return boolean
 846   */
 847  function feedback_check_is_switchrole() {
 848      global $USER;
 849      if (isset($USER->switchrole) AND
 850              is_array($USER->switchrole) AND
 851              count($USER->switchrole) > 0) {
 852  
 853          return true;
 854      }
 855      return false;
 856  }
 857  
 858  /**
 859   * count users which have not completed the feedback
 860   *
 861   * @global object
 862   * @uses CONTEXT_MODULE
 863   * @param cm_info $cm Course-module object
 864   * @param int $group single groupid
 865   * @param string $sort
 866   * @param int $startpage
 867   * @param int $pagecount
 868   * @return object the userrecords
 869   */
 870  function feedback_get_incomplete_users(cm_info $cm,
 871                                         $group = false,
 872                                         $sort = '',
 873                                         $startpage = false,
 874                                         $pagecount = false) {
 875  
 876      global $DB;
 877  
 878      $context = context_module::instance($cm->id);
 879  
 880      //first get all user who can complete this feedback
 881      $cap = 'mod/feedback:complete';
 882      $fields = 'u.id, u.username';
 883      if (!$allusers = get_users_by_capability($context,
 884                                              $cap,
 885                                              $fields,
 886                                              $sort,
 887                                              '',
 888                                              '',
 889                                              $group,
 890                                              '',
 891                                              true)) {
 892          return false;
 893      }
 894      // Filter users that are not in the correct group/grouping.
 895      $info = new \core_availability\info_module($cm);
 896      $allusers = $info->filter_user_list($allusers);
 897  
 898      $allusers = array_keys($allusers);
 899  
 900      //now get all completeds
 901      $params = array('feedback'=>$cm->instance);
 902      if (!$completedusers = $DB->get_records_menu('feedback_completed', $params, '', 'userid,id')) {
 903          return $allusers;
 904      }
 905      $completedusers = array_keys($completedusers);
 906  
 907      //now strike all completedusers from allusers
 908      $allusers = array_diff($allusers, $completedusers);
 909  
 910      //for paging I use array_slice()
 911      if ($startpage !== false AND $pagecount !== false) {
 912          $allusers = array_slice($allusers, $startpage, $pagecount);
 913      }
 914  
 915      return $allusers;
 916  }
 917  
 918  /**
 919   * count users which have not completed the feedback
 920   *
 921   * @global object
 922   * @param object $cm
 923   * @param int $group single groupid
 924   * @return int count of userrecords
 925   */
 926  function feedback_count_incomplete_users($cm, $group = false) {
 927      if ($allusers = feedback_get_incomplete_users($cm, $group)) {
 928          return count($allusers);
 929      }
 930      return 0;
 931  }
 932  
 933  /**
 934   * count users which have completed a feedback
 935   *
 936   * @global object
 937   * @uses FEEDBACK_ANONYMOUS_NO
 938   * @param object $cm
 939   * @param int $group single groupid
 940   * @return int count of userrecords
 941   */
 942  function feedback_count_complete_users($cm, $group = false) {
 943      global $DB;
 944  
 945      $params = array(FEEDBACK_ANONYMOUS_NO, $cm->instance);
 946  
 947      $fromgroup = '';
 948      $wheregroup = '';
 949      if ($group) {
 950          $fromgroup = ', {groups_members} g';
 951          $wheregroup = ' AND g.groupid = ? AND g.userid = c.userid';
 952          $params[] = $group;
 953      }
 954  
 955      $sql = 'SELECT COUNT(u.id) FROM {user} u, {feedback_completed} c'.$fromgroup.'
 956                WHERE anonymous_response = ? AND u.id = c.userid AND c.feedback = ?
 957                '.$wheregroup;
 958  
 959      return $DB->count_records_sql($sql, $params);
 960  
 961  }
 962  
 963  /**
 964   * get users which have completed a feedback
 965   *
 966   * @global object
 967   * @uses CONTEXT_MODULE
 968   * @uses FEEDBACK_ANONYMOUS_NO
 969   * @param object $cm
 970   * @param int $group single groupid
 971   * @param string $where a sql where condition (must end with " AND ")
 972   * @param array parameters used in $where
 973   * @param string $sort a table field
 974   * @param int $startpage
 975   * @param int $pagecount
 976   * @return object the userrecords
 977   */
 978  function feedback_get_complete_users($cm,
 979                                       $group = false,
 980                                       $where = '',
 981                                       array $params = null,
 982                                       $sort = '',
 983                                       $startpage = false,
 984                                       $pagecount = false) {
 985  
 986      global $DB;
 987  
 988      $context = context_module::instance($cm->id);
 989  
 990      $params = (array)$params;
 991  
 992      $params['anon'] = FEEDBACK_ANONYMOUS_NO;
 993      $params['instance'] = $cm->instance;
 994  
 995      $fromgroup = '';
 996      $wheregroup = '';
 997      if ($group) {
 998          $fromgroup = ', {groups_members} g';
 999          $wheregroup = ' AND g.groupid = :group AND g.userid = c.userid';
1000          $params['group'] = $group;
1001      }
1002  
1003      if ($sort) {
1004          $sortsql = ' ORDER BY '.$sort;
1005      } else {
1006          $sortsql = '';
1007      }
1008  
1009      $ufields = user_picture::fields('u');
1010      $sql = 'SELECT DISTINCT '.$ufields.', c.timemodified as completed_timemodified
1011              FROM {user} u, {feedback_completed} c '.$fromgroup.'
1012              WHERE '.$where.' anonymous_response = :anon
1013                  AND u.id = c.userid
1014                  AND c.feedback = :instance
1015                '.$wheregroup.$sortsql;
1016  
1017      if ($startpage === false OR $pagecount === false) {
1018          $startpage = false;
1019          $pagecount = false;
1020      }
1021      return $DB->get_records_sql($sql, $params, $startpage, $pagecount);
1022  }
1023  
1024  /**
1025   * get users which have the viewreports-capability
1026   *
1027   * @uses CONTEXT_MODULE
1028   * @param int $cmid
1029   * @param mixed $groups single groupid or array of groupids - group(s) user is in
1030   * @return object the userrecords
1031   */
1032  function feedback_get_viewreports_users($cmid, $groups = false) {
1033  
1034      $context = context_module::instance($cmid);
1035  
1036      //description of the call below:
1037      //get_users_by_capability($context, $capability, $fields='', $sort='', $limitfrom='',
1038      //                          $limitnum='', $groups='', $exceptions='', $doanything=true)
1039      return get_users_by_capability($context,
1040                              'mod/feedback:viewreports',
1041                              '',
1042                              'lastname',
1043                              '',
1044                              '',
1045                              $groups,
1046                              '',
1047                              false);
1048  }
1049  
1050  /**
1051   * get users which have the receivemail-capability
1052   *
1053   * @uses CONTEXT_MODULE
1054   * @param int $cmid
1055   * @param mixed $groups single groupid or array of groupids - group(s) user is in
1056   * @return object the userrecords
1057   */
1058  function feedback_get_receivemail_users($cmid, $groups = false) {
1059  
1060      $context = context_module::instance($cmid);
1061  
1062      //description of the call below:
1063      //get_users_by_capability($context, $capability, $fields='', $sort='', $limitfrom='',
1064      //                          $limitnum='', $groups='', $exceptions='', $doanything=true)
1065      return get_users_by_capability($context,
1066                              'mod/feedback:receivemail',
1067                              '',
1068                              'lastname',
1069                              '',
1070                              '',
1071                              $groups,
1072                              '',
1073                              false);
1074  }
1075  
1076  ////////////////////////////////////////////////
1077  //functions to handle the templates
1078  ////////////////////////////////////////////////
1079  ////////////////////////////////////////////////
1080  
1081  /**
1082   * creates a new template-record.
1083   *
1084   * @global object
1085   * @param int $courseid
1086   * @param string $name the name of template shown in the templatelist
1087   * @param int $ispublic 0:privat 1:public
1088   * @return int the new templateid
1089   */
1090  function feedback_create_template($courseid, $name, $ispublic = 0) {
1091      global $DB;
1092  
1093      $templ = new stdClass();
1094      $templ->course   = ($ispublic ? 0 : $courseid);
1095      $templ->name     = $name;
1096      $templ->ispublic = $ispublic;
1097  
1098      $templid = $DB->insert_record('feedback_template', $templ);
1099      return $DB->get_record('feedback_template', array('id'=>$templid));
1100  }
1101  
1102  /**
1103   * creates new template items.
1104   * all items will be copied and the attribute feedback will be set to 0
1105   * and the attribute template will be set to the new templateid
1106   *
1107   * @global object
1108   * @uses CONTEXT_MODULE
1109   * @uses CONTEXT_COURSE
1110   * @param object $feedback
1111   * @param string $name the name of template shown in the templatelist
1112   * @param int $ispublic 0:privat 1:public
1113   * @return boolean
1114   */
1115  function feedback_save_as_template($feedback, $name, $ispublic = 0) {
1116      global $DB;
1117      $fs = get_file_storage();
1118  
1119      if (!$feedbackitems = $DB->get_records('feedback_item', array('feedback'=>$feedback->id))) {
1120          return false;
1121      }
1122  
1123      if (!$newtempl = feedback_create_template($feedback->course, $name, $ispublic)) {
1124          return false;
1125      }
1126  
1127      //files in the template_item are in the context of the current course or
1128      //if the template is public the files are in the system context
1129      //files in the feedback_item are in the feedback_context of the feedback
1130      if ($ispublic) {
1131          $s_context = context_system::instance();
1132      } else {
1133          $s_context = context_course::instance($newtempl->course);
1134      }
1135      $cm = get_coursemodule_from_instance('feedback', $feedback->id);
1136      $f_context = context_module::instance($cm->id);
1137  
1138      //create items of this new template
1139      //depend items we are storing temporary in an mapping list array(new id => dependitem)
1140      //we also store a mapping of all items array(oldid => newid)
1141      $dependitemsmap = array();
1142      $itembackup = array();
1143      foreach ($feedbackitems as $item) {
1144  
1145          $t_item = clone($item);
1146  
1147          unset($t_item->id);
1148          $t_item->feedback = 0;
1149          $t_item->template     = $newtempl->id;
1150          $t_item->id = $DB->insert_record('feedback_item', $t_item);
1151          //copy all included files to the feedback_template filearea
1152          $itemfiles = $fs->get_area_files($f_context->id,
1153                                      'mod_feedback',
1154                                      'item',
1155                                      $item->id,
1156                                      "id",
1157                                      false);
1158          if ($itemfiles) {
1159              foreach ($itemfiles as $ifile) {
1160                  $file_record = new stdClass();
1161                  $file_record->contextid = $s_context->id;
1162                  $file_record->component = 'mod_feedback';
1163                  $file_record->filearea = 'template';
1164                  $file_record->itemid = $t_item->id;
1165                  $fs->create_file_from_storedfile($file_record, $ifile);
1166              }
1167          }
1168  
1169          $itembackup[$item->id] = $t_item->id;
1170          if ($t_item->dependitem) {
1171              $dependitemsmap[$t_item->id] = $t_item->dependitem;
1172          }
1173  
1174      }
1175  
1176      //remapping the dependency
1177      foreach ($dependitemsmap as $key => $dependitem) {
1178          $newitem = $DB->get_record('feedback_item', array('id'=>$key));
1179          $newitem->dependitem = $itembackup[$newitem->dependitem];
1180          $DB->update_record('feedback_item', $newitem);
1181      }
1182  
1183      return true;
1184  }
1185  
1186  /**
1187   * deletes all feedback_items related to the given template id
1188   *
1189   * @global object
1190   * @uses CONTEXT_COURSE
1191   * @param object $template the template
1192   * @return void
1193   */
1194  function feedback_delete_template($template) {
1195      global $DB;
1196  
1197      //deleting the files from the item is done by feedback_delete_item
1198      if ($t_items = $DB->get_records("feedback_item", array("template"=>$template->id))) {
1199          foreach ($t_items as $t_item) {
1200              feedback_delete_item($t_item->id, false, $template);
1201          }
1202      }
1203      $DB->delete_records("feedback_template", array("id"=>$template->id));
1204  }
1205  
1206  /**
1207   * creates new feedback_item-records from template.
1208   * if $deleteold is set true so the existing items of the given feedback will be deleted
1209   * if $deleteold is set false so the new items will be appanded to the old items
1210   *
1211   * @global object
1212   * @uses CONTEXT_COURSE
1213   * @uses CONTEXT_MODULE
1214   * @param object $feedback
1215   * @param int $templateid
1216   * @param boolean $deleteold
1217   */
1218  function feedback_items_from_template($feedback, $templateid, $deleteold = false) {
1219      global $DB, $CFG;
1220  
1221      require_once($CFG->libdir.'/completionlib.php');
1222  
1223      $fs = get_file_storage();
1224  
1225      if (!$template = $DB->get_record('feedback_template', array('id'=>$templateid))) {
1226          return false;
1227      }
1228      //get all templateitems
1229      if (!$templitems = $DB->get_records('feedback_item', array('template'=>$templateid))) {
1230          return false;
1231      }
1232  
1233      //files in the template_item are in the context of the current course
1234      //files in the feedback_item are in the feedback_context of the feedback
1235      if ($template->ispublic) {
1236          $s_context = context_system::instance();
1237      } else {
1238          $s_context = context_course::instance($feedback->course);
1239      }
1240      $course = $DB->get_record('course', array('id'=>$feedback->course));
1241      $cm = get_coursemodule_from_instance('feedback', $feedback->id);
1242      $f_context = context_module::instance($cm->id);
1243  
1244      //if deleteold then delete all old items before
1245      //get all items
1246      if ($deleteold) {
1247          if ($feedbackitems = $DB->get_records('feedback_item', array('feedback'=>$feedback->id))) {
1248              //delete all items of this feedback
1249              foreach ($feedbackitems as $item) {
1250                  feedback_delete_item($item->id, false);
1251              }
1252              //delete tracking-data
1253              $DB->delete_records('feedback_tracking', array('feedback'=>$feedback->id));
1254  
1255              $params = array('feedback'=>$feedback->id);
1256              if ($completeds = $DB->get_records('feedback_completed', $params)) {
1257                  $completion = new completion_info($course);
1258                  foreach ($completeds as $completed) {
1259                      // Update completion state
1260                      if ($completion->is_enabled($cm) && $feedback->completionsubmit) {
1261                          $completion->update_state($cm, COMPLETION_INCOMPLETE, $completed->userid);
1262                      }
1263                      $DB->delete_records('feedback_completed', array('id'=>$completed->id));
1264                  }
1265              }
1266              $DB->delete_records('feedback_completedtmp', array('feedback'=>$feedback->id));
1267          }
1268          $positionoffset = 0;
1269      } else {
1270          //if the old items are kept the new items will be appended
1271          //therefor the new position has an offset
1272          $positionoffset = $DB->count_records('feedback_item', array('feedback'=>$feedback->id));
1273      }
1274  
1275      //create items of this new template
1276      //depend items we are storing temporary in an mapping list array(new id => dependitem)
1277      //we also store a mapping of all items array(oldid => newid)
1278      $dependitemsmap = array();
1279      $itembackup = array();
1280      foreach ($templitems as $t_item) {
1281          $item = clone($t_item);
1282          unset($item->id);
1283          $item->feedback = $feedback->id;
1284          $item->template = 0;
1285          $item->position = $item->position + $positionoffset;
1286  
1287          $item->id = $DB->insert_record('feedback_item', $item);
1288  
1289          //moving the files to the new item
1290          $templatefiles = $fs->get_area_files($s_context->id,
1291                                          'mod_feedback',
1292                                          'template',
1293                                          $t_item->id,
1294                                          "id",
1295                                          false);
1296          if ($templatefiles) {
1297              foreach ($templatefiles as $tfile) {
1298                  $file_record = new stdClass();
1299                  $file_record->contextid = $f_context->id;
1300                  $file_record->component = 'mod_feedback';
1301                  $file_record->filearea = 'item';
1302                  $file_record->itemid = $item->id;
1303                  $fs->create_file_from_storedfile($file_record, $tfile);
1304              }
1305          }
1306  
1307          $itembackup[$t_item->id] = $item->id;
1308          if ($item->dependitem) {
1309              $dependitemsmap[$item->id] = $item->dependitem;
1310          }
1311      }
1312  
1313      //remapping the dependency
1314      foreach ($dependitemsmap as $key => $dependitem) {
1315          $newitem = $DB->get_record('feedback_item', array('id'=>$key));
1316          $newitem->dependitem = $itembackup[$newitem->dependitem];
1317          $DB->update_record('feedback_item', $newitem);
1318      }
1319  }
1320  
1321  /**
1322   * get the list of available templates.
1323   * if the $onlyown param is set true so only templates from own course will be served
1324   * this is important for droping templates
1325   *
1326   * @global object
1327   * @param object $course
1328   * @param string $onlyownorpublic
1329   * @return array the template recordsets
1330   */
1331  function feedback_get_template_list($course, $onlyownorpublic = '') {
1332      global $DB, $CFG;
1333  
1334      switch($onlyownorpublic) {
1335          case '':
1336              $templates = $DB->get_records_select('feedback_template',
1337                                                   'course = ? OR ispublic = 1',
1338                                                   array($course->id),
1339                                                   'name');
1340              break;
1341          case 'own':
1342              $templates = $DB->get_records('feedback_template',
1343                                            array('course'=>$course->id),
1344                                            'name');
1345              break;
1346          case 'public':
1347              $templates = $DB->get_records('feedback_template', array('ispublic'=>1), 'name');
1348              break;
1349      }
1350      return $templates;
1351  }
1352  
1353  ////////////////////////////////////////////////
1354  //Handling der Items
1355  ////////////////////////////////////////////////
1356  ////////////////////////////////////////////////
1357  
1358  /**
1359   * load the lib.php from item-plugin-dir and returns the instance of the itemclass
1360   *
1361   * @global object
1362   * @param object $item
1363   * @return object the instanz of itemclass
1364   */
1365  function feedback_get_item_class($typ) {
1366      global $CFG;
1367  
1368      //get the class of item-typ
1369      $itemclass = 'feedback_item_'.$typ;
1370      //get the instance of item-class
1371      if (!class_exists($itemclass)) {
1372          require_once($CFG->dirroot.'/mod/feedback/item/'.$typ.'/lib.php');
1373      }
1374      return new $itemclass();
1375  }
1376  
1377  /**
1378   * load the available item plugins from given subdirectory of $CFG->dirroot
1379   * the default is "mod/feedback/item"
1380   *
1381   * @global object
1382   * @param string $dir the subdir
1383   * @return array pluginnames as string
1384   */
1385  function feedback_load_feedback_items($dir = 'mod/feedback/item') {
1386      global $CFG;
1387      $names = get_list_of_plugins($dir);
1388      $ret_names = array();
1389  
1390      foreach ($names as $name) {
1391          require_once($CFG->dirroot.'/'.$dir.'/'.$name.'/lib.php');
1392          if (class_exists('feedback_item_'.$name)) {
1393              $ret_names[] = $name;
1394          }
1395      }
1396      return $ret_names;
1397  }
1398  
1399  /**
1400   * load the available item plugins to use as dropdown-options
1401   *
1402   * @global object
1403   * @return array pluginnames as string
1404   */
1405  function feedback_load_feedback_items_options() {
1406      global $CFG;
1407  
1408      $feedback_options = array("pagebreak" => get_string('add_pagebreak', 'feedback'));
1409  
1410      if (!$feedback_names = feedback_load_feedback_items('mod/feedback/item')) {
1411          return array();
1412      }
1413  
1414      foreach ($feedback_names as $fn) {
1415          $feedback_options[$fn] = get_string($fn, 'feedback');
1416      }
1417      asort($feedback_options);
1418      $feedback_options = array_merge( array(' ' => get_string('select')), $feedback_options );
1419      return $feedback_options;
1420  }
1421  
1422  /**
1423   * load the available items for the depend item dropdown list shown in the edit_item form
1424   *
1425   * @global object
1426   * @param object $feedback
1427   * @param object $item the item of the edit_item form
1428   * @return array all items except the item $item, labels and pagebreaks
1429   */
1430  function feedback_get_depend_candidates_for_item($feedback, $item) {
1431      global $DB;
1432      //all items for dependitem
1433      $where = "feedback = ? AND typ != 'pagebreak' AND hasvalue = 1";
1434      $params = array($feedback->id);
1435      if (isset($item->id) AND $item->id) {
1436          $where .= ' AND id != ?';
1437          $params[] = $item->id;
1438      }
1439      $dependitems = array(0 => get_string('choose'));
1440      $feedbackitems = $DB->get_records_select_menu('feedback_item',
1441                                                    $where,
1442                                                    $params,
1443                                                    'position',
1444                                                    'id, label');
1445  
1446      if (!$feedbackitems) {
1447          return $dependitems;
1448      }
1449      //adding the choose-option
1450      foreach ($feedbackitems as $key => $val) {
1451          $dependitems[$key] = $val;
1452      }
1453      return $dependitems;
1454  }
1455  
1456  /**
1457   * creates a new item-record
1458   *
1459   * @global object
1460   * @param object $data the data from edit_item_form
1461   * @return int the new itemid
1462   */
1463  function feedback_create_item($data) {
1464      global $DB;
1465  
1466      $item = new stdClass();
1467      $item->feedback = $data->feedbackid;
1468  
1469      $item->template=0;
1470      if (isset($data->templateid)) {
1471              $item->template = intval($data->templateid);
1472      }
1473  
1474      $itemname = trim($data->itemname);
1475      $item->name = ($itemname ? $data->itemname : get_string('no_itemname', 'feedback'));
1476  
1477      if (!empty($data->itemlabel)) {
1478          $item->label = trim($data->itemlabel);
1479      } else {
1480          $item->label = get_string('no_itemlabel', 'feedback');
1481      }
1482  
1483      $itemobj = feedback_get_item_class($data->typ);
1484      $item->presentation = ''; //the date comes from postupdate() of the itemobj
1485  
1486      $item->hasvalue = $itemobj->get_hasvalue();
1487  
1488      $item->typ = $data->typ;
1489      $item->position = $data->position;
1490  
1491      $item->required=0;
1492      if (!empty($data->required)) {
1493          $item->required = $data->required;
1494      }
1495  
1496      $item->id = $DB->insert_record('feedback_item', $item);
1497  
1498      //move all itemdata to the data
1499      $data->id = $item->id;
1500      $data->feedback = $item->feedback;
1501      $data->name = $item->name;
1502      $data->label = $item->label;
1503      $data->required = $item->required;
1504      return $itemobj->postupdate($data);
1505  }
1506  
1507  /**
1508   * save the changes of a given item.
1509   *
1510   * @global object
1511   * @param object $item
1512   * @return boolean
1513   */
1514  function feedback_update_item($item) {
1515      global $DB;
1516      return $DB->update_record("feedback_item", $item);
1517  }
1518  
1519  /**
1520   * deletes an item and also deletes all related values
1521   *
1522   * @global object
1523   * @uses CONTEXT_MODULE
1524   * @param int $itemid
1525   * @param boolean $renumber should the kept items renumbered Yes/No
1526   * @param object $template if the template is given so the items are bound to it
1527   * @return void
1528   */
1529  function feedback_delete_item($itemid, $renumber = true, $template = false) {
1530      global $DB;
1531  
1532      $item = $DB->get_record('feedback_item', array('id'=>$itemid));
1533  
1534      //deleting the files from the item
1535      $fs = get_file_storage();
1536  
1537      if ($template) {
1538          if ($template->ispublic) {
1539              $context = context_system::instance();
1540          } else {
1541              $context = context_course::instance($template->course);
1542          }
1543          $templatefiles = $fs->get_area_files($context->id,
1544                                      'mod_feedback',
1545                                      'template',
1546                                      $item->id,
1547                                      "id",
1548                                      false);
1549  
1550          if ($templatefiles) {
1551              $fs->delete_area_files($context->id, 'mod_feedback', 'template', $item->id);
1552          }
1553      } else {
1554          if (!$cm = get_coursemodule_from_instance('feedback', $item->feedback)) {
1555              return false;
1556          }
1557          $context = context_module::instance($cm->id);
1558  
1559          $itemfiles = $fs->get_area_files($context->id,
1560                                      'mod_feedback',
1561                                      'item',
1562                                      $item->id,
1563                                      "id", false);
1564  
1565          if ($itemfiles) {
1566              $fs->delete_area_files($context->id, 'mod_feedback', 'item', $item->id);
1567          }
1568      }
1569  
1570      $DB->delete_records("feedback_value", array("item"=>$itemid));
1571      $DB->delete_records("feedback_valuetmp", array("item"=>$itemid));
1572  
1573      //remove all depends
1574      $DB->set_field('feedback_item', 'dependvalue', '', array('dependitem'=>$itemid));
1575      $DB->set_field('feedback_item', 'dependitem', 0, array('dependitem'=>$itemid));
1576  
1577      $DB->delete_records("feedback_item", array("id"=>$itemid));
1578      if ($renumber) {
1579          feedback_renumber_items($item->feedback);
1580      }
1581  }
1582  
1583  /**
1584   * deletes all items of the given feedbackid
1585   *
1586   * @global object
1587   * @param int $feedbackid
1588   * @return void
1589   */
1590  function feedback_delete_all_items($feedbackid) {
1591      global $DB, $CFG;
1592      require_once($CFG->libdir.'/completionlib.php');
1593  
1594      if (!$feedback = $DB->get_record('feedback', array('id'=>$feedbackid))) {
1595          return false;
1596      }
1597  
1598      if (!$cm = get_coursemodule_from_instance('feedback', $feedback->id)) {
1599          return false;
1600      }
1601  
1602      if (!$course = $DB->get_record('course', array('id'=>$feedback->course))) {
1603          return false;
1604      }
1605  
1606      if (!$items = $DB->get_records('feedback_item', array('feedback'=>$feedbackid))) {
1607          return;
1608      }
1609      foreach ($items as $item) {
1610          feedback_delete_item($item->id, false);
1611      }
1612      if ($completeds = $DB->get_records('feedback_completed', array('feedback'=>$feedback->id))) {
1613          $completion = new completion_info($course);
1614          foreach ($completeds as $completed) {
1615              // Update completion state
1616              if ($completion->is_enabled($cm) && $feedback->completionsubmit) {
1617                  $completion->update_state($cm, COMPLETION_INCOMPLETE, $completed->userid);
1618              }
1619              $DB->delete_records('feedback_completed', array('id'=>$completed->id));
1620          }
1621      }
1622  
1623      $DB->delete_records('feedback_completedtmp', array('feedback'=>$feedbackid));
1624  
1625  }
1626  
1627  /**
1628   * this function toggled the item-attribute required (yes/no)
1629   *
1630   * @global object
1631   * @param object $item
1632   * @return boolean
1633   */
1634  function feedback_switch_item_required($item) {
1635      global $DB, $CFG;
1636  
1637      $itemobj = feedback_get_item_class($item->typ);
1638  
1639      if ($itemobj->can_switch_require()) {
1640          $new_require_val = (int)!(bool)$item->required;
1641          $params = array('id'=>$item->id);
1642          $DB->set_field('feedback_item', 'required', $new_require_val, $params);
1643      }
1644      return true;
1645  }
1646  
1647  /**
1648   * renumbers all items of the given feedbackid
1649   *
1650   * @global object
1651   * @param int $feedbackid
1652   * @return void
1653   */
1654  function feedback_renumber_items($feedbackid) {
1655      global $DB;
1656  
1657      $items = $DB->get_records('feedback_item', array('feedback'=>$feedbackid), 'position');
1658      $pos = 1;
1659      if ($items) {
1660          foreach ($items as $item) {
1661              $DB->set_field('feedback_item', 'position', $pos, array('id'=>$item->id));
1662              $pos++;
1663          }
1664      }
1665  }
1666  
1667  /**
1668   * this decreases the position of the given item
1669   *
1670   * @global object
1671   * @param object $item
1672   * @return bool
1673   */
1674  function feedback_moveup_item($item) {
1675      global $DB;
1676  
1677      if ($item->position == 1) {
1678          return true;
1679      }
1680  
1681      $params = array('feedback'=>$item->feedback);
1682      if (!$items = $DB->get_records('feedback_item', $params, 'position')) {
1683          return false;
1684      }
1685  
1686      $itembefore = null;
1687      foreach ($items as $i) {
1688          if ($i->id == $item->id) {
1689              if (is_null($itembefore)) {
1690                  return true;
1691              }
1692              $itembefore->position = $item->position;
1693              $item->position--;
1694              feedback_update_item($itembefore);
1695              feedback_update_item($item);
1696              feedback_renumber_items($item->feedback);
1697              return true;
1698          }
1699          $itembefore = $i;
1700      }
1701      return false;
1702  }
1703  
1704  /**
1705   * this increased the position of the given item
1706   *
1707   * @global object
1708   * @param object $item
1709   * @return bool
1710   */
1711  function feedback_movedown_item($item) {
1712      global $DB;
1713  
1714      $params = array('feedback'=>$item->feedback);
1715      if (!$items = $DB->get_records('feedback_item', $params, 'position')) {
1716          return false;
1717      }
1718  
1719      $movedownitem = null;
1720      foreach ($items as $i) {
1721          if (!is_null($movedownitem) AND $movedownitem->id == $item->id) {
1722              $movedownitem->position = $i->position;
1723              $i->position--;
1724              feedback_update_item($movedownitem);
1725              feedback_update_item($i);
1726              feedback_renumber_items($item->feedback);
1727              return true;
1728          }
1729          $movedownitem = $i;
1730      }
1731      return false;
1732  }
1733  
1734  /**
1735   * here the position of the given item will be set to the value in $pos
1736   *
1737   * @global object
1738   * @param object $moveitem
1739   * @param int $pos
1740   * @return boolean
1741   */
1742  function feedback_move_item($moveitem, $pos) {
1743      global $DB;
1744  
1745      $params = array('feedback'=>$moveitem->feedback);
1746      if (!$allitems = $DB->get_records('feedback_item', $params, 'position')) {
1747          return false;
1748      }
1749      if (is_array($allitems)) {
1750          $index = 1;
1751          foreach ($allitems as $item) {
1752              if ($index == $pos) {
1753                  $index++;
1754              }
1755              if ($item->id == $moveitem->id) {
1756                  $moveitem->position = $pos;
1757                  feedback_update_item($moveitem);
1758                  continue;
1759              }
1760              $item->position = $index;
1761              feedback_update_item($item);
1762              $index++;
1763          }
1764          return true;
1765      }
1766      return false;
1767  }
1768  
1769  /**
1770   * prints the given item as a preview.
1771   * each item-class has an own print_item_preview function implemented.
1772   *
1773   * @global object
1774   * @param object $item the item what we want to print out
1775   * @return void
1776   */
1777  function feedback_print_item_preview($item) {
1778      global $CFG;
1779      if ($item->typ == 'pagebreak') {
1780          return;
1781      }
1782      //get the instance of the item-class
1783      $itemobj = feedback_get_item_class($item->typ);
1784      $itemobj->print_item_preview($item);
1785  }
1786  
1787  /**
1788   * prints the given item in the completion form.
1789   * each item-class has an own print_item_complete function implemented.
1790   *
1791   * @param object $item the item what we want to print out
1792   * @param mixed $value the value
1793   * @param boolean $highlightrequire if this set true and the value are false on completing so the item will be highlighted
1794   * @return void
1795   */
1796  function feedback_print_item_complete($item, $value = false, $highlightrequire = false) {
1797      global $CFG;
1798      if ($item->typ == 'pagebreak') {
1799          return;
1800      }
1801  
1802      //get the instance of the item-class
1803      $itemobj = feedback_get_item_class($item->typ);
1804      $itemobj->print_item_complete($item, $value, $highlightrequire);
1805  }
1806  
1807  /**
1808   * prints the given item in the show entries page.
1809   * each item-class has an own print_item_show_value function implemented.
1810   *
1811   * @param object $item the item what we want to print out
1812   * @param mixed $value
1813   * @return void
1814   */
1815  function feedback_print_item_show_value($item, $value = false) {
1816      global $CFG;
1817      if ($item->typ == 'pagebreak') {
1818          return;
1819      }
1820  
1821      //get the instance of the item-class
1822      $itemobj = feedback_get_item_class($item->typ);
1823      $itemobj->print_item_show_value($item, $value);
1824  }
1825  
1826  /**
1827   * if the user completes a feedback and there is a pagebreak so the values are saved temporary.
1828   * the values are not saved permanently until the user click on save button
1829   *
1830   * @global object
1831   * @param object $feedbackcompleted
1832   * @return object temporary saved completed-record
1833   */
1834  function feedback_set_tmp_values($feedbackcompleted) {
1835      global $DB;
1836  
1837      //first we create a completedtmp
1838      $tmpcpl = new stdClass();
1839      foreach ($feedbackcompleted as $key => $value) {
1840          $tmpcpl->{$key} = $value;
1841      }
1842      unset($tmpcpl->id);
1843      $tmpcpl->timemodified = time();
1844      $tmpcpl->id = $DB->insert_record('feedback_completedtmp', $tmpcpl);
1845      //get all values of original-completed
1846      if (!$values = $DB->get_records('feedback_value', array('completed'=>$feedbackcompleted->id))) {
1847          return;
1848      }
1849      foreach ($values as $value) {
1850          unset($value->id);
1851          $value->completed = $tmpcpl->id;
1852          $DB->insert_record('feedback_valuetmp', $value);
1853      }
1854      return $tmpcpl;
1855  }
1856  
1857  /**
1858   * this saves the temporary saved values permanently
1859   *
1860   * @global object
1861   * @param object $feedbackcompletedtmp the temporary completed
1862   * @param object $feedbackcompleted the target completed
1863   * @param int $userid
1864   * @return int the id of the completed
1865   */
1866  function feedback_save_tmp_values($feedbackcompletedtmp, $feedbackcompleted, $userid) {
1867      global $DB;
1868  
1869      $tmpcplid = $feedbackcompletedtmp->id;
1870      if ($feedbackcompleted) {
1871          //first drop all existing values
1872          $DB->delete_records('feedback_value', array('completed'=>$feedbackcompleted->id));
1873          //update the current completed
1874          $feedbackcompleted->timemodified = time();
1875          $DB->update_record('feedback_completed', $feedbackcompleted);
1876      } else {
1877          $feedbackcompleted = clone($feedbackcompletedtmp);
1878          $feedbackcompleted->id = '';
1879          $feedbackcompleted->userid = $userid;
1880          $feedbackcompleted->timemodified = time();
1881          $feedbackcompleted->id = $DB->insert_record('feedback_completed', $feedbackcompleted);
1882      }
1883  
1884      //save all the new values from feedback_valuetmp
1885      //get all values of tmp-completed
1886      $params = array('completed'=>$feedbackcompletedtmp->id);
1887      if (!$values = $DB->get_records('feedback_valuetmp', $params)) {
1888          return false;
1889      }
1890      foreach ($values as $value) {
1891          //check if there are depend items
1892          $item = $DB->get_record('feedback_item', array('id'=>$value->item));
1893          if ($item->dependitem > 0) {
1894              $check = feedback_compare_item_value($tmpcplid,
1895                                          $item->dependitem,
1896                                          $item->dependvalue,
1897                                          true);
1898          } else {
1899              $check = true;
1900          }
1901          if ($check) {
1902              unset($value->id);
1903              $value->completed = $feedbackcompleted->id;
1904              $DB->insert_record('feedback_value', $value);
1905          }
1906      }
1907      //drop all the tmpvalues
1908      $DB->delete_records('feedback_valuetmp', array('completed'=>$tmpcplid));
1909      $DB->delete_records('feedback_completedtmp', array('id'=>$tmpcplid));
1910  
1911      // Trigger event for the delete action we performed.
1912      $cm = get_coursemodule_from_instance('feedback', $feedbackcompleted->feedback);
1913      $event = \mod_feedback\event\response_submitted::create(array(
1914          'relateduserid' => $userid,
1915          'objectid' => $feedbackcompleted->id,
1916          'context' => context_module::instance($cm->id),
1917          'anonymous' => ($feedbackcompleted->anonymous_response == FEEDBACK_ANONYMOUS_YES),
1918          'other' => array(
1919              'cmid' => $cm->id,
1920              'instanceid' => $feedbackcompleted->feedback,
1921              'anonymous' => $feedbackcompleted->anonymous_response // Deprecated.
1922          )
1923      ));
1924  
1925      $event->add_record_snapshot('feedback_completed', $feedbackcompleted);
1926  
1927      $event->trigger();
1928      return $feedbackcompleted->id;
1929  
1930  }
1931  
1932  /**
1933   * deletes the given temporary completed and all related temporary values
1934   *
1935   * @global object
1936   * @param int $tmpcplid
1937   * @return void
1938   */
1939  function feedback_delete_completedtmp($tmpcplid) {
1940      global $DB;
1941  
1942      $DB->delete_records('feedback_valuetmp', array('completed'=>$tmpcplid));
1943      $DB->delete_records('feedback_completedtmp', array('id'=>$tmpcplid));
1944  }
1945  
1946  ////////////////////////////////////////////////
1947  ////////////////////////////////////////////////
1948  ////////////////////////////////////////////////
1949  //functions to handle the pagebreaks
1950  ////////////////////////////////////////////////
1951  
1952  /**
1953   * this creates a pagebreak.
1954   * a pagebreak is a special kind of item
1955   *
1956   * @global object
1957   * @param int $feedbackid
1958   * @return mixed false if there already is a pagebreak on last position or the id of the pagebreak-item
1959   */
1960  function feedback_create_pagebreak($feedbackid) {
1961      global $DB;
1962  
1963      //check if there already is a pagebreak on the last position
1964      $lastposition = $DB->count_records('feedback_item', array('feedback'=>$feedbackid));
1965      if ($lastposition == feedback_get_last_break_position($feedbackid)) {
1966          return false;
1967      }
1968  
1969      $item = new stdClass();
1970      $item->feedback = $feedbackid;
1971  
1972      $item->template=0;
1973  
1974      $item->name = '';
1975  
1976      $item->presentation = '';
1977      $item->hasvalue = 0;
1978  
1979      $item->typ = 'pagebreak';
1980      $item->position = $lastposition + 1;
1981  
1982      $item->required=0;
1983  
1984      return $DB->insert_record('feedback_item', $item);
1985  }
1986  
1987  /**
1988   * get all positions of pagebreaks in the given feedback
1989   *
1990   * @global object
1991   * @param int $feedbackid
1992   * @return array all ordered pagebreak positions
1993   */
1994  function feedback_get_all_break_positions($feedbackid) {
1995      global $DB;
1996  
1997      $params = array('typ'=>'pagebreak', 'feedback'=>$feedbackid);
1998      $allbreaks = $DB->get_records_menu('feedback_item', $params, 'position', 'id, position');
1999      if (!$allbreaks) {
2000          return false;
2001      }
2002      return array_values($allbreaks);
2003  }
2004  
2005  /**
2006   * get the position of the last pagebreak
2007   *
2008   * @param int $feedbackid
2009   * @return int the position of the last pagebreak
2010   */
2011  function feedback_get_last_break_position($feedbackid) {
2012      if (!$allbreaks = feedback_get_all_break_positions($feedbackid)) {
2013          return false;
2014      }
2015      return $allbreaks[count($allbreaks) - 1];
2016  }
2017  
2018  /**
2019   * this returns the position where the user can continue the completing.
2020   *
2021   * @global object
2022   * @global object
2023   * @global object
2024   * @param int $feedbackid
2025   * @param int $courseid
2026   * @param string $guestid this id will be saved temporary and is unique
2027   * @return int the position to continue
2028   */
2029  function feedback_get_page_to_continue($feedbackid, $courseid = false, $guestid = false) {
2030      global $CFG, $USER, $DB;
2031  
2032      //is there any break?
2033  
2034      if (!$allbreaks = feedback_get_all_break_positions($feedbackid)) {
2035          return false;
2036      }
2037  
2038      $params = array();
2039      if ($courseid) {
2040          $courseselect = "AND fv.course_id = :courseid";
2041          $params['courseid'] = $courseid;
2042      } else {
2043          $courseselect = '';
2044      }
2045  
2046      if ($guestid) {
2047          $userselect = "AND fc.guestid = :guestid";
2048          $usergroup = "GROUP BY fc.guestid";
2049          $params['guestid'] = $guestid;
2050      } else {
2051          $userselect = "AND fc.userid = :userid";
2052          $usergroup = "GROUP BY fc.userid";
2053          $params['userid'] = $USER->id;
2054      }
2055  
2056      $sql =  "SELECT MAX(fi.position)
2057                 FROM {feedback_completedtmp} fc, {feedback_valuetmp} fv, {feedback_item} fi
2058                WHERE fc.id = fv.completed
2059                      $userselect
2060                      AND fc.feedback = :feedbackid
2061                      $courseselect
2062                      AND fi.id = fv.item
2063           $usergroup";
2064      $params['feedbackid'] = $feedbackid;
2065  
2066      $lastpos = $DB->get_field_sql($sql, $params);
2067  
2068      //the index of found pagebreak is the searched pagenumber
2069      foreach ($allbreaks as $pagenr => $br) {
2070          if ($lastpos < $br) {
2071              return $pagenr;
2072          }
2073      }
2074      return count($allbreaks);
2075  }
2076  
2077  ////////////////////////////////////////////////
2078  ////////////////////////////////////////////////
2079  ////////////////////////////////////////////////
2080  //functions to handle the values
2081  ////////////////////////////////////////////////
2082  
2083  /**
2084   * cleans the userinput while submitting the form.
2085   *
2086   * @param mixed $value
2087   * @return mixed
2088   */
2089  function feedback_clean_input_value($item, $value) {
2090      $itemobj = feedback_get_item_class($item->typ);
2091      return $itemobj->clean_input_value($value);
2092  }
2093  
2094  /**
2095   * this saves the values of an completed.
2096   * if the param $tmp is set true so the values are saved temporary in table feedback_valuetmp.
2097   * if there is already a completed and the userid is set so the values are updated.
2098   * on all other things new value records will be created.
2099   *
2100   * @global object
2101   * @param int $userid
2102   * @param boolean $tmp
2103   * @return mixed false on error or the completeid
2104   */
2105  function feedback_save_values($usrid, $tmp = false) {
2106      global $DB;
2107  
2108      $completedid = optional_param('completedid', 0, PARAM_INT);
2109  
2110      $tmpstr = $tmp ? 'tmp' : '';
2111      $time = time();
2112      $timemodified = mktime(0, 0, 0, date('m', $time), date('d', $time), date('Y', $time));
2113  
2114      if ($usrid == 0) {
2115          return feedback_create_values($usrid, $timemodified, $tmp);
2116      }
2117      $completed = $DB->get_record('feedback_completed'.$tmpstr, array('id'=>$completedid));
2118      if (!$completed) {
2119          return feedback_create_values($usrid, $timemodified, $tmp);
2120      } else {
2121          $completed->timemodified = $timemodified;
2122          return feedback_update_values($completed, $tmp);
2123      }
2124  }
2125  
2126  /**
2127   * this saves the values from anonymous user such as guest on the main-site
2128   *
2129   * @global object
2130   * @param string $guestid the unique guestidentifier
2131   * @return mixed false on error or the completeid
2132   */
2133  function feedback_save_guest_values($guestid) {
2134      global $DB;
2135  
2136      $completedid = optional_param('completedid', false, PARAM_INT);
2137  
2138      $timemodified = time();
2139      if (!$completed = $DB->get_record('feedback_completedtmp', array('id'=>$completedid))) {
2140          return feedback_create_values(0, $timemodified, true, $guestid);
2141      } else {
2142          $completed->timemodified = $timemodified;
2143          return feedback_update_values($completed, true);
2144      }
2145  }
2146  
2147  /**
2148   * get the value from the given item related to the given completed.
2149   * the value can come as temporary or as permanently value. the deciding is done by $tmp
2150   *
2151   * @global object
2152   * @param int $completeid
2153   * @param int $itemid
2154   * @param boolean $tmp
2155   * @return mixed the value, the type depends on plugin-definition
2156   */
2157  function feedback_get_item_value($completedid, $itemid, $tmp = false) {
2158      global $DB;
2159  
2160      $tmpstr = $tmp ? 'tmp' : '';
2161      $params = array('completed'=>$completedid, 'item'=>$itemid);
2162      return $DB->get_field('feedback_value'.$tmpstr, 'value', $params);
2163  }
2164  
2165  /**
2166   * compares the value of the itemid related to the completedid with the dependvalue.
2167   * this is used if a depend item is set.
2168   * the value can come as temporary or as permanently value. the deciding is done by $tmp.
2169   *
2170   * @global object
2171   * @global object
2172   * @param int $completeid
2173   * @param int $itemid
2174   * @param mixed $dependvalue
2175   * @param boolean $tmp
2176   * @return bool
2177   */
2178  function feedback_compare_item_value($completedid, $itemid, $dependvalue, $tmp = false) {
2179      global $DB, $CFG;
2180  
2181      $dbvalue = feedback_get_item_value($completedid, $itemid, $tmp);
2182  
2183      //get the class of the given item-typ
2184      $item = $DB->get_record('feedback_item', array('id'=>$itemid));
2185  
2186      //get the instance of the item-class
2187      $itemobj = feedback_get_item_class($item->typ);
2188      return $itemobj->compare_value($item, $dbvalue, $dependvalue); //true or false
2189  }
2190  
2191  /**
2192   * this function checks the correctness of values.
2193   * the rules for this are implemented in the class of each item.
2194   * it can be the required attribute or the value self e.g. numeric.
2195   * the params first/lastitem are given to determine the visible range between pagebreaks.
2196   *
2197   * @global object
2198   * @param int $firstitem the position of firstitem for checking
2199   * @param int $lastitem the position of lastitem for checking
2200   * @return boolean
2201   */
2202  function feedback_check_values($firstitem, $lastitem) {
2203      global $DB, $CFG;
2204  
2205      $feedbackid = optional_param('feedbackid', 0, PARAM_INT);
2206  
2207      //get all items between the first- and lastitem
2208      $select = "feedback = ?
2209                      AND position >= ?
2210                      AND position <= ?
2211                      AND hasvalue = 1";
2212      $params = array($feedbackid, $firstitem, $lastitem);
2213      if (!$feedbackitems = $DB->get_records_select('feedback_item', $select, $params)) {
2214          //if no values are given so no values can be wrong ;-)
2215          return true;
2216      }
2217  
2218      foreach ($feedbackitems as $item) {
2219          //get the instance of the item-class
2220          $itemobj = feedback_get_item_class($item->typ);
2221  
2222          //the name of the input field of the completeform is given in a special form:
2223          //<item-typ>_<item-id> eg. numeric_234
2224          //this is the key to get the value for the correct item
2225          $formvalname = $item->typ . '_' . $item->id;
2226  
2227          if ($itemobj->value_is_array()) {
2228              //get the raw value here. It is cleaned after that by the object itself
2229              $value = optional_param_array($formvalname, null, PARAM_RAW);
2230          } else {
2231              //get the raw value here. It is cleaned after that by the object itself
2232              $value = optional_param($formvalname, null, PARAM_RAW);
2233          }
2234          $value = $itemobj->clean_input_value($value);
2235  
2236          // If the item is not visible due to its dependency so it shouldn't be required.
2237          // Many thanks to Pau Ferrer Ocaña.
2238          if ($item->dependitem > 0 AND $item->required == 1) {
2239              $comparevalue = false;
2240              if ($feedbackcompletedtmp = feedback_get_current_completed($item->feedback, true)) {
2241                  $comparevalue = feedback_compare_item_value($feedbackcompletedtmp->id,
2242                                                              $item->dependitem,
2243                                                              $item->dependvalue,
2244                                                              true);
2245              }
2246  
2247              if (!$comparevalue) {
2248                  $item->required = 0; // Override the required property.
2249              }
2250          }
2251  
2252          //check if the value is set
2253          if (is_null($value) AND $item->required == 1) {
2254              return false;
2255          }
2256  
2257          //now we let check the value by the item-class
2258          if (!$itemobj->check_value($value, $item)) {
2259              return false;
2260          }
2261      }
2262      //if no wrong values so we can return true
2263      return true;
2264  }
2265  
2266  /**
2267   * this function create a complete-record and the related value-records.
2268   * depending on the $tmp (true/false) the values are saved temporary or permanently
2269   *
2270   * @global object
2271   * @param int $userid
2272   * @param int $timemodified
2273   * @param boolean $tmp
2274   * @param string $guestid a unique identifier to save temporary data
2275   * @return mixed false on error or the completedid
2276   */
2277  function feedback_create_values($usrid, $timemodified, $tmp = false, $guestid = false) {
2278      global $DB;
2279  
2280      $feedbackid = optional_param('feedbackid', false, PARAM_INT);
2281      $anonymous_response = optional_param('anonymous_response', false, PARAM_INT);
2282      $courseid = optional_param('courseid', false, PARAM_INT);
2283  
2284      $tmpstr = $tmp ? 'tmp' : '';
2285      //first we create a new completed record
2286      $completed = new stdClass();
2287      $completed->feedback           = $feedbackid;
2288      $completed->userid             = $usrid;
2289      $completed->guestid            = $guestid;
2290      $completed->timemodified       = $timemodified;
2291      $completed->anonymous_response = $anonymous_response;
2292  
2293      $completedid = $DB->insert_record('feedback_completed'.$tmpstr, $completed);
2294  
2295      $completed = $DB->get_record('feedback_completed'.$tmpstr, array('id'=>$completedid));
2296  
2297      //the keys are in the form like abc_xxx
2298      //with explode we make an array with(abc, xxx) and (abc=typ und xxx=itemnr)
2299  
2300      //get the items of the feedback
2301      if (!$allitems = $DB->get_records('feedback_item', array('feedback'=>$completed->feedback))) {
2302          return false;
2303      }
2304      foreach ($allitems as $item) {
2305          if (!$item->hasvalue) {
2306              continue;
2307          }
2308          //get the class of item-typ
2309          $itemobj = feedback_get_item_class($item->typ);
2310  
2311          $keyname = $item->typ.'_'.$item->id;
2312  
2313          if ($itemobj->value_is_array()) {
2314              $itemvalue = optional_param_array($keyname, null, $itemobj->value_type());
2315          } else {
2316              $itemvalue = optional_param($keyname, null, $itemobj->value_type());
2317          }
2318  
2319          if (is_null($itemvalue)) {
2320              continue;
2321          }
2322  
2323          $value = new stdClass();
2324          $value->item = $item->id;
2325          $value->completed = $completed->id;
2326          $value->course_id = $courseid;
2327  
2328          //the kind of values can be absolutely different
2329          //so we run create_value directly by the item-class
2330          $value->value = $itemobj->create_value($itemvalue);
2331          $DB->insert_record('feedback_value'.$tmpstr, $value);
2332      }
2333      return $completed->id;
2334  }
2335  
2336  /**
2337   * this function updates a complete-record and the related value-records.
2338   * depending on the $tmp (true/false) the values are saved temporary or permanently
2339   *
2340   * @global object
2341   * @param object $completed
2342   * @param boolean $tmp
2343   * @return int the completedid
2344   */
2345  function feedback_update_values($completed, $tmp = false) {
2346      global $DB;
2347  
2348      $courseid = optional_param('courseid', false, PARAM_INT);
2349      $tmpstr = $tmp ? 'tmp' : '';
2350  
2351      $DB->update_record('feedback_completed'.$tmpstr, $completed);
2352      //get the values of this completed
2353      $values = $DB->get_records('feedback_value'.$tmpstr, array('completed'=>$completed->id));
2354  
2355      //get the items of the feedback
2356      if (!$allitems = $DB->get_records('feedback_item', array('feedback'=>$completed->feedback))) {
2357          return false;
2358      }
2359      foreach ($allitems as $item) {
2360          if (!$item->hasvalue) {
2361              continue;
2362          }
2363          //get the class of item-typ
2364          $itemobj = feedback_get_item_class($item->typ);
2365  
2366          $keyname = $item->typ.'_'.$item->id;
2367  
2368          if ($itemobj->value_is_array()) {
2369              $itemvalue = optional_param_array($keyname, null, $itemobj->value_type());
2370          } else {
2371              $itemvalue = optional_param($keyname, null, $itemobj->value_type());
2372          }
2373  
2374          //is the itemvalue set (could be a subset of items because pagebreak)?
2375          if (is_null($itemvalue)) {
2376              continue;
2377          }
2378  
2379          $newvalue = new stdClass();
2380          $newvalue->item = $item->id;
2381          $newvalue->completed = $completed->id;
2382          $newvalue->course_id = $courseid;
2383  
2384          //the kind of values can be absolutely different
2385          //so we run create_value directly by the item-class
2386          $newvalue->value = $itemobj->create_value($itemvalue);
2387  
2388          //check, if we have to create or update the value
2389          $exist = false;
2390          foreach ($values as $value) {
2391              if ($value->item == $newvalue->item) {
2392                  $newvalue->id = $value->id;
2393                  $exist = true;
2394                  break;
2395              }
2396          }
2397          if ($exist) {
2398              $DB->update_record('feedback_value'.$tmpstr, $newvalue);
2399          } else {
2400              $DB->insert_record('feedback_value'.$tmpstr, $newvalue);
2401          }
2402      }
2403  
2404      return $completed->id;
2405  }
2406  
2407  /**
2408   * get the values of an item depending on the given groupid.
2409   * if the feedback is anonymous so the values are shuffled
2410   *
2411   * @global object
2412   * @global object
2413   * @param object $item
2414   * @param int $groupid
2415   * @param int $courseid
2416   * @param bool $ignore_empty if this is set true so empty values are not delivered
2417   * @return array the value-records
2418   */
2419  function feedback_get_group_values($item,
2420                                     $groupid = false,
2421                                     $courseid = false,
2422                                     $ignore_empty = false) {
2423  
2424      global $CFG, $DB;
2425  
2426      //if the groupid is given?
2427      if (intval($groupid) > 0) {
2428          $params = array();
2429          if ($ignore_empty) {
2430              $value = $DB->sql_compare_text('fbv.value');
2431              $ignore_empty_select = "AND $value != :emptyvalue AND $value != :zerovalue";
2432              $params += array('emptyvalue' => '', 'zerovalue' => '0');
2433          } else {
2434              $ignore_empty_select = "";
2435          }
2436  
2437          $query = 'SELECT fbv .  *
2438                      FROM {feedback_value} fbv, {feedback_completed} fbc, {groups_members} gm
2439                     WHERE fbv.item = :itemid
2440                           AND fbv.completed = fbc.id
2441                           AND fbc.userid = gm.userid
2442                           '.$ignore_empty_select.'
2443                           AND gm.groupid = :groupid
2444                  ORDER BY fbc.timemodified';
2445          $params += array('itemid' => $item->id, 'groupid' => $groupid);
2446          $values = $DB->get_records_sql($query, $params);
2447  
2448      } else {
2449          $params = array();
2450          if ($ignore_empty) {
2451              $value = $DB->sql_compare_text('value');
2452              $ignore_empty_select = "AND $value != :emptyvalue AND $value != :zerovalue";
2453              $params += array('emptyvalue' => '', 'zerovalue' => '0');
2454          } else {
2455              $ignore_empty_select = "";
2456          }
2457  
2458          if ($courseid) {
2459              $select = "item = :itemid AND course_id = :courseid ".$ignore_empty_select;
2460              $params += array('itemid' => $item->id, 'courseid' => $courseid);
2461              $values = $DB->get_records_select('feedback_value', $select, $params);
2462          } else {
2463              $select = "item = :itemid ".$ignore_empty_select;
2464              $params += array('itemid' => $item->id);
2465              $values = $DB->get_records_select('feedback_value', $select, $params);
2466          }
2467      }
2468      $params = array('id'=>$item->feedback);
2469      if ($DB->get_field('feedback', 'anonymous', $params) == FEEDBACK_ANONYMOUS_YES) {
2470          if (is_array($values)) {
2471              shuffle($values);
2472          }
2473      }
2474      return $values;
2475  }
2476  
2477  /**
2478   * check for multiple_submit = false.
2479   * if the feedback is global so the courseid must be given
2480   *
2481   * @global object
2482   * @global object
2483   * @param int $feedbackid
2484   * @param int $courseid
2485   * @return boolean true if the feedback already is submitted otherwise false
2486   */
2487  function feedback_is_already_submitted($feedbackid, $courseid = false) {
2488      global $USER, $DB;
2489  
2490      $params = array('userid'=>$USER->id, 'feedback'=>$feedbackid);
2491      if (!$trackings = $DB->get_records_menu('feedback_tracking', $params, '', 'id, completed')) {
2492          return false;
2493      }
2494  
2495      if ($courseid) {
2496          $select = 'completed IN ('.implode(',', $trackings).') AND course_id = ?';
2497          if (!$values = $DB->get_records_select('feedback_value', $select, array($courseid))) {
2498              return false;
2499          }
2500      }
2501  
2502      return true;
2503  }
2504  
2505  /**
2506   * if the completion of a feedback will be continued eg.
2507   * by pagebreak or by multiple submit so the complete must be found.
2508   * if the param $tmp is set true so all things are related to temporary completeds
2509   *
2510   * @global object
2511   * @global object
2512   * @global object
2513   * @param int $feedbackid
2514   * @param boolean $tmp
2515   * @param int $courseid
2516   * @param string $guestid
2517   * @return int the id of the found completed
2518   */
2519  function feedback_get_current_completed($feedbackid,
2520                                          $tmp = false,
2521                                          $courseid = false,
2522                                          $guestid = false) {
2523  
2524      global $USER, $CFG, $DB;
2525  
2526      $tmpstr = $tmp ? 'tmp' : '';
2527  
2528      if (!$courseid) {
2529          if ($guestid) {
2530              $params = array('feedback'=>$feedbackid, 'guestid'=>$guestid);
2531              return $DB->get_record('feedback_completed'.$tmpstr, $params);
2532          } else {
2533              $params = array('feedback'=>$feedbackid, 'userid'=>$USER->id);
2534              return $DB->get_record('feedback_completed'.$tmpstr, $params);
2535          }
2536      }
2537  
2538      $params = array();
2539  
2540      if ($guestid) {
2541          $userselect = "AND fc.guestid = :guestid";
2542          $params['guestid'] = $guestid;
2543      } else {
2544          $userselect = "AND fc.userid = :userid";
2545          $params['userid'] = $USER->id;
2546      }
2547      //if courseid is set the feedback is global.
2548      //there can be more than one completed on one feedback
2549      $sql =  "SELECT DISTINCT fc.*
2550                 FROM {feedback_value{$tmpstr}} fv, {feedback_completed{$tmpstr}} fc
2551                WHERE fv.course_id = :courseid
2552                      AND fv.completed = fc.id
2553                      $userselect
2554                      AND fc.feedback = :feedbackid";
2555      $params['courseid']   = intval($courseid);
2556      $params['feedbackid'] = $feedbackid;
2557  
2558      if (!$sqlresult = $DB->get_records_sql($sql, $params)) {
2559          return false;
2560      }
2561      foreach ($sqlresult as $r) {
2562          return $DB->get_record('feedback_completed'.$tmpstr, array('id'=>$r->id));
2563      }
2564  }
2565  
2566  /**
2567   * get the completeds depending on the given groupid.
2568   *
2569   * @global object
2570   * @global object
2571   * @param object $feedback
2572   * @param int $groupid
2573   * @param int $courseid
2574   * @return mixed array of found completeds otherwise false
2575   */
2576  function feedback_get_completeds_group($feedback, $groupid = false, $courseid = false) {
2577      global $CFG, $DB;
2578  
2579      if (intval($groupid) > 0) {
2580          $query = "SELECT fbc.*
2581                      FROM {feedback_completed} fbc, {groups_members} gm
2582                     WHERE fbc.feedback = ?
2583                           AND gm.groupid = ?
2584                           AND fbc.userid = gm.userid";
2585          if ($values = $DB->get_records_sql($query, array($feedback->id, $groupid))) {
2586              return $values;
2587          } else {
2588              return false;
2589          }
2590      } else {
2591          if ($courseid) {
2592              $query = "SELECT DISTINCT fbc.*
2593                          FROM {feedback_completed} fbc, {feedback_value} fbv
2594                          WHERE fbc.id = fbv.completed
2595                              AND fbc.feedback = ?
2596                              AND fbv.course_id = ?
2597                          ORDER BY random_response";
2598              if ($values = $DB->get_records_sql($query, array($feedback->id, $courseid))) {
2599                  return $values;
2600              } else {
2601                  return false;
2602              }
2603          } else {
2604              if ($values = $DB->get_records('feedback_completed', array('feedback'=>$feedback->id))) {
2605                  return $values;
2606              } else {
2607                  return false;
2608              }
2609          }
2610      }
2611  }
2612  
2613  /**
2614   * get the count of completeds depending on the given groupid.
2615   *
2616   * @global object
2617   * @global object
2618   * @param object $feedback
2619   * @param int $groupid
2620   * @param int $courseid
2621   * @return mixed count of completeds or false
2622   */
2623  function feedback_get_completeds_group_count($feedback, $groupid = false, $courseid = false) {
2624      global $CFG, $DB;
2625  
2626      if ($courseid > 0 AND !$groupid <= 0) {
2627          $sql = "SELECT id, COUNT(item) AS ci
2628                    FROM {feedback_value}
2629                   WHERE course_id  = ?
2630                GROUP BY item ORDER BY ci DESC";
2631          if ($foundrecs = $DB->get_records_sql($sql, array($courseid))) {
2632              $foundrecs = array_values($foundrecs);
2633              return $foundrecs[0]->ci;
2634          }
2635          return false;
2636      }
2637      if ($values = feedback_get_completeds_group($feedback, $groupid)) {
2638          return count($values);
2639      } else {
2640          return false;
2641      }
2642  }
2643  
2644  /**
2645   * deletes all completed-recordsets from a feedback.
2646   * all related data such as values also will be deleted
2647   *
2648   * @global object
2649   * @param int $feedbackid
2650   * @return void
2651   */
2652  function feedback_delete_all_completeds($feedbackid) {
2653      global $DB;
2654  
2655      if (!$completeds = $DB->get_records('feedback_completed', array('feedback'=>$feedbackid))) {
2656          return;
2657      }
2658      foreach ($completeds as $completed) {
2659          feedback_delete_completed($completed->id);
2660      }
2661  }
2662  
2663  /**
2664   * deletes a completed given by completedid.
2665   * all related data such values or tracking data also will be deleted
2666   *
2667   * @global object
2668   * @param int $completedid
2669   * @return boolean
2670   */
2671  function feedback_delete_completed($completedid) {
2672      global $DB, $CFG;
2673      require_once($CFG->libdir.'/completionlib.php');
2674  
2675      if (!$completed = $DB->get_record('feedback_completed', array('id'=>$completedid))) {
2676          return false;
2677      }
2678  
2679      if (!$feedback = $DB->get_record('feedback', array('id'=>$completed->feedback))) {
2680          return false;
2681      }
2682  
2683      if (!$course = $DB->get_record('course', array('id'=>$feedback->course))) {
2684          return false;
2685      }
2686  
2687      if (!$cm = get_coursemodule_from_instance('feedback', $feedback->id)) {
2688          return false;
2689      }
2690  
2691      //first we delete all related values
2692      $DB->delete_records('feedback_value', array('completed'=>$completed->id));
2693  
2694      //now we delete all tracking data
2695      $params = array('completed'=>$completed->id, 'feedback'=>$completed->feedback);
2696      if ($tracking = $DB->get_record('feedback_tracking', $params)) {
2697          $DB->delete_records('feedback_tracking', array('completed'=>$completed->id));
2698      }
2699  
2700      // Update completion state
2701      $completion = new completion_info($course);
2702      if ($completion->is_enabled($cm) && $feedback->completionsubmit) {
2703          $completion->update_state($cm, COMPLETION_INCOMPLETE, $completed->userid);
2704      }
2705      // Last we delete the completed-record.
2706      $return = $DB->delete_records('feedback_completed', array('id'=>$completed->id));
2707  
2708      // Trigger event for the delete action we performed.
2709      $event = \mod_feedback\event\response_deleted::create(array(
2710          'relateduserid' => $completed->userid,
2711          'objectid' => $completedid,
2712          'courseid' => $course->id,
2713          'context' => context_module::instance($cm->id),
2714          'anonymous' => ($completed->anonymous_response == FEEDBACK_ANONYMOUS_YES),
2715          'other' => array(
2716              'cmid' => $cm->id,
2717              'instanceid' => $feedback->id,
2718              'anonymous' => $completed->anonymous_response) // Deprecated.
2719      ));
2720  
2721      $event->add_record_snapshot('feedback_completed', $completed);
2722      $event->add_record_snapshot('course', $course);
2723      $event->add_record_snapshot('feedback', $feedback);
2724  
2725      $event->trigger();
2726  
2727      return $return;
2728  }
2729  
2730  ////////////////////////////////////////////////
2731  ////////////////////////////////////////////////
2732  ////////////////////////////////////////////////
2733  //functions to handle sitecourse mapping
2734  ////////////////////////////////////////////////
2735  
2736  /**
2737   * checks if the course and the feedback is in the table feedback_sitecourse_map.
2738   *
2739   * @global object
2740   * @param int $feedbackid
2741   * @param int $courseid
2742   * @return int the count of records
2743   */
2744  function feedback_is_course_in_sitecourse_map($feedbackid, $courseid) {
2745      global $DB;
2746      $params = array('feedbackid'=>$feedbackid, 'courseid'=>$courseid);
2747      return $DB->count_records('feedback_sitecourse_map', $params);
2748  }
2749  
2750  /**
2751   * checks if the feedback is in the table feedback_sitecourse_map.
2752   *
2753   * @global object
2754   * @param int $feedbackid
2755   * @return boolean
2756   */
2757  function feedback_is_feedback_in_sitecourse_map($feedbackid) {
2758      global $DB;
2759      return $DB->record_exists('feedback_sitecourse_map', array('feedbackid'=>$feedbackid));
2760  }
2761  
2762  /**
2763   * gets the feedbacks from table feedback_sitecourse_map.
2764   * this is used to show the global feedbacks on the feedback block
2765   * all feedbacks with the following criteria will be selected:<br />
2766   *
2767   * 1) all feedbacks which id are listed together with the courseid in sitecoursemap and<br />
2768   * 2) all feedbacks which not are listed in sitecoursemap
2769   *
2770   * @global object
2771   * @param int $courseid
2772   * @return array the feedback-records
2773   */
2774  function feedback_get_feedbacks_from_sitecourse_map($courseid) {
2775      global $DB;
2776  
2777      //first get all feedbacks listed in sitecourse_map with named courseid
2778      $sql = "SELECT f.id AS id,
2779                     cm.id AS cmid,
2780                     f.name AS name,
2781                     f.timeopen AS timeopen,
2782                     f.timeclose AS timeclose
2783              FROM {feedback} f, {course_modules} cm, {feedback_sitecourse_map} sm, {modules} m
2784              WHERE f.id = cm.instance
2785                     AND f.course = '".SITEID."'
2786                     AND m.id = cm.module
2787                     AND m.name = 'feedback'
2788                     AND sm.courseid = ?
2789                     AND sm.feedbackid = f.id";
2790  
2791      if (!$feedbacks1 = $DB->get_records_sql($sql, array($courseid))) {
2792          $feedbacks1 = array();
2793      }
2794  
2795      //second get all feedbacks not listed in sitecourse_map
2796      $feedbacks2 = array();
2797      $sql = "SELECT f.id AS id,
2798                     cm.id AS cmid,
2799                     f.name AS name,
2800                     f.timeopen AS timeopen,
2801                     f.timeclose AS timeclose
2802              FROM {feedback} f, {course_modules} cm, {modules} m
2803              WHERE f.id = cm.instance
2804                     AND f.course = '".SITEID."'
2805                     AND m.id = cm.module
2806                     AND m.name = 'feedback'";
2807      if (!$allfeedbacks = $DB->get_records_sql($sql)) {
2808          $allfeedbacks = array();
2809      }
2810      foreach ($allfeedbacks as $a) {
2811          if (!$DB->record_exists('feedback_sitecourse_map', array('feedbackid'=>$a->id))) {
2812              $feedbacks2[] = $a;
2813          }
2814      }
2815  
2816      return array_merge($feedbacks1, $feedbacks2);
2817  
2818  }
2819  
2820  /**
2821   * gets the courses from table feedback_sitecourse_map.
2822   *
2823   * @global object
2824   * @param int $feedbackid
2825   * @return array the course-records
2826   */
2827  function feedback_get_courses_from_sitecourse_map($feedbackid) {
2828      global $DB;
2829  
2830      $sql = "SELECT f.id, f.courseid, c.fullname, c.shortname
2831                FROM {feedback_sitecourse_map} f, {course} c
2832               WHERE c.id = f.courseid
2833                     AND f.feedbackid = ?
2834            ORDER BY c.fullname";
2835  
2836      return $DB->get_records_sql($sql, array($feedbackid));
2837  
2838  }
2839  
2840  /**
2841   * removes non existing courses or feedbacks from sitecourse_map.
2842   * it shouldn't be called all too often
2843   * a good place for it could be the mapcourse.php or unmapcourse.php
2844   *
2845   * @global object
2846   * @return void
2847   */
2848  function feedback_clean_up_sitecourse_map() {
2849      global $DB;
2850  
2851      $maps = $DB->get_records('feedback_sitecourse_map');
2852      foreach ($maps as $map) {
2853          if (!$DB->get_record('course', array('id'=>$map->courseid))) {
2854              $params = array('courseid'=>$map->courseid, 'feedbackid'=>$map->feedbackid);
2855              $DB->delete_records('feedback_sitecourse_map', $params);
2856              continue;
2857          }
2858          if (!$DB->get_record('feedback', array('id'=>$map->feedbackid))) {
2859              $params = array('courseid'=>$map->courseid, 'feedbackid'=>$map->feedbackid);
2860              $DB->delete_records('feedback_sitecourse_map', $params);
2861              continue;
2862          }
2863  
2864      }
2865  }
2866  
2867  ////////////////////////////////////////////////
2868  ////////////////////////////////////////////////
2869  ////////////////////////////////////////////////
2870  //not relatable functions
2871  ////////////////////////////////////////////////
2872  
2873  /**
2874   * prints the option items of a selection-input item (dropdownlist).
2875   * @param int $startval the first value of the list
2876   * @param int $endval the last value of the list
2877   * @param int $selectval which item should be selected
2878   * @param int $interval the stepsize from the first to the last value
2879   * @return void
2880   */
2881  function feedback_print_numeric_option_list($startval, $endval, $selectval = '', $interval = 1) {
2882      for ($i = $startval; $i <= $endval; $i += $interval) {
2883          if ($selectval == ($i)) {
2884              $selected = 'selected="selected"';
2885          } else {
2886              $selected = '';
2887          }
2888          echo '<option '.$selected.'>'.$i.'</option>';
2889      }
2890  }
2891  
2892  /**
2893   * sends an email to the teachers of the course where the given feedback is placed.
2894   *
2895   * @global object
2896   * @global object
2897   * @uses FEEDBACK_ANONYMOUS_NO
2898   * @uses FORMAT_PLAIN
2899   * @param object $cm the coursemodule-record
2900   * @param object $feedback
2901   * @param object $course
2902   * @param int $userid
2903   * @return void
2904   */
2905  function feedback_send_email($cm, $feedback, $course, $userid) {
2906      global $CFG, $DB;
2907  
2908      if ($feedback->email_notification == 0) {  // No need to do anything
2909          return;
2910      }
2911  
2912      $user = $DB->get_record('user', array('id'=>$userid));
2913  
2914      if (isset($cm->groupmode) && empty($course->groupmodeforce)) {
2915          $groupmode =  $cm->groupmode;
2916      } else {
2917          $groupmode = $course->groupmode;
2918      }
2919  
2920      if ($groupmode == SEPARATEGROUPS) {
2921          $groups = $DB->get_records_sql_menu("SELECT g.name, g.id
2922                                                 FROM {groups} g, {groups_members} m
2923                                                WHERE g.courseid = ?
2924                                                      AND g.id = m.groupid
2925                                                      AND m.userid = ?
2926                                             ORDER BY name ASC", array($course->id, $userid));
2927          $groups = array_values($groups);
2928  
2929          $teachers = feedback_get_receivemail_users($cm->id, $groups);
2930      } else {
2931          $teachers = feedback_get_receivemail_users($cm->id);
2932      }
2933  
2934      if ($teachers) {
2935  
2936          $strfeedbacks = get_string('modulenameplural', 'feedback');
2937          $strfeedback  = get_string('modulename', 'feedback');
2938          $strcompleted  = get_string('completed', 'feedback');
2939  
2940          if ($feedback->anonymous == FEEDBACK_ANONYMOUS_NO) {
2941              $printusername = fullname($user);
2942          } else {
2943              $printusername = get_string('anonymous_user', 'feedback');
2944          }
2945  
2946          foreach ($teachers as $teacher) {
2947              $info = new stdClass();
2948              $info->username = $printusername;
2949              $info->feedback = format_string($feedback->name, true);
2950              $info->url = $CFG->wwwroot.'/mod/feedback/show_entries.php?'.
2951                              'id='.$cm->id.'&'.
2952                              'userid='.$userid.'&'.
2953                              'do_show=showentries';
2954  
2955              $postsubject = $strcompleted.': '.$info->username.' -> '.$feedback->name;
2956              $posttext = feedback_send_email_text($info, $course);
2957  
2958              if ($teacher->mailformat == 1) {
2959                  $posthtml = feedback_send_email_html($info, $course, $cm);
2960              } else {
2961                  $posthtml = '';
2962              }
2963  
2964              if ($feedback->anonymous == FEEDBACK_ANONYMOUS_NO) {
2965                  $eventdata = new stdClass();
2966                  $eventdata->name             = 'submission';
2967                  $eventdata->component        = 'mod_feedback';
2968                  $eventdata->userfrom         = $user;
2969                  $eventdata->userto           = $teacher;
2970                  $eventdata->subject          = $postsubject;
2971                  $eventdata->fullmessage      = $posttext;
2972                  $eventdata->fullmessageformat = FORMAT_PLAIN;
2973                  $eventdata->fullmessagehtml  = $posthtml;
2974                  $eventdata->smallmessage     = '';
2975                  message_send($eventdata);
2976              } else {
2977                  $eventdata = new stdClass();
2978                  $eventdata->name             = 'submission';
2979                  $eventdata->component        = 'mod_feedback';
2980                  $eventdata->userfrom         = $teacher;
2981                  $eventdata->userto           = $teacher;
2982                  $eventdata->subject          = $postsubject;
2983                  $eventdata->fullmessage      = $posttext;
2984                  $eventdata->fullmessageformat = FORMAT_PLAIN;
2985                  $eventdata->fullmessagehtml  = $posthtml;
2986                  $eventdata->smallmessage     = '';
2987                  message_send($eventdata);
2988              }
2989          }
2990      }
2991  }
2992  
2993  /**
2994   * sends an email to the teachers of the course where the given feedback is placed.
2995   *
2996   * @global object
2997   * @uses FORMAT_PLAIN
2998   * @param object $cm the coursemodule-record
2999   * @param object $feedback
3000   * @param object $course
3001   * @return void
3002   */
3003  function feedback_send_email_anonym($cm, $feedback, $course) {
3004      global $CFG;
3005  
3006      if ($feedback->email_notification == 0) { // No need to do anything
3007          return;
3008      }
3009  
3010      $teachers = feedback_get_receivemail_users($cm->id);
3011  
3012      if ($teachers) {
3013  
3014          $strfeedbacks = get_string('modulenameplural', 'feedback');
3015          $strfeedback  = get_string('modulename', 'feedback');
3016          $strcompleted  = get_string('completed', 'feedback');
3017          $printusername = get_string('anonymous_user', 'feedback');
3018  
3019          foreach ($teachers as $teacher) {
3020              $info = new stdClass();
3021              $info->username = $printusername;
3022              $info->feedback = format_string($feedback->name, true);
3023              $info->url = $CFG->wwwroot.'/mod/feedback/show_entries_anonym.php?id='.$cm->id;
3024  
3025              $postsubject = $strcompleted.': '.$info->username.' -> '.$feedback->name;
3026              $posttext = feedback_send_email_text($info, $course);
3027  
3028              if ($teacher->mailformat == 1) {
3029                  $posthtml = feedback_send_email_html($info, $course, $cm);
3030              } else {
3031                  $posthtml = '';
3032              }
3033  
3034              $eventdata = new stdClass();
3035              $eventdata->name             = 'submission';
3036              $eventdata->component        = 'mod_feedback';
3037              $eventdata->userfrom         = $teacher;
3038              $eventdata->userto           = $teacher;
3039              $eventdata->subject          = $postsubject;
3040              $eventdata->fullmessage      = $posttext;
3041              $eventdata->fullmessageformat = FORMAT_PLAIN;
3042              $eventdata->fullmessagehtml  = $posthtml;
3043              $eventdata->smallmessage     = '';
3044              message_send($eventdata);
3045          }
3046      }
3047  }
3048  
3049  /**
3050   * send the text-part of the email
3051   *
3052   * @param object $info includes some infos about the feedback you want to send
3053   * @param object $course
3054   * @return string the text you want to post
3055   */
3056  function feedback_send_email_text($info, $course) {
3057      $coursecontext = context_course::instance($course->id);
3058      $courseshortname = format_string($course->shortname, true, array('context' => $coursecontext));
3059      $posttext  = $courseshortname.' -> '.get_string('modulenameplural', 'feedback').' -> '.
3060                      $info->feedback."\n";
3061      $posttext .= '---------------------------------------------------------------------'."\n";
3062      $posttext .= get_string("emailteachermail", "feedback", $info)."\n";
3063      $posttext .= '---------------------------------------------------------------------'."\n";
3064      return $posttext;
3065  }
3066  
3067  
3068  /**
3069   * send the html-part of the email
3070   *
3071   * @global object
3072   * @param object $info includes some infos about the feedback you want to send
3073   * @param object $course
3074   * @return string the text you want to post
3075   */
3076  function feedback_send_email_html($info, $course, $cm) {
3077      global $CFG;
3078      $coursecontext = context_course::instance($course->id);
3079      $courseshortname = format_string($course->shortname, true, array('context' => $coursecontext));
3080      $course_url = $CFG->wwwroot.'/course/view.php?id='.$course->id;
3081      $feedback_all_url = $CFG->wwwroot.'/mod/feedback/index.php?id='.$course->id;
3082      $feedback_url = $CFG->wwwroot.'/mod/feedback/view.php?id='.$cm->id;
3083  
3084      $posthtml = '<p><font face="sans-serif">'.
3085              '<a href="'.$course_url.'">'.$courseshortname.'</a> ->'.
3086              '<a href="'.$feedback_all_url.'">'.get_string('modulenameplural', 'feedback').'</a> ->'.
3087              '<a href="'.$feedback_url.'">'.$info->feedback.'</a></font></p>';
3088      $posthtml .= '<hr /><font face="sans-serif">';
3089      $posthtml .= '<p>'.get_string('emailteachermailhtml', 'feedback', $info).'</p>';
3090      $posthtml .= '</font><hr />';
3091      return $posthtml;
3092  }
3093  
3094  /**
3095   * @param string $url
3096   * @return string
3097   */
3098  function feedback_encode_target_url($url) {
3099      if (strpos($url, '?')) {
3100          list($part1, $part2) = explode('?', $url, 2); //maximal 2 parts
3101          return $part1 . '?' . htmlentities($part2);
3102      } else {
3103          return $url;
3104      }
3105  }
3106  
3107  /**
3108   * Adds module specific settings to the settings block
3109   *
3110   * @param settings_navigation $settings The settings navigation object
3111   * @param navigation_node $feedbacknode The node to add module settings to
3112   */
3113  function feedback_extend_settings_navigation(settings_navigation $settings,
3114                                               navigation_node $feedbacknode) {
3115  
3116      global $PAGE, $DB;
3117  
3118      if (!$context = context_module::instance($PAGE->cm->id, IGNORE_MISSING)) {
3119          print_error('badcontext');
3120      }
3121  
3122      if (has_capability('mod/feedback:edititems', $context)) {
3123          $questionnode = $feedbacknode->add(get_string('questions', 'feedback'));
3124  
3125          $questionnode->add(get_string('edit_items', 'feedback'),
3126                      new moodle_url('/mod/feedback/edit.php',
3127                                      array('id' => $PAGE->cm->id,
3128                                            'do_show' => 'edit')));
3129  
3130          $questionnode->add(get_string('export_questions', 'feedback'),
3131                      new moodle_url('/mod/feedback/export.php',
3132                                      array('id' => $PAGE->cm->id,
3133                                            'action' => 'exportfile')));
3134  
3135          $questionnode->add(get_string('import_questions', 'feedback'),
3136                      new moodle_url('/mod/feedback/import.php',
3137                                      array('id' => $PAGE->cm->id)));
3138  
3139          $questionnode->add(get_string('templates', 'feedback'),
3140                      new moodle_url('/mod/feedback/edit.php',
3141                                      array('id' => $PAGE->cm->id,
3142                                            'do_show' => 'templates')));
3143      }
3144  
3145      if (has_capability('mod/feedback:viewreports', $context)) {
3146          $feedback = $DB->get_record('feedback', array('id'=>$PAGE->cm->instance));
3147          if ($feedback->course == SITEID) {
3148              $feedbacknode->add(get_string('analysis', 'feedback'),
3149                      new moodle_url('/mod/feedback/analysis_course.php',
3150                                      array('id' => $PAGE->cm->id,
3151                                            'course' => $PAGE->course->id,
3152                                            'do_show' => 'analysis')));
3153          } else {
3154              $feedbacknode->add(get_string('analysis', 'feedback'),
3155                      new moodle_url('/mod/feedback/analysis.php',
3156                                      array('id' => $PAGE->cm->id,
3157                                            'course' => $PAGE->course->id,
3158                                            'do_show' => 'analysis')));
3159          }
3160  
3161          $feedbacknode->add(get_string('show_entries', 'feedback'),
3162                      new moodle_url('/mod/feedback/show_entries.php',
3163                                      array('id' => $PAGE->cm->id,
3164                                            'do_show' => 'showentries')));
3165      }
3166  }
3167  
3168  function feedback_init_feedback_session() {
3169      //initialize the feedback-Session - not nice at all!!
3170      global $SESSION;
3171      if (!empty($SESSION)) {
3172          if (!isset($SESSION->feedback) OR !is_object($SESSION->feedback)) {
3173              $SESSION->feedback = new stdClass();
3174          }
3175      }
3176  }
3177  
3178  /**
3179   * Return a list of page types
3180   * @param string $pagetype current page type
3181   * @param stdClass $parentcontext Block's parent context
3182   * @param stdClass $currentcontext Current context of block
3183   */
3184  function feedback_page_type_list($pagetype, $parentcontext, $currentcontext) {
3185      $module_pagetype = array('mod-feedback-*'=>get_string('page-mod-feedback-x', 'feedback'));
3186      return $module_pagetype;
3187  }
3188  
3189  /**
3190   * Move save the items of the given $feedback in the order of $itemlist.
3191   * @param string $itemlist a comma separated list with item ids
3192   * @param stdClass $feedback
3193   * @return bool true if success
3194   */
3195  function feedback_ajax_saveitemorder($itemlist, $feedback) {
3196      global $DB;
3197  
3198      $result = true;
3199      $position = 0;
3200      foreach ($itemlist as $itemid) {
3201          $position++;
3202          $result = $result && $DB->set_field('feedback_item',
3203                                              'position',
3204                                              $position,
3205                                              array('id'=>$itemid, 'feedback'=>$feedback->id));
3206      }
3207      return $result;
3208  }


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1