PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/classes/cliTool/ScheduledTaskTool.inc.php

https://github.com/mbehiels/pkp-lib
PHP | 249 lines | 131 code | 42 blank | 76 comment | 36 complexity | 6d5f143660d95c461b224edd3ae2dda2 MD5 | raw file
  1. <?php
  2. /**
  3. * @file classes/cliTool/ScheduledTaskTool.inc.php
  4. *
  5. * Copyright (c) 2000-2011 John Willinsky
  6. * Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
  7. *
  8. * @class ScheduledTaskTool
  9. * @ingroup tools
  10. *
  11. * @brief CLI tool to execute a set of scheduled tasks.
  12. */
  13. /** Default XML tasks file to parse if none is specified */
  14. define('TASKS_REGISTRY_FILE', Config::getVar('general', 'registry_dir') . '/scheduledTasks.xml');
  15. import('lib.pkp.classes.scheduledTask.ScheduledTask');
  16. import('lib.pkp.classes.scheduledTask.ScheduledTaskDAO');
  17. class ScheduledTaskTool extends CommandLineTool {
  18. /** @var string the XML file listing the tasks to be executed */
  19. var $file;
  20. /** @var ScheduledTaskDAO the DAO object */
  21. var $taskDao;
  22. /**
  23. * Constructor.
  24. * @param $argv array command-line arguments
  25. * If specified, the first parameter should be the path to
  26. * a tasks XML descriptor file (other than the default)
  27. */
  28. function ScheduledTaskTool($argv = array()) {
  29. parent::CommandLineTool($argv);
  30. if (isset($this->argv[0])) {
  31. $this->file = $this->argv[0];
  32. } else {
  33. $this->file = TASKS_REGISTRY_FILE;
  34. }
  35. if (!file_exists($this->file) || !is_readable($this->file)) {
  36. printf("Tasks file \"%s\" does not exist or is not readable!\n", $this->file);
  37. exit(1);
  38. }
  39. $this->taskDao =& DAORegistry::getDAO('ScheduledTaskDAO');
  40. }
  41. /**
  42. * Print command usage information.
  43. */
  44. function usage() {
  45. echo "Script to run a set of scheduled tasks\n"
  46. . "Usage: {$this->scriptName} [tasks_file]\n";
  47. }
  48. /**
  49. * Parse and execute the scheduled tasks.
  50. */
  51. function execute() {
  52. $this->parseTasks($this->file);
  53. }
  54. /**
  55. * Parse and execute the scheduled tasks in the specified file.
  56. * @param $file string
  57. */
  58. function parseTasks($file) {
  59. $xmlParser = new XMLParser();
  60. $tree = $xmlParser->parse($file);
  61. if (!$tree) {
  62. $xmlParser->destroy();
  63. printf("Unable to parse file \"%s\"!\n", $file);
  64. exit(1);
  65. }
  66. foreach ($tree->getChildren() as $task) {
  67. $className = $task->getAttribute('class');
  68. $frequency = $task->getChildByName('frequency');
  69. if (isset($frequency)) {
  70. $canExecute = $this->checkFrequency($className, $frequency);
  71. } else {
  72. // Always execute if no frequency is specified
  73. $canExecute = true;
  74. }
  75. if ($canExecute) {
  76. $this->executeTask($className, $this->getTaskArgs($task));
  77. }
  78. }
  79. $xmlParser->destroy();
  80. }
  81. /**
  82. * Execute the specified task.
  83. * @param $className string the class name to execute
  84. * @param $args array the array of arguments to pass to the class constructors
  85. */
  86. function executeTask($className, $args) {
  87. // Load and execute the task
  88. if (!is_object($task =& instantiate($className, null, null, 'execute', $args))) {
  89. fatalError('Cannot instantiate task class.');
  90. }
  91. $task->execute();
  92. $this->taskDao->updateLastRunTime($className);
  93. }
  94. /**
  95. * Get the arguments for a task from the parsed XML.
  96. * @param XMLNode
  97. * @return array
  98. */
  99. function getTaskArgs($task) {
  100. $args = array();
  101. $index = 0;
  102. while(($arg = $task->getChildByName('arg', $index)) != null) {
  103. array_push($args, $arg->getValue());
  104. $index++;
  105. }
  106. return $args;
  107. }
  108. /**
  109. * Check if the specified task should be executed according to the specified
  110. * frequency and its last run time.
  111. * @param $className string
  112. * @param $frequency XMLNode
  113. * @return string
  114. */
  115. function checkFrequency($className, $frequency) {
  116. $isValid = true;
  117. $lastRunTime = $this->taskDao->getLastRunTime($className);
  118. // Check day of week
  119. $dayOfWeek = $frequency->getAttribute('dayofweek');
  120. if (isset($dayOfWeek)) {
  121. $isValid = $this->isInRange($dayOfWeek, (int)date('w'), $lastRunTime, 'day', strtotime('-1 week'));
  122. }
  123. if ($isValid) {
  124. // Check month
  125. $month = $frequency->getAttribute('month');
  126. if (isset($month)) {
  127. $isValid = $this->isInRange($month, (int)date('n'), $lastRunTime, 'month', strtotime('-1 year'));
  128. }
  129. }
  130. if ($isValid) {
  131. // Check day
  132. $day = $frequency->getAttribute('day');
  133. if (isset($day)) {
  134. $isValid = $this->isInRange($day, (int)date('j'), $lastRunTime, 'day', strtotime('-1 month'));
  135. }
  136. }
  137. if ($isValid) {
  138. // Check hour
  139. $hour = $frequency->getAttribute('hour');
  140. if (isset($hour)) {
  141. $isValid = $this->isInRange($hour, (int)date('G'), $lastRunTime, 'hour', strtotime('-1 day'));
  142. }
  143. }
  144. if ($isValid) {
  145. // Check minute
  146. $minute = $frequency->getAttribute('minute');
  147. if (isset($minute)) {
  148. $isValid = $this->isInRange($minute, (int)date('i'), $lastRunTime, 'min', strtotime('-1 hour'));
  149. }
  150. }
  151. return $isValid;
  152. }
  153. /**
  154. * Check if a value is within the specified range.
  155. * @param $rangeStr string the range (e.g., 0, 1-5, *, etc.)
  156. * @param $currentValue int value to check if its in the range
  157. * @param $lastTimestamp int the last time the task was executed
  158. * @param $timeCompareStr string value to use in strtotime("-X $timeCompareStr")
  159. * @param $cutoffTimestamp int value will be considered valid if older than this
  160. * @return boolean
  161. */
  162. function isInRange($rangeStr, $currentValue, $lastTimestamp, $timeCompareStr, $cutoffTimestamp) {
  163. $isValid = false;
  164. $rangeArray = explode(',', $rangeStr);
  165. if ($cutoffTimestamp > $lastTimestamp) {
  166. // Execute immediately if the cutoff time period has past since the task was last run
  167. $isValid = true;
  168. }
  169. for ($i = 0, $count = count($rangeArray); !$isValid && ($i < $count); $i++) {
  170. if ($rangeArray[$i] == '*') {
  171. // Is wildcard
  172. $isValid = true;
  173. } if (is_numeric($rangeArray[$i])) {
  174. // Is just a value
  175. $isValid = ($currentValue == (int)$rangeArray[$i]);
  176. } else if (preg_match('/^(\d*)\-(\d*)$/', $rangeArray[$i], $matches)) {
  177. // Is a range
  178. $isValid = $this->isInNumericRange($currentValue, (int)$matches[1], (int)$matches[2]);
  179. } else if (preg_match('/^(.+)\/(\d+)$/', $rangeArray[$i], $matches)) {
  180. // Is a range with a skip factor
  181. $skipRangeStr = $matches[1];
  182. $skipFactor = (int)$matches[2];
  183. if ($skipRangeStr == '*') {
  184. $isValid = true;
  185. } else if (preg_match('/^(\d*)\-(\d*)$/', $skipRangeStr, $matches)) {
  186. $isValid = $this->isInNumericRange($currentValue, (int)$matches[1], (int)$matches[2]);
  187. }
  188. if ($isValid) {
  189. // Check against skip factor
  190. $isValid = (strtotime("-$skipFactor $timeCompareStr") > $lastTimestamp);
  191. }
  192. }
  193. }
  194. return $isValid;
  195. }
  196. /**
  197. * Check if a numeric value is within the specified range.
  198. * @param $value int
  199. * @param $min int
  200. * @param $max int
  201. * @return boolean
  202. */
  203. function isInNumericRange($value, $min, $max) {
  204. return ($value >= $min && $value <= $max);
  205. }
  206. }
  207. ?>