Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   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   * Class for user_competency_course persistence.
  19   *
  20   * @package    core_competency
  21   * @copyright  2016 Jun Pataleta
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  namespace core_competency;
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  use context_course;
  28  use context_user;
  29  use lang_string;
  30  
  31  /**
  32   * Class for loading/storing user_competency_course from the DB.
  33   *
  34   * @copyright  2016 Jun Pataleta
  35   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  36   */
  37  class user_competency_course extends persistent {
  38  
  39      /** Table name for user_competency persistency */
  40      const TABLE = 'competency_usercompcourse';
  41  
  42      /**
  43       * Return the definition of the properties of this model.
  44       *
  45       * @return array
  46       */
  47      protected static function define_properties() {
  48          return array(
  49              'userid' => array(
  50                  'type' => PARAM_INT,
  51              ),
  52              'courseid' => array(
  53                  'type' => PARAM_INT
  54              ),
  55              'competencyid' => array(
  56                  'type' => PARAM_INT,
  57              ),
  58              'proficiency' => array(
  59                  'type' => PARAM_BOOL,
  60                  'default' => null,
  61                  'null' => NULL_ALLOWED,
  62              ),
  63              'grade' => array(
  64                  'type' => PARAM_INT,
  65                  'default' => null,
  66                  'null' => NULL_ALLOWED,
  67              ),
  68          );
  69      }
  70  
  71      /**
  72       * Return the competency Object.
  73       *
  74       * @return competency Competency Object
  75       */
  76      public function get_competency() {
  77          return new competency($this->get('competencyid'));
  78      }
  79  
  80      /**
  81       * Get the context.
  82       *
  83       * @return context The context.
  84       */
  85      public function get_context() {
  86          return context_user::instance($this->get('userid'));
  87      }
  88  
  89      /**
  90       * Create a new user_competency_course object.
  91       *
  92       * Note, this is intended to be used to create a blank relation, for instance when
  93       * the record was not found in the database. This does not save the model.
  94       *
  95       * @param  int $userid The user ID.
  96       * @param  int $competencyid The competency ID.
  97       * @param  int $courseid The course ID.
  98       * @return \core_competency\user_competency_course
  99       */
 100      public static function create_relation($userid, $competencyid, $courseid) {
 101          $data = new \stdClass();
 102          $data->userid = $userid;
 103          $data->competencyid = $competencyid;
 104          $data->courseid = $courseid;
 105  
 106          $relation = new user_competency_course(0, $data);
 107          return $relation;
 108      }
 109  
 110      /**
 111       * Validate the user ID.
 112       *
 113       * @param int $value The value.
 114       * @return true|lang_string
 115       */
 116      protected function validate_userid($value) {
 117          global $DB;
 118  
 119          if (!$DB->record_exists('user', array('id' => $value))) {
 120              return new lang_string('invaliduserid', 'error');
 121          }
 122  
 123          return true;
 124      }
 125  
 126      /**
 127       * Validate the competency ID.
 128       *
 129       * @param int $value The value.
 130       * @return true|lang_string
 131       */
 132      protected function validate_competencyid($value) {
 133          if (!competency::record_exists($value)) {
 134              return new lang_string('errornocompetency', 'core_competency', $value);
 135          }
 136  
 137          return true;
 138      }
 139  
 140      /**
 141       * Validate course ID.
 142       *
 143       * @param int $value The course ID.
 144       * @return true|lang_string
 145       */
 146      protected function validate_courseid($value) {
 147          if (!context_course::instance($value, IGNORE_MISSING)) {
 148              return new lang_string('errorinvalidcourse', 'core_competency', $value);
 149          }
 150  
 151          return true;
 152      }
 153  
 154      /**
 155       * Validate the proficiency.
 156       *
 157       * @param int $value The value.
 158       * @return true|lang_string
 159       */
 160      protected function validate_proficiency($value) {
 161          $grade = $this->get('grade');
 162  
 163          if ($grade !== null && $value === null) {
 164              // We must set a proficiency when we set a grade.
 165              return new lang_string('invaliddata', 'error');
 166  
 167          } else if ($grade === null && $value !== null) {
 168              // We must not set a proficiency when we don't set a grade.
 169              return new lang_string('invaliddata', 'error');
 170          }
 171  
 172          return true;
 173      }
 174  
 175      /**
 176       * Validate the grade.
 177       *
 178       * @param int $value The value.
 179       * @return true|lang_string
 180       */
 181      protected function validate_grade($value) {
 182          if ($value !== null) {
 183              if ($value <= 0) {
 184                  return new lang_string('invalidgrade', 'core_competency');
 185              }
 186  
 187              // TODO MDL-52243 Use a core method to validate the grade_scale item.
 188              // Check if grade exist in the scale item values.
 189              $competency = $this->get_competency();
 190              if (!array_key_exists($value - 1 , $competency->get_scale()->scale_items)) {
 191                  return new lang_string('invalidgrade', 'core_competency');
 192              }
 193          }
 194  
 195          return true;
 196      }
 197  
 198      /**
 199       * Get multiple user_competency_course for a user.
 200       *
 201       * @param  int $userid
 202       * @param  int $courseid
 203       * @param  array  $competenciesorids Limit search to those competencies, or competency IDs.
 204       * @return \core_competency\user_competency_course[]
 205       */
 206      public static function get_multiple($userid, $courseid, array $competenciesorids = null) {
 207          global $DB;
 208  
 209          $params = array();
 210          $params['userid'] = $userid;
 211          $params['courseid'] = $courseid;
 212          $sql = '1 = 1';
 213  
 214          if (!empty($competenciesorids)) {
 215              $test = reset($competenciesorids);
 216              if (is_number($test)) {
 217                  $ids = $competenciesorids;
 218              } else {
 219                  $ids = array();
 220                  foreach ($competenciesorids as $comp) {
 221                      $ids[] = $comp->get('id');
 222                  }
 223              }
 224  
 225              list($insql, $inparams) = $DB->get_in_or_equal($ids, SQL_PARAMS_NAMED);
 226              $params += $inparams;
 227              $sql = "competencyid $insql";
 228          }
 229  
 230          // Order by ID to prevent random ordering.
 231          return self::get_records_select("userid = :userid AND courseid = :courseid AND $sql", $params, 'id ASC');
 232      }
 233  
 234      /**
 235       * Count the proficient competencies in this course for one user.
 236       *
 237       * @param int $courseid The course id
 238       * @param int $userid The user id
 239       * @return int
 240       */
 241      public static function count_proficient_competencies($courseid, $userid) {
 242          global $DB;
 243  
 244          $sql = 'SELECT COUNT(comp.id)
 245                    FROM {' . self::TABLE . '} usercoursecomp
 246                    JOIN {' . course_competency::TABLE . '} cc
 247                      ON usercoursecomp.competencyid = cc.competencyid AND cc.courseid = usercoursecomp.courseid
 248                    JOIN {' . competency::TABLE . '} comp
 249                      ON usercoursecomp.competencyid = comp.id
 250                   WHERE usercoursecomp.courseid = ? AND usercoursecomp.userid = ? AND usercoursecomp.proficiency = ?';
 251          $params = array($courseid, $userid, true);
 252  
 253          $results = $DB->count_records_sql($sql, $params);
 254  
 255          return $results;
 256      }
 257  
 258      /**
 259       * Get the list of competencies that were completed the least times in a course.
 260       *
 261       * @param int $courseid
 262       * @param int $skip The number of competencies to skip
 263       * @param int $limit The max number of competencies to return
 264       * @return competency[]
 265       */
 266      public static function get_least_proficient_competencies_for_course($courseid, $skip = 0, $limit = 0) {
 267          global $DB;
 268  
 269          $fields = competency::get_sql_fields('c', 'c_');
 270          $params = array('courseid' => $courseid);
 271          $sql = 'SELECT ' . $fields . '
 272                    FROM (SELECT cc.competencyid, SUM(COALESCE(ucc.proficiency, 0)) AS timesproficient
 273                            FROM {' . course_competency::TABLE . '} cc
 274                       LEFT JOIN {' . self::TABLE . '} ucc
 275                                  ON ucc.competencyid = cc.competencyid
 276                                 AND ucc.courseid = cc.courseid
 277                           WHERE cc.courseid = :courseid
 278                        GROUP BY cc.competencyid
 279                       ) p
 280                    JOIN {' . competency::TABLE . '} c
 281                      ON c.id = p.competencyid
 282                ORDER BY p.timesproficient ASC, c.id DESC';
 283  
 284          $results = $DB->get_records_sql($sql, $params, $skip, $limit);
 285  
 286          $comps = array();
 287          foreach ($results as $r) {
 288              $c = competency::extract_record($r, 'c_');
 289              $comps[] = new competency(0, $c);
 290          }
 291          return $comps;
 292      }
 293  }