Search moodle.org's
Developer Documentation

  • 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 37 and 311]

       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  }