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.

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

   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 persistence.
  19   *
  20   * @package    core_competency
  21   * @copyright  2015 Serge Gauthier
  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 coding_exception;
  28  use context_course;
  29  use context_user;
  30  use comment;
  31  use lang_string;
  32  
  33  /**
  34   * Class for loading/storing user_competency from the DB.
  35   *
  36   * @copyright  2015 Serge Gauthier
  37   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  38   */
  39  class user_competency extends persistent {
  40  
  41      /** Table name for user_competency persistency */
  42      const TABLE = 'competency_usercomp';
  43  
  44      /** Idle status */
  45      const STATUS_IDLE = 0;
  46  
  47      /** Waiting for review status */
  48      const STATUS_WAITING_FOR_REVIEW = 1;
  49  
  50      /** In review status */
  51      const STATUS_IN_REVIEW = 2;
  52  
  53      /**
  54       * Return the definition of the properties of this model.
  55       *
  56       * @return array
  57       */
  58      protected static function define_properties() {
  59          return array(
  60              'userid' => array(
  61                  'type' => PARAM_INT,
  62              ),
  63              'competencyid' => array(
  64                  'type' => PARAM_INT,
  65              ),
  66              'status' => array(
  67                  'choices' => array(
  68                      self::STATUS_IDLE,
  69                      self::STATUS_WAITING_FOR_REVIEW,
  70                      self::STATUS_IN_REVIEW,
  71                  ),
  72                  'type' => PARAM_INT,
  73                  'default' => self::STATUS_IDLE,
  74              ),
  75              'reviewerid' => array(
  76                  'type' => PARAM_INT,
  77                  'default' => null,
  78                  'null' => NULL_ALLOWED,
  79              ),
  80              'proficiency' => array(
  81                  'type' => PARAM_BOOL,
  82                  'default' => null,
  83                  'null' => NULL_ALLOWED,
  84              ),
  85              'grade' => array(
  86                  'type' => PARAM_INT,
  87                  'default' => null,
  88                  'null' => NULL_ALLOWED,
  89              ),
  90          );
  91      }
  92  
  93      /**
  94       * Whether the current user can comment on this user competency.
  95       *
  96       * @return bool
  97       */
  98      public function can_comment() {
  99          return static::can_comment_user($this->get('userid'));
 100      }
 101  
 102      /**
 103       * Whether the current user can read this user competency.
 104       *
 105       * @return bool
 106       */
 107      public function can_read() {
 108          return static::can_read_user($this->get('userid'));
 109      }
 110  
 111      /**
 112       * Whether the current user can read comments on this user competency.
 113       *
 114       * @return bool
 115       */
 116      public function can_read_comments() {
 117          return static::can_read_comments_user($this->get('userid'));
 118      }
 119  
 120      /**
 121       * Can the current user send the user competency for review?
 122       *
 123       * @return bool
 124       */
 125      public function can_request_review() {
 126          return static::can_request_review_user($this->get('userid'));
 127      }
 128  
 129      /**
 130       * Can the current user review the user competency?
 131       *
 132       * @return bool
 133       */
 134      public function can_review() {
 135          return static::can_review_user($this->get('userid'));
 136      }
 137  
 138      /**
 139       * Human readable status name.
 140       *
 141       * @param int $status The status code.
 142       * @return lang_string
 143       */
 144      public static function get_status_name($status) {
 145  
 146          switch ($status) {
 147              case self::STATUS_IDLE:
 148                  $strname = 'idle';
 149                  break;
 150              case self::STATUS_WAITING_FOR_REVIEW:
 151                  $strname = 'waitingforreview';
 152                  break;
 153              case self::STATUS_IN_REVIEW:
 154                  $strname = 'inreview';
 155                  break;
 156              default:
 157                  throw new \moodle_exception('errorusercomptencystatus', 'core_competency', '', $status);
 158                  break;
 159          }
 160  
 161          return new lang_string('usercompetencystatus_' . $strname, 'core_competency');
 162      }
 163  
 164      /**
 165       * Get list of competency status.
 166       *
 167       * @return array
 168       */
 169      public static function get_status_list() {
 170  
 171          static $list = null;
 172  
 173          if ($list === null) {
 174              $list = array(
 175                  self::STATUS_IDLE => self::get_status_name(self::STATUS_IDLE),
 176                  self::STATUS_WAITING_FOR_REVIEW => self::get_status_name(self::STATUS_WAITING_FOR_REVIEW),
 177                  self::STATUS_IN_REVIEW => self::get_status_name(self::STATUS_IN_REVIEW));
 178          }
 179  
 180          return $list;
 181      }
 182  
 183      /**
 184       * Get the comment object.
 185       *
 186       * @return comment
 187       */
 188      public function get_comment_object() {
 189          global $CFG;
 190          require_once($CFG->dirroot . '/comment/lib.php');
 191  
 192          if (!$this->get('id')) {
 193              throw new coding_exception('The user competency record must exist.');
 194          }
 195  
 196          $comment = new comment((object) array(
 197              'context' => $this->get_context(),
 198              'component' => 'competency',    // This cannot be named 'core_competency'.
 199              'itemid' => $this->get('id'),
 200              'area' => 'user_competency',
 201              'showcount' => true,
 202          ));
 203          $comment->set_fullwidth(true);
 204          return $comment;
 205      }
 206  
 207      /**
 208       * Return the competency Object.
 209       *
 210       * @return competency Competency Object
 211       */
 212      public function get_competency() {
 213          return new competency($this->get('competencyid'));
 214      }
 215  
 216      /**
 217       * Get the context.
 218       *
 219       * @return context The context.
 220       */
 221      public function get_context() {
 222          return context_user::instance($this->get('userid'));
 223      }
 224  
 225      /**
 226       * Find the plans for the user and this competency.
 227       *
 228       * Note that this:
 229       * - does not perform any capability check.
 230       * - may return completed plans.
 231       * - may return an empty array.
 232       *
 233       * @return plans[]
 234       */
 235      public function get_plans() {
 236          return plan::get_by_user_and_competency($this->get('userid'), $this->get('competencyid'));
 237      }
 238  
 239      /**
 240       * Validate the user ID.
 241       *
 242       * @param int $value The value.
 243       * @return true|lang_string
 244       */
 245      protected function validate_userid($value) {
 246          global $DB;
 247  
 248          if (!$DB->record_exists('user', array('id' => $value))) {
 249              return new lang_string('invaliduserid', 'error');
 250          }
 251  
 252          return true;
 253      }
 254  
 255      /**
 256       * Validate the competency ID.
 257       *
 258       * @param int $value The value.
 259       * @return true|lang_string
 260       */
 261      protected function validate_competencyid($value) {
 262          if (!competency::record_exists($value)) {
 263              return new lang_string('errornocompetency', 'core_competency', $value);
 264          }
 265  
 266          return true;
 267      }
 268  
 269      /**
 270       * Validate the proficiency.
 271       *
 272       * @param int $value The value.
 273       * @return true|lang_string
 274       */
 275      protected function validate_proficiency($value) {
 276          $grade = $this->get('grade');
 277  
 278          if ($grade !== null && $value === null) {
 279              // We must set a proficiency when we set a grade.
 280              return new lang_string('invaliddata', 'error');
 281  
 282          } else if ($grade === null && $value !== null) {
 283              // We must not set a proficiency when we don't set a grade.
 284              return new lang_string('invaliddata', 'error');
 285          }
 286  
 287          return true;
 288      }
 289  
 290      /**
 291       * Validate the reviewer ID.
 292       *
 293       * @param int $value The value.
 294       * @return true|lang_string
 295       */
 296      protected function validate_reviewerid($value) {
 297          global $DB;
 298  
 299          if ($value !== null && !$DB->record_exists('user', array('id' => $value))) {
 300              return new lang_string('invaliduserid', 'error');
 301          }
 302  
 303          return true;
 304      }
 305  
 306      /**
 307       * Validate the grade.
 308       *
 309       * @param int $value The value.
 310       * @return true|lang_string
 311       */
 312      protected function validate_grade($value) {
 313          if ($value !== null) {
 314              if ($value <= 0) {
 315                  return new lang_string('invalidgrade', 'core_competency');
 316              }
 317  
 318              // TODO MDL-52243 Use a core method to validate the grade_scale item.
 319              // Check if grade exist in the scale item values.
 320              $competency = $this->get_competency();
 321              if (!array_key_exists($value - 1 , $competency->get_scale()->scale_items)) {
 322                  return new lang_string('invalidgrade', 'core_competency');
 323              }
 324          }
 325  
 326          return true;
 327      }
 328  
 329      /**
 330       * Can the current user comment on a user's competency?
 331       *
 332       * @param int $userid The user ID the competency belongs to.
 333       * @return bool
 334       */
 335      public static function can_comment_user($userid) {
 336          global $USER;
 337  
 338          $capabilities = array('moodle/competency:usercompetencycomment');
 339          if ($USER->id == $userid) {
 340              $capabilities[] = 'moodle/competency:usercompetencycommentown';
 341          }
 342  
 343          if (has_any_capability($capabilities, context_user::instance($userid))) {
 344              return true;
 345          }
 346  
 347          return false;
 348      }
 349  
 350      /**
 351       * Can the current user grade a user's user competency?
 352       *
 353       * @param int $userid The user ID the competency belongs to.
 354       * @return bool
 355       */
 356      public static function can_grade_user($userid) {
 357          $ratecap = 'moodle/competency:competencygrade';
 358          return has_capability($ratecap, context_user::instance($userid));
 359      }
 360  
 361      /**
 362       * Can the current user grade a user's user competency in a course?
 363       *
 364       * @param int $userid The user ID the competency belongs to.
 365       * @param int $courseid The course ID.
 366       * @return bool
 367       */
 368      public static function can_grade_user_in_course($userid, $courseid) {
 369          $ratecap = 'moodle/competency:competencygrade';
 370          return has_capability($ratecap, context_course::instance($courseid))
 371              || static::can_grade_user($userid);
 372      }
 373  
 374      /**
 375       * Can the current user read the comments on a user's competency?
 376       *
 377       * @param int $userid The user ID the competency belongs to.
 378       * @return bool
 379       */
 380      public static function can_read_comments_user($userid) {
 381          // Everyone who can read the user competency can read the comments.
 382          return static::can_read_user($userid);
 383      }
 384  
 385      /**
 386       * Can the current user read the user competencies of a user in a course?
 387       *
 388       * @param int $userid The user ID the competency belongs to.
 389       * @param int $courseid The course ID.
 390       * @return bool
 391       */
 392      public static function can_read_user_in_course($userid, $courseid) {
 393          $capability = 'moodle/competency:usercompetencyview';
 394          return has_capability($capability, context_course::instance($courseid))
 395              || static::can_read_user($userid);
 396      }
 397  
 398      /**
 399       * Can the current user read a user's competency?
 400       *
 401       * @param int $userid The user ID the competency belongs to.
 402       * @return bool
 403       */
 404      public static function can_read_user($userid) {
 405          $capability = 'moodle/competency:usercompetencyview';
 406          return has_capability($capability, context_user::instance($userid))
 407              || plan::can_read_user($userid);
 408      }
 409  
 410      /**
 411       * Can the current user send a user's competency for review?
 412       *
 413       * Note that the status 'review' is not meant to be used for student to self-assess
 414       * themselves, then to ask the teacher to review their assessment. It is more intended
 415       * for a student to provide evidence of prior learning and request their review.
 416       *
 417       * @param int $userid The user ID the competency belongs to.
 418       * @return bool
 419       */
 420      public static function can_request_review_user($userid) {
 421          global $USER;
 422  
 423          $capabilities = array('moodle/competency:usercompetencyrequestreview');
 424          if ($USER->id == $userid) {
 425              $capabilities[] = 'moodle/competency:usercompetencyrequestreviewown';
 426          }
 427  
 428          if (has_any_capability($capabilities, context_user::instance($userid))) {
 429              return true;
 430          }
 431  
 432          return false;
 433      }
 434  
 435      /**
 436       * Can the current user review the user competency?
 437       *
 438       * @param int $userid The user ID the competency belongs to.
 439       * @return bool
 440       */
 441      public static function can_review_user($userid) {
 442          $capability = 'moodle/competency:usercompetencyreview';
 443          return has_capability($capability, context_user::instance($userid));
 444      }
 445  
 446      /**
 447       * Create a new user_competency object.
 448       *
 449       * Note, this is intended to be used to create a blank relation, for instance when
 450       * the record was not found in the database. This does not save the model.
 451       *
 452       * @param  int $userid The user ID.
 453       * @param  int $competencyid The competency ID.
 454       * @return \core_competency\user_competency
 455       */
 456      public static function create_relation($userid, $competencyid) {
 457          $relation = new user_competency(0, (object) array('userid' => $userid, 'competencyid' => $competencyid));
 458          return $relation;
 459      }
 460  
 461      /**
 462       * Fetch a competency by user competency ID.
 463       *
 464       * This is a convenience method to attempt to efficiently fetch a competency when
 465       * the only information we have is the user_competency ID, in evidence for instance.
 466       *
 467       * @param  int $id The user competency ID.
 468       * @return competency
 469       */
 470      public static function get_competency_by_usercompetencyid($id) {
 471          global $DB;
 472          $sql = "SELECT c.*
 473                    FROM {" . self::TABLE . "} uc
 474                    JOIN {" . competency::TABLE . "} c
 475                      ON c.id = uc.competencyid
 476                   WHERE uc.id = ?";
 477          $record = $DB->get_record_sql($sql, array($id), MUST_EXIST);
 478          return new competency(0, $record);
 479      }
 480  
 481      /**
 482       * Get multiple user_competency for a user.
 483       *
 484       * @param  int $userid
 485       * @param  array  $competenciesorids Limit search to those competencies, or competency IDs.
 486       * @return \core_competency\user_competency[]
 487       */
 488      public static function get_multiple($userid, array $competenciesorids = null) {
 489          global $DB;
 490  
 491          $params = array();
 492          $params['userid'] = $userid;
 493          $sql = '1 = 1';
 494  
 495          if (!empty($competenciesorids)) {
 496              $test = reset($competenciesorids);
 497              if (is_number($test)) {
 498                  $ids = $competenciesorids;
 499              } else {
 500                  $ids = array();
 501                  foreach ($competenciesorids as $comp) {
 502                      $ids[] = $comp->get('id');
 503                  }
 504              }
 505  
 506              list($insql, $inparams) = $DB->get_in_or_equal($ids, SQL_PARAMS_NAMED);
 507              $params += $inparams;
 508              $sql = "competencyid $insql";
 509          }
 510  
 511          // Order by ID to prevent random ordering.
 512          return self::get_records_select("userid = :userid AND $sql", $params, 'id ASC');
 513      }
 514  
 515      /**
 516       * Checks if a competency has user competency records.
 517       *
 518       * @param  int $competencyid The competency ID
 519       * @return boolean
 520       */
 521      public static function has_records_for_competency($competencyid) {
 522          return self::record_exists_select('competencyid = ?', array($competencyid));
 523      }
 524  
 525      /**
 526       * Checks if any of the competencies of a framework has a user competency record.
 527       *
 528       * @param  int $frameworkid The competency framework ID.
 529       * @return boolean
 530       */
 531      public static function has_records_for_framework($frameworkid) {
 532          global $DB;
 533  
 534          $sql = "SELECT 'x'
 535                    FROM {" . self::TABLE . "} uc
 536                    JOIN {" . competency::TABLE . "} c
 537                      ON uc.competencyid = c.id
 538                   WHERE c.competencyframeworkid = ?";
 539          $params = array($frameworkid);
 540  
 541          return $DB->record_exists_sql($sql, $params);
 542      }
 543  
 544      /**
 545       * Check if user competency has records for competencies.
 546       *
 547       * @param array $competencyids The competencies ids.
 548       * @return boolean Return true if the delete was successfull.
 549       */
 550      public static function has_records_for_competencies($competencyids) {
 551          global $DB;
 552          list($insql, $params) = $DB->get_in_or_equal($competencyids, SQL_PARAMS_NAMED);
 553          return self::record_exists_select("competencyid $insql", $params);
 554      }
 555  
 556  }