File size: 7,585 Bytes
f8ce8bb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | <?php
/**
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Scheduler\Schedule;
use Exception;
use Piwik\Date;
/**
* Describes the interval on which a scheduled task is executed. Use the {@link factory()} method
* to create Schedule instances.
*
* @see \Piwik\Scheduler\Task
*/
abstract class Schedule
{
public const PERIOD_NEVER = 'never';
public const PERIOD_DAY = 'day';
public const PERIOD_WEEK = 'week';
public const PERIOD_MONTH = 'month';
public const PERIOD_HOUR = 'hour';
public const PERIOD_YEAR = 'year';
public const PERIOD_RANGE = 'range';
/**
* @link https://php.net/manual/en/function.date.php, format string : 'G'
* Defaults to midnight
* @var integer
*/
protected $hour = 0;
/**
* For weekly scheduling : https://php.net/manual/en/function.date.php, format string : 'N', defaults to Monday
* For monthly scheduling : day of the month (1 to 31) (note: will be capped at the latest day available the
* month), defaults to first day of the month
* @var integer
*/
protected $day = 1;
protected $timezone = null;
/**
* @param $period
* @return Daily|Monthly|Weekly|Hourly
* @ignore
*/
public static function getScheduledTimeForPeriod($period)
{
switch ($period) {
case self::PERIOD_MONTH:
return new Monthly();
case self::PERIOD_WEEK:
return new Weekly();
case self::PERIOD_DAY:
return new Daily();
case self::PERIOD_HOUR:
return new Hourly();
default:
throw new Exception('period ' . $period . 'is undefined.');
}
}
/**
* Returns the system time used by subclasses to compute schedulings.
* This method has been introduced so unit tests can override the current system time.
* @return int
*/
protected function getTime()
{
return time();
}
/**
* Computes the next scheduled time based on the system time at which the method has been called and
* the underlying scheduling interval.
*
* @abstract
* @return integer Returns the rescheduled time measured in the number of seconds since the Unix Epoch
* @ignore
*/
abstract public function getRescheduledTime();
/**
* Sets the day of the period to execute the scheduled task. Not a valid operation for all period types.
*
* @abstract
* @param int $_day a number describing the day to set. Its meaning depends on the Schedule's period type.
* @throws Exception if method not supported by subclass or parameter _day is invalid
*/
abstract public function setDay($_day);
/**
* Sets the hour of the day on which the task should be executed.
*
* @param int $hour Must be `>= 0` and `< 24`.
* @throws Exception If the current scheduled period is **hourly** or if `$hour` is invalid.
* @api
*/
public function setHour($hour)
{
if (!($hour >= 0 && $hour < 24)) {
throw new Exception("Invalid hour parameter, must be >=0 and < 24");
}
$this->hour = $hour;
}
/**
* By setting a timezone you make sure the scheduled task will be run at the requested time in the
* given timezone. This is useful for instance in case you want to make sure a task runs at midnight in a website's
* timezone.
*
* @param string $timezone
*/
public function setTimezone($timezone)
{
$this->timezone = $timezone;
}
protected function adjustTimezone($rescheduledTime)
{
if (is_null($this->timezone)) {
return $rescheduledTime;
}
$arbitraryDateInUTC = Date::factory('2011-01-01');
$dateInTimezone = Date::factory('2011-01-01', $this->timezone);
$midnightInTimezone = date('H', $dateInTimezone->getTimestamp());
if ($arbitraryDateInUTC->isEarlier($dateInTimezone)) {
$hoursDifference = 0 - $midnightInTimezone;
} else {
$hoursDifference = 24 - $midnightInTimezone;
}
$hoursDifference = $hoursDifference % 24;
$rescheduledTime += (3600 * $hoursDifference);
if ($this->getTime() > $rescheduledTime) {
// make sure the rescheduled date is in the future
$rescheduledTime = (24 * 3600) + $rescheduledTime;
}
return $rescheduledTime;
}
/**
* Computes the delta in seconds needed to adjust the rescheduled time to the required hour.
*
* @param int $rescheduledTime The rescheduled time to be adjusted
* @return int adjusted rescheduled time
*/
protected function adjustHour($rescheduledTime)
{
if ($this->hour !== null) {
// Reset the number of minutes and set the scheduled hour to the one specified with setHour()
$rescheduledTime = mktime(
$this->hour,
0,
date('s', $rescheduledTime),
date('n', $rescheduledTime),
date('j', $rescheduledTime),
date('Y', $rescheduledTime)
);
}
return $rescheduledTime;
}
/**
* Returns a new Schedule instance using a string description of the scheduled period type
* and a string description of the day within the period to execute the task on.
*
* @param string $periodType The scheduled period type. Can be `'hourly'`, `'daily'`, `'weekly'`, or `'monthly'`.
* @param bool|false|int|string $periodDay A string describing the day within the scheduled period to execute
* the task on. Only valid for week and month periods.
*
* If `'weekly'` is supplied for `$periodType`, this should be a day
* of the week, for example, `'monday'` or `'tuesday'`.
*
* If `'monthly'` is supplied for `$periodType`, this can be a numeric
* day in the month or a day in one week of the month. For example,
* `12`, `23`, `'first sunday'` or `'fourth tuesday'`.
* @return Hourly|Daily|Weekly|Monthly
* @throws Exception
* @api
*/
public static function factory($periodType, $periodDay = false)
{
switch ($periodType) {
case 'hourly':
return new Hourly();
case 'daily':
return new Daily();
case 'weekly':
$result = new Weekly();
if ($periodDay !== false) {
$result->setDay($periodDay);
}
return $result;
case 'monthly':
$result = new Monthly();
if ($periodDay !== false) {
if (is_int($periodDay)) {
$result->setDay($periodDay);
} else {
$result->setDayOfWeekFromString($periodDay);
}
}
return $result;
default:
throw new Exception("Unsupported scheduled period type: '$periodType'. Supported values are"
. " 'hourly', 'daily', 'weekly' or 'monthly'.");
}
}
}
|