[ Index ]

PHP Cross Reference of Unnamed Project

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


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1