[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/lib/classes/task/ -> scheduled_task.php (source)

   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   * Scheduled task abstract class.
  19   *
  20   * @package    core
  21   * @category   task
  22   * @copyright  2013 Damyon Wiese
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  namespace core\task;
  26  
  27  /**
  28   * Abstract class defining a scheduled task.
  29   * @copyright  2013 Damyon Wiese
  30   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  31   */
  32  abstract class scheduled_task extends task_base {
  33  
  34      /** Minimum minute value. */
  35      const MINUTEMIN = 0;
  36      /** Maximum minute value. */
  37      const MINUTEMAX = 59;
  38      /** Minimum hour value. */
  39      const HOURMIN = 0;
  40      /** Maximum hour value. */
  41      const HOURMAX = 23;
  42  
  43      /** @var string $hour - Pattern to work out the valid hours */
  44      private $hour = '*';
  45  
  46      /** @var string $minute - Pattern to work out the valid minutes */
  47      private $minute = '*';
  48  
  49      /** @var string $day - Pattern to work out the valid days */
  50      private $day = '*';
  51  
  52      /** @var string $month - Pattern to work out the valid months */
  53      private $month = '*';
  54  
  55      /** @var string $dayofweek - Pattern to work out the valid dayofweek */
  56      private $dayofweek = '*';
  57  
  58      /** @var int $lastruntime - When this task was last run */
  59      private $lastruntime = 0;
  60  
  61      /** @var boolean $customised - Has this task been changed from it's default schedule? */
  62      private $customised = false;
  63  
  64      /** @var int $disabled - Is this task disabled in cron? */
  65      private $disabled = false;
  66  
  67      /**
  68       * Get the last run time for this scheduled task.
  69       * @return int
  70       */
  71      public function get_last_run_time() {
  72          return $this->lastruntime;
  73      }
  74  
  75      /**
  76       * Set the last run time for this scheduled task.
  77       * @param int $lastruntime
  78       */
  79      public function set_last_run_time($lastruntime) {
  80          $this->lastruntime = $lastruntime;
  81      }
  82  
  83      /**
  84       * Has this task been changed from it's default config?
  85       * @return bool
  86       */
  87      public function is_customised() {
  88          return $this->customised;
  89      }
  90  
  91      /**
  92       * Has this task been changed from it's default config?
  93       * @param bool
  94       */
  95      public function set_customised($customised) {
  96          $this->customised = $customised;
  97      }
  98  
  99      /**
 100       * Setter for $minute. Accepts a special 'R' value
 101       * which will be translated to a random minute.
 102       * @param string $minute
 103       */
 104      public function set_minute($minute) {
 105          if ($minute === 'R') {
 106              $minute = mt_rand(self::HOURMIN, self::HOURMAX);
 107          }
 108          $this->minute = $minute;
 109      }
 110  
 111      /**
 112       * Getter for $minute.
 113       * @return string
 114       */
 115      public function get_minute() {
 116          return $this->minute;
 117      }
 118  
 119      /**
 120       * Setter for $hour. Accepts a special 'R' value
 121       * which will be translated to a random hour.
 122       * @param string $hour
 123       */
 124      public function set_hour($hour) {
 125          if ($hour === 'R') {
 126              $hour = mt_rand(self::HOURMIN, self::HOURMAX);
 127          }
 128          $this->hour = $hour;
 129      }
 130  
 131      /**
 132       * Getter for $hour.
 133       * @return string
 134       */
 135      public function get_hour() {
 136          return $this->hour;
 137      }
 138  
 139      /**
 140       * Setter for $month.
 141       * @param string $month
 142       */
 143      public function set_month($month) {
 144          $this->month = $month;
 145      }
 146  
 147      /**
 148       * Getter for $month.
 149       * @return string
 150       */
 151      public function get_month() {
 152          return $this->month;
 153      }
 154  
 155      /**
 156       * Setter for $day.
 157       * @param string $day
 158       */
 159      public function set_day($day) {
 160          $this->day = $day;
 161      }
 162  
 163      /**
 164       * Getter for $day.
 165       * @return string
 166       */
 167      public function get_day() {
 168          return $this->day;
 169      }
 170  
 171      /**
 172       * Setter for $dayofweek.
 173       * @param string $dayofweek
 174       */
 175      public function set_day_of_week($dayofweek) {
 176          $this->dayofweek = $dayofweek;
 177      }
 178  
 179      /**
 180       * Getter for $dayofweek.
 181       * @return string
 182       */
 183      public function get_day_of_week() {
 184          return $this->dayofweek;
 185      }
 186  
 187      /**
 188       * Setter for $disabled.
 189       * @param bool $disabled
 190       */
 191      public function set_disabled($disabled) {
 192          $this->disabled = (bool)$disabled;
 193      }
 194  
 195      /**
 196       * Getter for $disabled.
 197       * @return bool
 198       */
 199      public function get_disabled() {
 200          return $this->disabled;
 201      }
 202  
 203      /**
 204       * Override this function if you want this scheduled task to run, even if the component is disabled.
 205       *
 206       * @return bool
 207       */
 208      public function get_run_if_component_disabled() {
 209          return false;
 210      }
 211  
 212      /**
 213       * Take a cron field definition and return an array of valid numbers with the range min-max.
 214       *
 215       * @param string $field - The field definition.
 216       * @param int $min - The minimum allowable value.
 217       * @param int $max - The maximum allowable value.
 218       * @return array(int)
 219       */
 220      public function eval_cron_field($field, $min, $max) {
 221          // Cleanse the input.
 222          $field = trim($field);
 223  
 224          // Format for a field is:
 225          // <fieldlist> := <range>(/<step>)(,<fieldlist>)
 226          // <step>  := int
 227          // <range> := <any>|<int>|<min-max>
 228          // <any>   := *
 229          // <min-max> := int-int
 230          // End of format BNF.
 231  
 232          // This function is complicated but is covered by unit tests.
 233          $range = array();
 234  
 235          $matches = array();
 236          preg_match_all('@[0-9]+|\*|,|/|-@', $field, $matches);
 237  
 238          $last = 0;
 239          $inrange = false;
 240          $instep = false;
 241  
 242          foreach ($matches[0] as $match) {
 243              if ($match == '*') {
 244                  array_push($range, range($min, $max));
 245              } else if ($match == '/') {
 246                  $instep = true;
 247              } else if ($match == '-') {
 248                  $inrange = true;
 249              } else if (is_numeric($match)) {
 250                  if ($instep) {
 251                      $i = 0;
 252                      for ($i = 0; $i < count($range[count($range) - 1]); $i++) {
 253                          if (($i) % $match != 0) {
 254                              $range[count($range) - 1][$i] = -1;
 255                          }
 256                      }
 257                      $inrange = false;
 258                  } else if ($inrange) {
 259                      if (count($range)) {
 260                          $range[count($range) - 1] = range($last, $match);
 261                      }
 262                      $inrange = false;
 263                  } else {
 264                      if ($match >= $min && $match <= $max) {
 265                          array_push($range, $match);
 266                      }
 267                      $last = $match;
 268                  }
 269              }
 270          }
 271  
 272          // Flatten the result.
 273          $result = array();
 274          foreach ($range as $r) {
 275              if (is_array($r)) {
 276                  foreach ($r as $rr) {
 277                      if ($rr >= $min && $rr <= $max) {
 278                          $result[$rr] = 1;
 279                      }
 280                  }
 281              } else if (is_numeric($r)) {
 282                  if ($r >= $min && $r <= $max) {
 283                      $result[$r] = 1;
 284                  }
 285              }
 286          }
 287          $result = array_keys($result);
 288          sort($result, SORT_NUMERIC);
 289          return $result;
 290      }
 291  
 292      /**
 293       * Assuming $list is an ordered list of items, this function returns the item
 294       * in the list that is greater than or equal to the current value (or 0). If
 295       * no value is greater than or equal, this will return the first valid item in the list.
 296       * If list is empty, this function will return 0.
 297       *
 298       * @param int $current The current value
 299       * @param int[] $list The list of valid items.
 300       * @return int $next.
 301       */
 302      private function next_in_list($current, $list) {
 303          foreach ($list as $l) {
 304              if ($l >= $current) {
 305                  return $l;
 306              }
 307          }
 308          if (count($list)) {
 309              return $list[0];
 310          }
 311  
 312          return 0;
 313      }
 314  
 315      /**
 316       * Calculate when this task should next be run based on the schedule.
 317       * @return int $nextruntime.
 318       */
 319      public function get_next_scheduled_time() {
 320          global $CFG;
 321  
 322          $validminutes = $this->eval_cron_field($this->minute, self::MINUTEMIN, self::MINUTEMAX);
 323          $validhours = $this->eval_cron_field($this->hour, self::HOURMIN, self::HOURMAX);
 324  
 325          // We need to change to the server timezone before using php date() functions.
 326          $origtz = date_default_timezone_get();
 327          if (!empty($CFG->timezone) && $CFG->timezone != 99) {
 328              date_default_timezone_set($CFG->timezone);
 329          }
 330  
 331          $daysinmonth = date("t");
 332          $validdays = $this->eval_cron_field($this->day, 1, $daysinmonth);
 333          $validdaysofweek = $this->eval_cron_field($this->dayofweek, 0, 7);
 334          $validmonths = $this->eval_cron_field($this->month, 1, 12);
 335          $nextvalidyear = date('Y');
 336  
 337          $currentminute = date("i") + 1;
 338          $currenthour = date("H");
 339          $currentday = date("j");
 340          $currentmonth = date("n");
 341          $currentdayofweek = date("w");
 342  
 343          $nextvalidminute = $this->next_in_list($currentminute, $validminutes);
 344          if ($nextvalidminute < $currentminute) {
 345              $currenthour += 1;
 346          }
 347          $nextvalidhour = $this->next_in_list($currenthour, $validhours);
 348          if ($nextvalidhour < $currenthour) {
 349              $currentdayofweek += 1;
 350              $currentday += 1;
 351          }
 352          $nextvaliddayofmonth = $this->next_in_list($currentday, $validdays);
 353          $nextvaliddayofweek = $this->next_in_list($currentdayofweek, $validdaysofweek);
 354          $daysincrementbymonth = $nextvaliddayofmonth - $currentday;
 355          if ($nextvaliddayofmonth < $currentday) {
 356              $daysincrementbymonth += $daysinmonth;
 357          }
 358  
 359          $daysincrementbyweek = $nextvaliddayofweek - $currentdayofweek;
 360          if ($nextvaliddayofweek < $currentdayofweek) {
 361              $daysincrementbyweek += 7;
 362          }
 363  
 364          // Special handling for dayofmonth vs dayofweek:
 365          // if either field is * - use the other field
 366          // otherwise - choose the soonest (see man 5 cron).
 367          if ($this->dayofweek == '*') {
 368              $daysincrement = $daysincrementbymonth;
 369          } else if ($this->day == '*') {
 370              $daysincrement = $daysincrementbyweek;
 371          } else {
 372              // Take the smaller increment of days by month or week.
 373              $daysincrement = $daysincrementbymonth;
 374              if ($daysincrementbyweek < $daysincrementbymonth) {
 375                  $daysincrement = $daysincrementbyweek;
 376              }
 377          }
 378  
 379          $nextvaliddayofmonth = $currentday + $daysincrement;
 380          if ($nextvaliddayofmonth > $daysinmonth) {
 381              $currentmonth += 1;
 382              $nextvaliddayofmonth -= $daysinmonth;
 383          }
 384  
 385          $nextvalidmonth = $this->next_in_list($currentmonth, $validmonths);
 386          if ($nextvalidmonth < $currentmonth) {
 387              $nextvalidyear += 1;
 388          }
 389  
 390          // Work out the next valid time.
 391          $nexttime = mktime($nextvalidhour,
 392                             $nextvalidminute,
 393                             0,
 394                             $nextvalidmonth,
 395                             $nextvaliddayofmonth,
 396                             $nextvalidyear);
 397  
 398          // We need to change the timezone back so other date functions in moodle do not get confused.
 399          if (!empty($CFG->timezone) && $CFG->timezone != 99) {
 400              date_default_timezone_set($origtz);
 401          }
 402  
 403          return $nexttime;
 404      }
 405  
 406      /**
 407       * Get a descriptive name for this task (shown to admins).
 408       *
 409       * @return string
 410       */
 411      public abstract function get_name();
 412  
 413  }


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1