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.
  •    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);