PDF rausgenommen

This commit is contained in:
aschwarz
2023-01-23 11:03:31 +01:00
parent 82d562a322
commit a6523903eb
28078 changed files with 4247552 additions and 2 deletions

View File

@ -0,0 +1,56 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Scheduler\Schedule;
use Exception;
/**
* Daily class is used to schedule tasks every day.
*
* @see \Piwik\Scheduler\Task
*/
class Daily extends Schedule
{
/**
* @see ScheduledTime::getRescheduledTime
* @return int
*
*/
public function getRescheduledTime()
{
$currentTime = $this->getTime();
// Add one day
$rescheduledTime = mktime(date('H', $currentTime),
date('i', $currentTime),
date('s', $currentTime),
date('n', $currentTime),
date('j', $currentTime) + 1,
date('Y', $currentTime)
);
// Adjusts the scheduled hour
$rescheduledTime = $this->adjustHour($rescheduledTime);
$rescheduledTime = $this->adjustTimezone($rescheduledTime);
return $rescheduledTime;
}
/**
* @see ScheduledTime::setDay
* @param int $_day
* @throws \Exception
* @ignore
*/
public function setDay($_day)
{
throw new Exception("Method not supported");
}
}

View File

@ -0,0 +1,61 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Scheduler\Schedule;
use Exception;
/**
* Hourly class is used to schedule tasks every hour.
*
* @see \Piwik\Scheduler\Task
*/
class Hourly extends Schedule
{
/**
* @see ScheduledTime::getRescheduledTime
* @return int
*/
public function getRescheduledTime()
{
$currentTime = $this->getTime();
// Adds one hour and reset the number of minutes
$rescheduledTime = mktime(date('H', $currentTime) + 1,
0,
date('s', $currentTime),
date('n', $currentTime),
date('j', $currentTime),
date('Y', $currentTime)
);
return $rescheduledTime;
}
/**
* @see ScheduledTime::setHour
* @param int $_hour
* @throws \Exception
* @return int
*/
public function setHour($_hour)
{
throw new Exception("Method not supported");
}
/**
* @see ScheduledTime::setDay
* @param int $_day
* @throws \Exception
* @return int
*/
public function setDay($_day)
{
throw new Exception("Method not supported");
}
}

View File

