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   * Guesses course start and end dates based on activity logs.
  19   *
  20   * @package    tool_analytics
  21   * @copyright  2016 David Monllao {@link http://www.davidmonllao.com}
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  define('CLI_SCRIPT', true);
  26  
  27  require_once(__DIR__ . '/../../../../config.php');
  28  require_once($CFG->libdir.'/clilib.php');
  29  
  30  require_once($CFG->dirroot . '/course/lib.php');
  31  require_once($CFG->dirroot . '/course/format/weeks/lib.php');
  32  
  33  $help = "Guesses course start and end dates based on activity logs.
  34  
  35  IMPORTANT: Don't use this script if you keep previous academic years users enrolled in courses. Guesses would not be accurate.
  36  
  37  Options:
  38  --guessstart           Guess the course start date (default to true)
  39  --guessend             Guess the course end date (default to true)
  40  --guessall             Guess all start and end dates, even if they are already set (default to false)
  41  --update               Update the db or just notify the guess (default to false)
  42  --filter               Analyser dependant. e.g. A courseid would evaluate the model using a single course (Optional)
  43  -h, --help             Print out this help
  44  
  45  Example:
  46  \$ php admin/tool/analytics/cli/guess_course_start_and_end_dates.php --update=1 --filter=123,321
  47  ";
  48  
  49  // Now get cli options.
  50  list($options, $unrecognized) = cli_get_params(
  51      array(
  52          'help'        => false,
  53          'guessstart'  => true,
  54          'guessend'    => true,
  55          'guessall'    => false,
  56          'update'      => false,
  57          'filter'      => false
  58      ),
  59      array(
  60          'h' => 'help',
  61      )
  62  );
  63  
  64  if ($options['help']) {
  65      echo $help;
  66      exit(0);
  67  }
  68  
  69  if ($options['guessstart'] === false && $options['guessend'] === false && $options['guessall'] === false) {
  70      echo $help;
  71      exit(0);
  72  }
  73  
  74  // Reformat them as an array.
  75  if ($options['filter'] !== false) {
  76      $options['filter'] = explode(',', clean_param($options['filter'], PARAM_SEQUENCE));
  77  }
  78  
  79  // We need admin permissions.
  80  \core\session\manager::set_user(get_admin());
  81  
  82  $conditions = array('id != 1');
  83  if (!$options['guessall']) {
  84      if ($options['guessstart']) {
  85          $conditions[] = '(startdate is null or startdate = 0)';
  86      }
  87      if ($options['guessend']) {
  88          $conditions[] = '(enddate is null or enddate = 0)';
  89      }
  90  }
  91  
  92  $coursessql = '';
  93  $params = null;
  94  if ($options['filter']) {
  95      list($coursessql, $params) = $DB->get_in_or_equal($options['filter'], SQL_PARAMS_NAMED);
  96      $conditions[] = 'id ' . $coursessql;
  97  }
  98  
  99  $courses = $DB->get_recordset_select('course', implode(' AND ', $conditions), $params, 'sortorder ASC');
 100  foreach ($courses as $course) {
 101      tool_analytics_calculate_course_dates($course, $options);
 102  }
 103  $courses->close();
 104  
 105  
 106  /**
 107   * tool_analytics_calculate_course_dates
 108   *
 109   * @param stdClass $course
 110   * @param array $options CLI options
 111   * @return void
 112   */
 113  function tool_analytics_calculate_course_dates($course, $options) {
 114      global $DB, $OUTPUT;
 115  
 116      $courseman = new \core_analytics\course($course);
 117  
 118      $notification = $course->shortname . ' (id = ' . $course->id . '): ';
 119  
 120      $originalenddate = null;
 121      $guessedstartdate = null;
 122      $guessedenddate = null;
 123      $samestartdate = null;
 124      $lowerenddate = null;
 125  
 126      if ($options['guessstart'] || $options['guessall']) {
 127  
 128          $originalstartdate = $course->startdate;
 129  
 130          $guessedstartdate = $courseman->guess_start();
 131          $samestartdate = ($guessedstartdate == $originalstartdate);
 132          $lowerenddate = ($course->enddate && ($course->enddate < $guessedstartdate));
 133  
 134          if ($samestartdate) {
 135              if (!$guessedstartdate) {
 136                  $notification .= PHP_EOL . '  ' . get_string('cantguessstartdate', 'tool_analytics');
 137              } else {
 138                  // No need to update.
 139                  $notification .= PHP_EOL . '  ' . get_string('samestartdate', 'tool_analytics') . ': ' . userdate($guessedstartdate);
 140              }
 141          } else if (!$guessedstartdate) {
 142              $notification .= PHP_EOL . '  ' . get_string('cantguessstartdate', 'tool_analytics');
 143          } else if ($lowerenddate) {
 144              $notification .= PHP_EOL . '  ' . get_string('cantguessstartdate', 'tool_analytics') . ': ' .
 145                  get_string('enddatebeforestartdate', 'error') . ' - ' . userdate($guessedstartdate);
 146          } else {
 147              // Update it to something we guess.
 148  
 149              // We set it to $course even if we don't update because may be needed to guess the end one.
 150              $course->startdate = $guessedstartdate;
 151              $notification .= PHP_EOL . '  ' . get_string('startdate') . ': ' . userdate($guessedstartdate);
 152  
 153              // Two different course updates because week's end date may be recalculated after setting the start date.
 154              if ($options['update']) {
 155                  update_course($course);
 156  
 157                  // Refresh course data as end date may have been updated.
 158                  $course = $DB->get_record('course', array('id' => $course->id));
 159                  $courseman = new \core_analytics\course($course);
 160              }
 161          }
 162      }
 163  
 164      if ($options['guessend'] || $options['guessall']) {
 165  
 166          if (!empty($lowerenddate) && !empty($guessedstartdate)) {
 167              $course->startdate = $guessedstartdate;
 168          }
 169  
 170          $originalenddate = $course->enddate;
 171  
 172          $format = course_get_format($course);
 173          $formatoptions = $format->get_format_options();
 174  
 175          // Change this for a course formats API level call in MDL-60702.
 176          if ((get_class($format) == 'format_weeks' || is_subclass_of($format, 'format_weeks')) &&
 177                  method_exists($format, 'update_end_date') && $formatoptions['automaticenddate']) {
 178              // Special treatment for weeks-based formats with automatic end date.
 179  
 180              if ($options['update']) {
 181                  $format::update_end_date($course->id);
 182                  $course->enddate = $DB->get_field('course', 'enddate', array('id' => $course->id));
 183                  $notification .= PHP_EOL . '  ' . get_string('weeksenddateautomaticallyset', 'tool_analytics') . ': ' .
 184                      userdate($course->enddate);
 185              } else {
 186                  // We can't provide more info without actually updating it in db.
 187                  $notification .= PHP_EOL . '  ' . get_string('weeksenddatedefault', 'tool_analytics');
 188              }
 189          } else {
 190              $guessedenddate = $courseman->guess_end();
 191  
 192              if ($guessedenddate == $originalenddate) {
 193                  if (!$guessedenddate) {
 194                      $notification .= PHP_EOL . '  ' . get_string('cantguessenddate', 'tool_analytics');
 195                  } else {
 196                      // No need to update.
 197                      $notification .= PHP_EOL . '  ' . get_string('sameenddate', 'tool_analytics') . ': ' . userdate($guessedenddate);
 198                  }
 199              } else if (!$guessedenddate) {
 200                  $notification .= PHP_EOL . '  ' . get_string('cantguessenddate', 'tool_analytics');
 201              } else {
 202                  // Update it to something we guess.
 203  
 204                  $course->enddate = $guessedenddate;
 205  
 206                  $updateit = false;
 207                  if ($course->enddate < $course->startdate) {
 208                      $notification .= PHP_EOL . '  ' . get_string('errorendbeforestart', 'course', userdate($course->enddate));
 209                  } else if ($course->startdate + (YEARSECS + (WEEKSECS * 4)) > $course->enddate) {
 210                      $notification .= PHP_EOL . '  ' . get_string('coursetoolong', 'course');
 211                  } else {
 212                      $notification .= PHP_EOL . '  ' . get_string('enddate') . ': ' . userdate($course->enddate);
 213                      $updateit = true;
 214                  }
 215  
 216                  if ($options['update'] && $updateit) {
 217                      update_course($course);
 218                  }
 219              }
 220          }
 221  
 222      }
 223  
 224      mtrace($notification);
 225  }
 226  
 227  mtrace(get_string('success'));
 228  
 229  exit(0);