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   * Template cohort persistent.
  19   *
  20   * @package    core_competency
  21   * @copyright  2015 Frédéric Massart - FMCorz.net
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace core_competency;
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  use lang_string;
  29  use core_competency\template;
  30  
  31  /**
  32   * Template cohort persistent.
  33   *
  34   * @package    core_competency
  35   * @copyright  2015 Frédéric Massart - FMCorz.net
  36   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37   */
  38  class template_cohort extends persistent {
  39  
  40      const TABLE = 'competency_templatecohort';
  41  
  42      /** 2 hours of threshold to prevent expired plans **/
  43      const DUEDATE_THRESHOLD = 7200;
  44  
  45      /**
  46       * Return the custom definition of the properties of this model.
  47       *
  48       * @return array Where keys are the property names.
  49       */
  50      protected static function define_properties() {
  51          return array(
  52              'templateid' => array(
  53                  'type' => PARAM_INT
  54              ),
  55              'cohortid' => array(
  56                  'type' => PARAM_INT
  57              )
  58          );
  59      }
  60  
  61      /**
  62       * Validate the cohort ID.
  63       *
  64       * @param  int $value The cohort ID.
  65       * @return true|lang_string
  66       */
  67      protected function validate_cohortid($value) {
  68          global $DB;
  69          if (!$DB->record_exists('cohort', array('id' => $value))) {
  70              return new lang_string('invaliddata', 'error');
  71          }
  72          return true;
  73      }
  74  
  75      /**
  76       * Validate the template ID.
  77       *
  78       * @param  int $value The template ID.
  79       * @return true|lang_string
  80       */
  81      protected function validate_templateid($value) {
  82          if (!template::record_exists($value)) {
  83              return new lang_string('invaliddata', 'error');
  84          }
  85          return true;
  86      }
  87  
  88      /**
  89       * Return an array of user IDs for which the plans are missing.
  90       *
  91       * Plans are considered as missing when a member of a cohort does not have a plan created.
  92       * When the parameter $unlinkedaremissing is set to false, plans that were unlinked from
  93       * their template will be ignored so that we do not recreate unlinked plans endlessly.
  94       *
  95       * This method ignores the due date of the template.
  96       *
  97       * @param  int     $templateid The template ID.
  98       * @param  int     $cohortid The cohort ID.
  99       * @param  boolean $unlinkedaremissing When true, unlinked plans are considered as missing.
 100       * @return int[]   User IDs.
 101       */
 102      public static function get_missing_plans($templateid, $cohortid, $unlinkedaremissing = false) {
 103          global $DB;
 104  
 105          $skipsql = '';
 106          $skipparams = array();
 107          if (!$unlinkedaremissing) {
 108              $skipsql = 'OR p.origtemplateid = :origtemplateid';
 109              $skipparams = array('origtemplateid' => $templateid);
 110          }
 111  
 112          $sql = "SELECT cm.userid
 113                    FROM {cohort_members} cm
 114               LEFT JOIN {" . plan::TABLE . "} p
 115                      ON p.userid = cm.userid
 116                     AND (p.templateid = :templateid
 117                          $skipsql)
 118                   WHERE cm.cohortid = :cohortid
 119                     AND p.id IS NULL";
 120          $params = array('templateid' => $templateid, 'cohortid' => $cohortid) + $skipparams;
 121  
 122          return $DB->get_fieldset_sql($sql, $params);
 123      }
 124  
 125      /**
 126       * Get a relation.
 127       *
 128       * This does not perform any validation on the data passed. If the relation exists in the database
 129       * then it is loaded in a the model, if not then it is up to the developer to save the model.
 130       *
 131       * @param int $templateid
 132       * @param int $cohortid
 133       * @return template_cohort
 134       */
 135      public static function get_relation($templateid, $cohortid) {
 136          global $DB;
 137  
 138          $params = array(
 139              'templateid' => $templateid,
 140              'cohortid' => $cohortid
 141          );
 142  
 143          $relation = new static(null, (object) $params);
 144          if ($record = $DB->get_record(self::TABLE, $params)) {
 145              $relation->from_record($record);
 146          }
 147  
 148          return $relation;
 149      }
 150  
 151      /**
 152       * Get a relations by templateid.
 153       *
 154       * This does not perform any validation on the data passed. If the relation exists in the database
 155       * then it is loaded in a the model, if not then it is up to the developer to save the model.
 156       *
 157       * @param int $templateid
 158       * @return template_cohort[] array of template cohort
 159       */
 160      public static function get_relations_by_templateid($templateid) {
 161          global $DB;
 162  
 163          $params = array(
 164              'templateid' => $templateid
 165          );
 166  
 167          $relations = array();
 168          $records = $DB->get_records(self::TABLE, $params);
 169          foreach ($records as $record) {
 170              $relations[] = new template_cohort(0, $record);
 171          }
 172  
 173          return $relations;
 174      }
 175  
 176      /**
 177       * Return an array of templates persistent with their missing userids.
 178       *
 179       * Note that only cohorts associated with visible templates are considered,
 180       * as well as only templates with a due date in the future, or no due date.
 181       *
 182       * @param int $lastruntime  The last time the Cohort ssync task ran.
 183       * @param bool $unlinkedaremissing When true, unlinked plans are considered as missing.
 184       * @return array( array(
 185       *                   'template' => \core_competency\template,
 186       *                   'userids' => array
 187       *              ))
 188       */
 189      public static function get_all_missing_plans($lastruntime = 0, $unlinkedaremissing = false) {
 190          global $DB;
 191  
 192          $planwhereclause = " WHERE (p.id is NULL
 193                                 AND (cm.timeadded >= :lastruntime1
 194                                  OR tc.timecreated >= :lastruntime3
 195                                  OR t.timemodified >= :lastruntime4))";
 196  
 197          if ($unlinkedaremissing) {
 198              $planwhereclause .= " OR (p.origtemplateid IS NOT NULL AND cm.timeadded < :lastruntime2)";
 199          }
 200  
 201          $sql = "SELECT " . $DB->sql_concat('cm.userid', 'tc.templateid') . " as uniqueid, cm.userid, t.*
 202                    FROM {cohort_members} cm
 203                    JOIN {" . self::TABLE . "} tc ON cm.cohortid = tc.cohortid
 204                    JOIN {" . template::TABLE . "} t
 205                      ON (tc.templateid = t.id AND t.visible = 1)
 206                     AND (t.duedate = 0 OR t.duedate > :time1)
 207               LEFT JOIN {" . plan::TABLE . "} p ON (cm.userid = p.userid AND (t.id = p.templateid OR t.id = p.origtemplateid))
 208                    $planwhereclause
 209                ORDER BY t.id";
 210  
 211          $params = array('time1' => time(), 'time2' => time(),
 212                          'lastruntime1' => $lastruntime, 'lastruntime2' => $lastruntime,
 213                          'lastruntime3' => $lastruntime, 'lastruntime4' => $lastruntime);
 214          $results = $DB->get_records_sql($sql, $params);
 215  
 216          $missingplans = array();
 217          foreach ($results as $usertemplate) {
 218              $userid = $usertemplate->userid;
 219  
 220              // Check if template already exist in the array.
 221              if (isset($missingplans[$usertemplate->id])) {
 222                  $missingplans[$usertemplate->id]['userids'][] = $userid;
 223              } else {
 224                  unset($usertemplate->userid);
 225                  unset($usertemplate->uniqueid);
 226                  $template = new template(0, $usertemplate);
 227                  $missingplans[$template->get('id')]['template'] = $template;
 228                  $missingplans[$template->get('id')]['userids'][] = $userid;
 229              }
 230          }
 231          return array_values($missingplans);
 232      }
 233  
 234  }