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