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