@ -0,0 +1,144 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Scheduler\Schedule;
use Exception;
/**
* Monthly class is used to schedule tasks every month.
*
* @see \Piwik\Scheduler\Task
*/
class Monthly extends Schedule
{
/**
* List of available week number strings used in setDayOfWeekFromString.
*/
private static $weekNumberStringToInt = array('first' => 0, 'second' => 1, 'third' => 2, 'fourth' => 3);
/**
* Day of the week for scheduled time.
*
* @var int
*/
private $dayOfWeek = null;
/**
* Week number for scheduled time.
*
* @var int
*/
private $week = null;
public function setDayOfWeekFromString($day)
{
@list($weekNumberString, $dayNumberString) = explode(' ', $day);
// get day number
$day = Weekly::getDayIntFromString($dayNumberString) % 7;
// get week number
$weekNumberString = strtolower($weekNumberString);
if (isset(self::$weekNumberStringToInt[$weekNumberString])) {
$week = self::$weekNumberStringToInt[$weekNumberString];
} else {
throw new Exception("Invalid week describer in Schedule\\Monthly::setDayOfWeekFromString: '$weekNumberString'. "
. "Supported values are 'first', 'second', 'third', 'fourth'.");
}
$this->setDayOfWeek($day, $week);
}
/**
* @return int
*/
public function getRescheduledTime()
{
$currentTime = $this->getTime();
// Adds one month
$rescheduledTime = mktime(date('H', $currentTime),
date('i', $currentTime),
date('s', $currentTime),
date('n', $currentTime) + 1,
1,
date('Y', $currentTime)
);
$nextMonthLength = date('t', $rescheduledTime);
// Sets scheduled day
$scheduledDay = date('j', $currentTime);
if ($this->day !== null) {
$scheduledDay = $this->day;
}
if ($this->dayOfWeek !== null
&& $this->week !== null
) {
$newTime = $rescheduledTime + $this->week * 7 * 86400;
while (date("w", $newTime) != $this->dayOfWeek % 7) {
// modulus for sanity check
$newTime += 86400;
}
$scheduledDay = ($newTime - $rescheduledTime) / 86400 + 1;
}
// Caps scheduled day
if ($scheduledDay > $nextMonthLength) {
$scheduledDay = $nextMonthLength;
}
// Adjusts the scheduled day
$rescheduledTime += ($scheduledDay - 1) * 86400;
// Adjusts the scheduled hour
$rescheduledTime = $this->adjustHour($rescheduledTime);
$rescheduledTime = $this->adjustTimezone($rescheduledTime);
return $rescheduledTime;
}
/**
* @param int $_day the day to set, has to be >= 1 and < 32
* @throws Exception if parameter _day is invalid
*/
public function setDay($_day)
{
if (!($_day >= 1 && $_day < 32)) {
throw new Exception("Invalid day parameter, must be >=1 and < 32");
}
$this->day = $_day;
}
/**
* Makes this scheduled time execute on a particular day of the week on each month.
*
* @param int $_day the day of the week to use, between 0-6 (inclusive). 0 -> Sunday
* @param int $_week the week to use, between 0-3 (inclusive)
* @throws Exception if either parameter is invalid
*/
public function setDayOfWeek($_day, $_week)
{
if (!($_day >= 0 && $_day < 7)) {
throw new Exception("Invalid day of week parameter, must be >= 0 & < 7");
}
if (!($_week >= 0 && $_week < 4)) {
throw new Exception("Invalid week number, must be >= 1 & < 4");
}
$this->dayOfWeek = $_day;
$this->week = $_week;
}
}

View File

@ -0,0 +1,224 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://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
{
const PERIOD_NEVER = 'never';
const PERIOD_DAY = 'day';
const PERIOD_WEEK = 'week';
const PERIOD_MONTH = 'month';
const PERIOD_HOUR = 'hour';
const PERIOD_YEAR = 'year';
const PERIOD_RANGE = 'range';
/**
* @link http://php.net/manual/en/function.date.php, format string : 'G'
* Defaults to midnight
* @var integer
*/
protected $hour = 0;
/**
* For weekly scheduling : http://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
* @throws \Exception
* @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($arbitraryDateInUTC, $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($periodDay);
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'.");
}
}
}

View File

@ -0,0 +1,33 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Scheduler\Schedule;
class SpecificTime extends Schedule
{
/**
* @var int
*/
private $scheduledTime;
public function __construct($scheduledTime)
{
$this->scheduledTime = $scheduledTime;
}
public function getRescheduledTime()
{
return $this->scheduledTime;
}
public function setDay($_day)
{
throw new \Exception('not supported');
}
}

View File

@ -0,0 +1,82 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Scheduler\Schedule;
use Exception;
/**
* Weekly class is used to schedule tasks every week.
*
* @see \Piwik\Scheduler\Task
*/
class Weekly extends Schedule
{
/**
* @see ScheduledTime::getRescheduledTime
* @return int
*/
public function getRescheduledTime()
{
$currentTime = $this->getTime();
$daysFromNow = 7;
// Adjusts the scheduled day
if ($this->day !== null) {
$daysFromNow = ($this->day - date('N', $currentTime) + 7) % 7;
if ($daysFromNow == 0) {
$daysFromNow = 7;
}
}
// Adds correct number of days
$rescheduledTime = mktime(date('H', $currentTime),
date('i', $currentTime),
date('s', $currentTime),
date('n', $currentTime),
date('j', $currentTime) + $daysFromNow,
date('Y', $currentTime)
);
// Adjusts the scheduled hour
$rescheduledTime = $this->adjustHour($rescheduledTime);
$rescheduledTime = $this->adjustTimezone($rescheduledTime);
return $rescheduledTime;
}
/**
* @param int $day the day to set, has to be >= 1 and < 8
* @throws Exception if parameter _day is invalid
*/
public function setDay($day)
{
if (!is_int($day)) {
$day = self::getDayIntFromString($day);
}
if (!($day >= 1 && $day < 8)) {
throw new Exception("Invalid day parameter, must be >=1 and < 8");
}
$this->day = $day;
}
public static function getDayIntFromString($dayString)
{
$time = strtotime($dayString);
if ($time === false) {
throw new Exception("Invalid day string '$dayString'. Must be 'monday', 'tuesday', etc.");
}
return date("N", $time);
}
}

