PageRenderTime 890ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/pkp/classes/cliTool/ScheduledTaskTool.inc.php

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