Teknik is a suite of services with attractive and functional interfaces. https://www.teknik.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ScheduledTime.php 7.4KB

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