View File

@ -0,0 +1,288 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Scheduler;
use Exception;
use Piwik\Piwik;
use Piwik\Timer;
use Psr\Log\LoggerInterface;
/**
* Schedules task execution.
*
* A scheduled task is a callback that should be executed every so often (such as daily,
* weekly, monthly, etc.). They are registered by extending {@link \Piwik\Plugin\Tasks}.
*
* Tasks are executed when the `core:archive` command is executed.
*
* ### Examples
*
* **Scheduling a task**
*
* class Tasks extends \Piwik\Plugin\Tasks
* {
* public function schedule()
* {
* $this->hourly('myTask'); // myTask() will be executed once every hour
* }
* public function myTask()
* {
* // do something
* }
* }
*
* **Executing all pending tasks**
*
* $results = $scheduler->run();
* $task1Result = $results[0];
* $task1Name = $task1Result['task'];
* $task1Output = $task1Result['output'];
*
* echo "Executed task '$task1Name'. Task output:\n$task1Output";
*/
class Scheduler
{
/**
* Is the scheduler running any task.
* @var bool
*/
private $isRunningTask = false;
/**
* @var Timetable
*/
private $timetable;
/**
* @var TaskLoader
*/
private $loader;
/**
* @var LoggerInterface
*/
private $logger;
public function __construct(TaskLoader $loader, LoggerInterface $logger)
{
$this->timetable = new Timetable();
$this->loader = $loader;
$this->logger = $logger;
}
/**
* Executes tasks that are scheduled to run, then reschedules them.
*
* @return array An array describing the results of scheduled task execution. Each element
* in the array will have the following format:
*
* ```
* array(
* 'task' => 'task name',
* 'output' => '... task output ...'
* )
* ```
*/
public function run()
{
$tasks = $this->loader->loadTasks();
$this->logger->debug('{count} scheduled tasks loaded', array('count' => count($tasks)));
// remove from timetable tasks that are not active anymore
$this->timetable->removeInactiveTasks($tasks);
$this->logger->info("Starting Scheduled tasks... ");
// for every priority level, starting with the highest and concluding with the lowest
$executionResults = array();
for ($priority = Task::HIGHEST_PRIORITY; $priority <= Task::LOWEST_PRIORITY; ++$priority) {
$this->logger->debug("Executing tasks with priority {priority}:", array('priority' => $priority));
// loop through each task
foreach ($tasks as $task) {
// if the task does not have the current priority level, don't execute it yet
if ($task->getPriority() != $priority) {
continue;
}
$taskName = $task->getName();
$shouldExecuteTask = $this->timetable->shouldExecuteTask($taskName);
if ($this->timetable->taskShouldBeRescheduled($taskName)) {
$rescheduledDate = $this->timetable->rescheduleTask($task);
$this->logger->debug("Task {task} is scheduled to run again for {date}.", array('task' => $taskName, 'date' => $rescheduledDate));
}
/**
* Triggered before a task is executed.
*
* A plugin can listen to it and modify whether a specific task should be executed or not. This way
* you can force certain tasks to be executed more often or for example to be never executed.
*
* @param bool &$shouldExecuteTask Decides whether the task will be executed.
* @param Task $task The task that is about to be executed.
*/
Piwik::postEvent('ScheduledTasks.shouldExecuteTask', array(&$shouldExecuteTask, $task));
if ($shouldExecuteTask) {
$message = $this->executeTask($task);
$executionResults[] = array('task' => $taskName, 'output' => $message);
}
}
}
$this->logger->info("done");
return $executionResults;
}
/**
* Run a specific task now. Will ignore the schedule completely.
*
* @param string $taskName
* @return string Task output.
*/
public function runTaskNow($taskName)
{
$tasks = $this->loader->loadTasks();
foreach ($tasks as $task) {
if ($task->getName() === $taskName) {
return $this->executeTask($task);
}
}
throw new \InvalidArgumentException('Task ' . $taskName . ' not found');
}
/**
* Determines a task's scheduled time and persists it, overwriting the previous scheduled time.
*
* Call this method if your task's scheduled time has changed due to, for example, an option that
* was changed.
*
* @param Task $task Describes the scheduled task being rescheduled.
* @api
*/
public function rescheduleTask(Task $task)
{
$this->logger->debug('Rescheduling task {task}', array('task' => $task->getName()));
$this->timetable->rescheduleTask($task);
}
/**
* Determines a task's scheduled time and persists it, overwriting the previous scheduled time.
*
* Call this method if your task's scheduled time has changed due to, for example, an option that
* was changed.
*
* The task will be run the first time tomorrow.
*
* @param Task $task Describes the scheduled task being rescheduled.
* @api
*/
public function rescheduleTaskAndRunTomorrow(Task $task)
{
$this->logger->debug('Rescheduling task and setting first run for tomorrow {task}', array('task' => $task->getName()));
$this->timetable->rescheduleTaskAndRunTomorrow($task);
}
/**
* Returns true if the scheduler is currently running a task.
*
* @return bool
*/
public function isRunningTask()
{
return $this->isRunningTask;
}
/**
* Return the next scheduled time given the class and method names of a scheduled task.
*
* @param string $className The name of the class that contains the scheduled task method.
* @param string $methodName The name of the scheduled task method.
* @param string|null $methodParameter Optional method parameter.
* @return mixed int|bool The time in miliseconds when the scheduled task will be executed
* next or false if it is not scheduled to run.
*/
public function getScheduledTimeForMethod($className, $methodName, $methodParameter = null)
{
return $this->timetable->getScheduledTimeForMethod($className, $methodName, $methodParameter);
}
/**
* Returns the list of the task names.
*
* @return string[]
*/
public function getTaskList()
{
$tasks = $this->loader->loadTasks();
return array_map(function (Task $task) {
return $task->getName();
}, $tasks);
}
/**
* Executes the given task
*
* @param Task $task
* @return string
*/
private function executeTask($task)
{
$this->logger->info("Scheduler: executing task {taskName}...", array(
'taskName' => $task->getName(),
));
$this->isRunningTask = true;
$timer = new Timer();
/**
* Triggered directly before a scheduled task is executed
*
* @param Task $task The task that is about to be executed
*/
Piwik::postEvent('ScheduledTasks.execute', array(&$task));
try {
$callable = array($task->getObjectInstance(), $task->getMethodName());
call_user_func($callable, $task->getMethodParameter());
$message = $timer->__toString();
} catch (Exception $e) {
$message = 'ERROR: ' . $e->getMessage();
}
$this->isRunningTask = false;
/**
* Triggered after a scheduled task is successfully executed.
*
* You can use the event to execute for example another task whenever a specific task is executed or to clean up
* certain resources.
*
* @param Task $task The task that was just executed
*/
Piwik::postEvent('ScheduledTasks.execute.end', array(&$task));
$this->logger->info("Scheduler: finished. {timeElapsed}", array(
'timeElapsed' => $timer,
));
return $message;
}
}

