Search moodle.org's
Developer Documentation

See Release Notes

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

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

   1  <?php
   2  
   3  // This file is part of Moodle - http://moodle.org/
   4  //
   5  // Moodle is free software: you can redistribute it and/or modify
   6  // it under the terms of the GNU General Public License as published by
   7  // the Free Software Foundation, either version 3 of the License, or
   8  // (at your option) any later version.
   9  //
  10  // Moodle is distributed in the hope that it will be useful,
  11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13  // GNU General Public License for more details.
  14  //
  15  // You should have received a copy of the GNU General Public License
  16  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  17  
  18  /**
  19   * This file contains the activity completion criteria type class and any
  20   * supporting functions it may require.
  21   *
  22   * @package core_completion
  23   * @category completion
  24   * @copyright 2009 Catalyst IT Ltd
  25   * @author Aaron Barnes <aaronb@catalyst.net.nz>
  26   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  27   */
  28  
  29  defined('MOODLE_INTERNAL') || die();
  30  
  31  /**
  32   * Course completion critieria - completion on activity completion
  33   *
  34   * @package core_completion
  35   * @category completion
  36   * @copyright 2009 Catalyst IT Ltd
  37   * @author Aaron Barnes <aaronb@catalyst.net.nz>
  38   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  39   */
  40  class completion_criteria_activity extends completion_criteria {
  41  
  42      /* @var int Criteria [COMPLETION_CRITERIA_TYPE_ACTIVITY] */
  43      public $criteriatype = COMPLETION_CRITERIA_TYPE_ACTIVITY;
  44  
  45      /**
  46       * Finds and returns a data_object instance based on params.
  47       *
  48       * @param array $params associative arrays varname=>value
  49       * @return completion_criteria_activity data_object instance or false if none found.
  50       */
  51      public static function fetch($params) {
  52          $params['criteriatype'] = COMPLETION_CRITERIA_TYPE_ACTIVITY;
  53          return self::fetch_helper('course_completion_criteria', __CLASS__, $params);
  54      }
  55  
  56      /**
  57       * Add appropriate form elements to the critieria form
  58       *
  59       * @param moodleform $mform  Moodle forms object
  60       * @param stdClass $data details of various modules
  61       */
  62      public function config_form_display(&$mform, $data = null) {
  63          $modnames = get_module_types_names();
  64          $mform->addElement('advcheckbox',
  65                  'criteria_activity['.$data->id.']',
  66                  $modnames[self::get_mod_name($data->module)] . ' - ' . format_string($data->name),
  67                  null,
  68                  array('group' => 1));
  69  
  70          if ($this->id) {
  71              $mform->setDefault('criteria_activity['.$data->id.']', 1);
  72          }
  73      }
  74  
  75      /**
  76       * Update the criteria information stored in the database
  77       *
  78       * @param stdClass $data Form data
  79       */
  80      public function update_config(&$data) {
  81          global $DB;
  82  
  83          if (!empty($data->criteria_activity) && is_array($data->criteria_activity)) {
  84  
  85              $this->course = $data->id;
  86  
  87              // Data comes from advcheckbox, so contains keys for all activities.
  88              // A value of 0 is 'not checked' whereas 1 is 'checked'.
  89              foreach ($data->criteria_activity as $activity => $val) {
  90                  // Only update those which are checked.
  91                  if (!empty($val)) {
  92                      $module = $DB->get_record('course_modules', array('id' => $activity));
  93                      $this->module = self::get_mod_name($module->module);
  94                      $this->moduleinstance = $activity;
  95                      $this->id = null;
  96                      $this->insert();
  97                  }
  98              }
  99          }
 100      }
 101  
 102      /**
 103       * Get module instance module type
 104       *
 105       * @param int $type Module type id
 106       * @return string
 107       */
 108      public static function get_mod_name($type) {
 109          static $types;
 110  
 111          if (!is_array($types)) {
 112              global $DB;
 113              $types = $DB->get_records('modules');
 114          }
 115  
 116          return $types[$type]->name;
 117      }
 118  
 119      /**
 120       * Gets the module instance from the database and returns it.
 121       * If no module instance exists this function returns false.
 122       *
 123       * @return stdClass|bool
 124       */
 125      public function get_mod_instance() {
 126          global $DB;
 127  
 128          return $DB->get_record_sql(
 129              "
 130                  SELECT
 131                      m.*
 132                  FROM
 133                      {{$this->module}} m
 134                  INNER JOIN
 135                      {course_modules} cm
 136                   ON cm.id = {$this->moduleinstance}
 137                  AND m.id = cm.instance
 138              "
 139          );
 140      }
 141  
 142      /**
 143       * Review this criteria and decide if the user has completed
 144       *
 145       * @param completion_completion $completion     The user's completion record
 146       * @param bool $mark Optionally set false to not save changes to database
 147       * @return bool
 148       */
 149      public function review($completion, $mark = true) {
 150          global $DB;
 151  
 152          $course = $DB->get_record('course', array('id' => $completion->course));
 153          $cm = $DB->get_record('course_modules', array('id' => $this->moduleinstance));
 154          $info = new completion_info($course);
 155  
 156          $data = $info->get_data($cm, false, $completion->userid);
 157  
 158          // If the activity is complete
 159          if (in_array($data->completionstate, array(COMPLETION_COMPLETE, COMPLETION_COMPLETE_PASS, COMPLETION_COMPLETE_FAIL))) {
 160              if ($mark) {
 161                  $completion->mark_complete();
 162              }
 163  
 164              return true;
 165          }
 166  
 167          return false;
 168      }
 169  
 170      /**
 171       * Return criteria title for display in reports
 172       *
 173       * @return string
 174       */
 175      public function get_title() {
 176          return get_string('activitiescompleted', 'completion');
 177      }
 178  
 179      /**
 180       * Return a more detailed criteria title for display in reports
 181       *
 182       * @return  string
 183       */
 184      public function get_title_detailed() {
 185          global $DB;
 186          $module = $DB->get_record('course_modules', array('id' => $this->moduleinstance));
 187          $activity = $DB->get_record($this->module, array('id' => $module->instance));
 188  
 189          return shorten_text(format_string($activity->name, true,
 190                  array('context' => context_module::instance($module->id))));
 191      }
 192  
 193      /**
 194       * Return criteria type title for display in reports
 195       *
 196       * @return  string
 197       */
 198      public function get_type_title() {
 199          return get_string('activities', 'completion');
 200      }
 201  
 202      /**
 203       * Find users who have completed this criteria and mark them accordingly
 204       */
 205      public function cron() {
 206          global $DB;
 207  
 208          // Get all users who meet this criteria
 209          $sql = '
 210              SELECT DISTINCT
 211                  c.id AS course,
 212                  cr.id AS criteriaid,
 213                  ra.userid AS userid,
 214                  mc.timemodified AS timecompleted
 215              FROM
 216                  {course_completion_criteria} cr
 217              INNER JOIN
 218                  {course} c
 219               ON cr.course = c.id
 220              INNER JOIN
 221                  {context} con
 222               ON con.instanceid = c.id
 223              INNER JOIN
 224                  {role_assignments} ra
 225                ON ra.contextid = con.id
 226              INNER JOIN
 227                  {course_modules_completion} mc
 228               ON mc.coursemoduleid = cr.moduleinstance
 229              AND mc.userid = ra.userid
 230              LEFT JOIN
 231                  {course_completion_crit_compl} cc
 232               ON cc.criteriaid = cr.id
 233              AND cc.userid = ra.userid
 234              WHERE
 235                  cr.criteriatype = '.COMPLETION_CRITERIA_TYPE_ACTIVITY.'
 236              AND con.contextlevel = '.CONTEXT_COURSE.'
 237              AND c.enablecompletion = 1
 238              AND cc.id IS NULL
 239              AND (
 240                  mc.completionstate = '.COMPLETION_COMPLETE.'
 241               OR mc.completionstate = '.COMPLETION_COMPLETE_PASS.'
 242               OR mc.completionstate = '.COMPLETION_COMPLETE_FAIL.'
 243                  )
 244          ';
 245  
 246          // Loop through completions, and mark as complete
 247          $rs = $DB->get_recordset_sql($sql);
 248          foreach ($rs as $record) {
 249              $completion = new completion_criteria_completion((array) $record, DATA_OBJECT_FETCH_BY_KEY);
 250              $completion->mark_complete($record->timecompleted);
 251          }
 252          $rs->close();
 253      }
 254  
 255      /**
 256       * Return criteria progress details for display in reports
 257       *
 258       * @param completion_completion $completion The user's completion record
 259       * @return array An array with the following keys:
 260       *     type, criteria, requirement, status
 261       */
 262      public function get_details($completion) {
 263          // Get completion info
 264          $modinfo = get_fast_modinfo($completion->course);
 265          $cm = $modinfo->get_cm($this->moduleinstance);
 266  
 267          $details = array();
 268          $details['type'] = $this->get_title();
 269          if ($cm->has_view()) {
 270              $details['criteria'] = html_writer::link($cm->url, $cm->get_formatted_name());
 271          } else {
 272              $details['criteria'] = $cm->get_formatted_name();
 273          }
 274  
 275          // Build requirements
 276          $details['requirement'] = array();
 277  
 278          if ($cm->completion == COMPLETION_TRACKING_MANUAL) {
 279              $details['requirement'][] = get_string('markingyourselfcomplete', 'completion');
 280          } elseif ($cm->completion == COMPLETION_TRACKING_AUTOMATIC) {
 281              if ($cm->completionview) {
 282                  $modulename = core_text::strtolower(get_string('modulename', $this->module));
 283                  $details['requirement'][] = get_string('viewingactivity', 'completion', $modulename);
 284              }
 285  
 286              if (!is_null($cm->completiongradeitemnumber)) {
 287                  $details['requirement'][] = get_string('achievinggrade', 'completion');
 288              }
 289          }
 290  
 291          $details['requirement'] = implode(', ', $details['requirement']);
 292  
 293          $details['status'] = '';
 294  
 295          return $details;
 296      }
 297  
 298      /**
 299       * Return pix_icon for display in reports.
 300       *
 301       * @param string $alt The alt text to use for the icon
 302       * @param array $attributes html attributes
 303       * @return pix_icon
 304       */
 305      public function get_icon($alt, array $attributes = null) {
 306          return new pix_icon('icon', $alt, 'mod_'.$this->module, $attributes);
 307      }
 308  }