View File

@ -0,0 +1,200 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Scheduler;
use Exception;
use Piwik\Scheduler\Schedule\Schedule;
/**
* Describes a task that should be executed on a given time.
*
* See the {@link TaskScheduler} docs to learn more about scheduled tasks.
*
* @api
*/
class Task
{
const LOWEST_PRIORITY = 12;
const LOW_PRIORITY = 9;
const NORMAL_PRIORITY = 6;
const HIGH_PRIORITY = 3;
const HIGHEST_PRIORITY = 0;
/**
* Object instance on which the method will be executed by the task scheduler
* @var string
*/
private $objectInstance;
/**
* Class name where the specified method is located
* @var string
*/
private $className;
/**
* Class method to run when task is scheduled
* @var string
*/
private $methodName;
/**
* Parameter to pass to the executed method
* @var string
*/
private $methodParameter;
/**
* The scheduled time policy
* @var Schedule
*/
private $scheduledTime;
/**
* The priority of a task. Affects the order in which this task will be run.
* @var int
*/
private $priority;
/**
* @param mixed $objectInstance The object or class that contains the method to execute regularly.
* Usually this will be a {@link Plugin} instance.
* @param string $methodName The name of the method that will be regularly executed.
* @param mixed|null $methodParameter An optional parameter to pass to the method when executed.
* Must be convertible to string.
* @param Schedule|null $scheduledTime A {@link Schedule} instance that describes when the method
* should be executed and how long before the next execution.
* @param int $priority The priority of the task. Tasks with a higher priority will be executed first.
* Tasks with low priority will be executed last.
* @throws Exception
*/
public function __construct($objectInstance, $methodName, $methodParameter, $scheduledTime,
$priority = self::NORMAL_PRIORITY)
{
$this->className = $this->getClassNameFromInstance($objectInstance);
if ($priority < self::HIGHEST_PRIORITY || $priority > self::LOWEST_PRIORITY) {
throw new Exception("Invalid priority for ScheduledTask '$this->className.$methodName': $priority");
}
$this->objectInstance = $objectInstance;
$this->methodName = $methodName;
$this->scheduledTime = $scheduledTime;
$this->methodParameter = $methodParameter;
$this->priority = $priority;
}
protected function getClassNameFromInstance($_objectInstance)
{
if (is_string($_objectInstance)) {
return $_objectInstance;
}
$namespaced = get_class($_objectInstance);
return $namespaced;
}
/**
* Returns the object instance that contains the method to execute. Returns a class
* name if the method is static.
*
* @return mixed
*/
public function getObjectInstance()
{
return $this->objectInstance;
}
/**
* Returns the name of the class that contains the method to execute.
*
* @return string
*/
public function getClassName()
{
return $this->className;
}
/**
* Returns the name of the method that will be executed.
*
* @return string
*/
public function getMethodName()
{
return $this->methodName;
}
/**
* Returns the value that will be passed to the method when executed, or `null` if
* no value will be supplied.
*
* @return string|null
*/
public function getMethodParameter()
{
return $this->methodParameter;
}
/**
* Returns a {@link Schedule} instance that describes when the method should be executed
* and how long before the next execution.
*
* @return \Piwik\Scheduler\Schedule\Schedule
*/
public function getScheduledTime()
{
return $this->scheduledTime;
}
/**
* Returns the time in milliseconds when this task will be executed next.
*
* @return int
*/
public function getRescheduledTime()
{
return $this->getScheduledTime()->getRescheduledTime();
}
/**
* Returns the task priority. The priority will be an integer whose value is
* between {@link HIGH_PRIORITY} and {@link LOW_PRIORITY}.
*
* @return int
*/
public function getPriority()
{
return $this->priority;
}
/**
* Returns a unique name for this scheduled task. The name is stored in the DB and is used
* to store a task's previous execution time. The name is created using:
*
* - the name of the class that contains the method to execute,
* - the name of the method to regularly execute,
* - and the value that is passed to the executed task.
*
* @return string
*/
public function getName()
{
return self::getTaskName($this->getClassName(), $this->getMethodName(), $this->getMethodParameter());
}
/**
* @ignore
*/
public static function getTaskName($className, $methodName, $methodParameter = null)
{
return $className . '.' . $methodName . ($methodParameter == null ? '' : '_' . $methodParameter);
}
}

View File

@ -0,0 +1,41 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Scheduler;
use Piwik\Container\StaticContainer;
use Piwik\Plugin\Manager as PluginManager;
use Piwik\Plugin\Tasks;
/**
* Loads scheduled tasks.
*/
class TaskLoader
{
/**
* @return Task[]
*/
public function loadTasks()
{
$tasks = array();
/** @var Tasks[] $pluginTasks */
$pluginTasks = PluginManager::getInstance()->findComponents('Tasks', 'Piwik\Plugin\Tasks');
foreach ($pluginTasks as $pluginTask) {
$pluginTask = StaticContainer::get($pluginTask);
$pluginTask->schedule();
foreach ($pluginTask->getScheduledTasks() as $task) {
$tasks[] = $task;
}
}
return $tasks;
}
}

View File

@ -0,0 +1,146 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Scheduler;
use Piwik\Common;
use Piwik\Option;
use Piwik\Date;
/**
* This data structure holds the scheduled times for each active scheduled task.
*/
class Timetable
{
const TIMETABLE_OPTION_STRING = "TaskScheduler.timetable";
private $timetable;
public function __construct()
{
$optionData = Option::get(self::TIMETABLE_OPTION_STRING);
$unserializedTimetable = Common::safe_unserialize($optionData);
$this->timetable = $unserializedTimetable === false ? array() : $unserializedTimetable;
}
public function getTimetable()
{
return $this->timetable;
}
public function setTimetable($timetable)
{
$this->timetable = $timetable;
}
/**
* @param Task[] $activeTasks
*/
public function removeInactiveTasks($activeTasks)
{
$activeTaskNames = array();
foreach ($activeTasks as $task) {
$activeTaskNames[] = $task->getName();
}
foreach (array_keys($this->timetable) as $taskName) {
if (!in_array($taskName, $activeTaskNames)) {
unset($this->timetable[$taskName]);
}
}
$this->save();
}
public function getScheduledTaskNames()
{
return array_keys($this->timetable);
}
public function getScheduledTaskTime($taskName)
{
return isset($this->timetable[$taskName]) ? Date::factory($this->timetable[$taskName]) : false;
}
/**
* Checks if the task should be executed
*
* Task has to be executed if :
* - the task has already been scheduled once and the current system time is greater than the scheduled time.
* - execution is forced, see $forceTaskExecution
*
* @param string $taskName
*
* @return boolean
*/
public function shouldExecuteTask($taskName)
{
$forceTaskExecution = (defined('DEBUG_FORCE_SCHEDULED_TASKS') && DEBUG_FORCE_SCHEDULED_TASKS);
if ($forceTaskExecution) {
return true;
}
return $this->taskHasBeenScheduledOnce($taskName) && time() >= $this->timetable[$taskName];
}
/**
* Checks if a task should be rescheduled
*
* Task has to be rescheduled if :
* - the task has to be executed
* - the task has never been scheduled before
*
* @param string $taskName
*
* @return boolean
*/
public function taskShouldBeRescheduled($taskName)
{
return !$this->taskHasBeenScheduledOnce($taskName) || $this->shouldExecuteTask($taskName);
}
public function rescheduleTask(Task $task)
{
$rescheduledTime = $task->getRescheduledTime();
// update the scheduled time
$this->timetable[$task->getName()] = $rescheduledTime;
$this->save();
return Date::factory($rescheduledTime);
}
public function rescheduleTaskAndRunTomorrow(Task $task)
{
$tomorrow = Date::factory('tomorrow');
// update the scheduled time
$this->timetable[$task->getName()] = $tomorrow->getTimestamp();
$this->save();
return $tomorrow;
}
public function save()
{
Option::set(self::TIMETABLE_OPTION_STRING, serialize($this->timetable));
}
public function getScheduledTimeForMethod($className, $methodName, $methodParameter = null)
{
$taskName = Task::getTaskName($className, $methodName, $methodParameter);
return $this->taskHasBeenScheduledOnce($taskName) ? $this->timetable[$taskName] : false;
}
public function taskHasBeenScheduledOnce($taskName)
{
return isset($this->timetable[$taskName]);
}
}