Elgg  Version 5.0
Cron.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg;
4 
8 use GO\Job;
9 use GO\Scheduler;
10 
16 class Cron {
17 
18  use Loggable;
19  use TimeUsing;
20 
24  protected $default_intervals = [
25  'minute' => '* * * * *',
26  'fiveminute' => '*/5 * * * *',
27  'fifteenmin' => '*/15 * * * *',
28  'halfhour' => '*/30 * * * *',
29  'hourly' => '0 * * * *',
30  'daily' => '0 0 * * *',
31  'weekly' => '0 0 * * 0',
32  'monthly' => '0 0 1 * *',
33  'yearly' => '0 0 1 1 *',
34  ];
35 
39  protected $events;
40 
46  public function __construct(EventsService $events) {
47  $this->events = $events;
48  }
49 
59  public function run(array $intervals = null, $force = false) {
60 
61  if (!isset($intervals)) {
62  $intervals = array_keys($this->default_intervals);
63  }
64 
65  $allowed_intervals = $this->getConfiguredIntervals();
66 
67  $scheduler = new Scheduler();
68  $time = $this->getCurrentTime();
69 
70  foreach ($intervals as $interval) {
71  if (!array_key_exists($interval, $allowed_intervals)) {
72  throw new CronException("$interval is not a recognized cron interval");
73  }
74 
75  $cron_interval = $force ? $allowed_intervals['minute'] : $allowed_intervals[$interval];
76 
77  $scheduler
78  ->call(function () use ($interval, $time) {
79  return $this->execute($interval, $time);
80  })
81  ->at($cron_interval)
82  ->before(function () use ($interval, $time) {
83  $this->before($interval, $time);
84  })
85  ->then(function ($output) use ($interval) {
86  $this->after($output, $interval);
87  });
88  }
89 
90  return $scheduler->run($time);
91  }
92 
101  protected function before($interval, \DateTime $time = null) {
102 
103  if (!isset($time)) {
104  $time = $this->getCurrentTime();
105  }
106 
107  $this->events->triggerBefore('cron', $interval, $time);
108 
109  // give every period at least 'max_execution_time' (PHP ini setting)
110  set_time_limit((int) ini_get('max_execution_time'));
111 
112  $now = new \DateTime();
113 
114  $msg = elgg_echo('admin:cron:started', [$interval, $time->format(DATE_RFC2822)]) . PHP_EOL;
115  $msg .= elgg_echo('admin:cron:started:actual', [$interval, $now->format(DATE_RFC2822)]) . PHP_EOL;
116 
117  $this->cronLog('output', $interval, $msg);
118  }
119 
128  protected function execute($interval, \DateTime $time = null) {
129 
130  if (!isset($time)) {
131  $time = $this->getCurrentTime();
132  }
133 
134  $now = new \DateTime();
135 
136  $output = [];
137 
138  $output[] = elgg_echo('admin:cron:started', [$interval, $time->format(DATE_RFC2822)]);
139  $output[] = elgg_echo('admin:cron:started:actual', [$interval, $now->format(DATE_RFC2822)]);
140 
141  ob_start();
142 
143  $old_stdout = $this->events->triggerResults('cron', $interval, [
144  'time' => $time->getTimestamp(),
145  'dt' => $time,
146  ], '');
147 
148  $output[] = ob_get_clean();
149  $output[] = $old_stdout;
150 
151  $now = new \DateTime();
152 
153  $output[] = elgg_echo('admin:cron:complete', [$interval, $now->format(DATE_RFC2822)]);
154 
155  return implode(PHP_EOL, array_filter($output));
156  }
157 
166  protected function after($output, $interval) {
167 
168  $time = new \DateTime();
169 
170  $this->cronLog('output', $interval, $output);
171  $this->cronLog('completion', $interval, $time->getTimestamp());
172 
173  $this->getLogger()->info($output);
174 
175  $this->events->triggerAfter('cron', $interval, $time);
176  }
177 
187  protected function cronLog($setting, $interval, $msg = '') {
188  $suffix = $setting ?: 'output';
189 
190  $fh = new \ElggFile();
191  $fh->owner_guid = elgg_get_site_entity()->guid;
192  $fh->setFilename("{$interval}-{$suffix}.log");
193 
194  $fh->open('write');
195  $fh->write($msg);
196  $fh->close();
197  }
198 
207  public function getLog($setting, $interval) {
208  $suffix = $setting ?: 'output';
209 
210  $fh = new \ElggFile();
211  $fh->owner_guid = elgg_get_site_entity()->guid;
212  $fh->setFilename("{$interval}-{$suffix}.log");
213 
214  if (!$fh->exists()) {
215  return '';
216  }
217 
218  $contents = $fh->grabFile();
219  if (!is_string($contents)) {
220  $contents = '';
221  }
222 
223  return $contents;
224  }
225 
234  public function getConfiguredIntervals(bool $only_names = false) {
235  $result = $this->events->triggerResults('cron:intervals', 'system', [], $this->default_intervals);
236  if (!is_array($result)) {
237  $this->getLogger()->warning("The event 'cron:intervals', 'system' should return an array, " . gettype($result) . ' given');
238 
239  $result = $this->default_intervals;
240  }
241 
242  if ($only_names) {
243  return array_keys($result);
244  }
245 
246  return $result;
247  }
248 }
$events
Definition: Cron.php:39
getConfiguredIntervals(bool $only_names=false)
Get the cron interval configuration.
Definition: Cron.php:234
before($interval,\DateTime $time=null)
Execute commands before cron interval is run.
Definition: Cron.php:101
elgg_echo(string $message_key, array $args=[], string $language= '')
Elgg language module Functions to manage language and translations.
Definition: languages.php:17
if(!$annotation instanceof ElggAnnotation) $time
Definition: time.php:20
Events service.
trait TimeUsing
Adds methods for setting the current time (for testing)
Definition: TimeUsing.php:10
getCurrentTime($modifier= '')
Get the (cloned) time.
Definition: TimeUsing.php:25
Cron.
Definition: Cron.php:16
trait Loggable
Enables adding a logger.
Definition: Loggable.php:14
execute($interval,\DateTime $time=null)
Execute handlers attached to a specific cron interval.
Definition: Cron.php:128
$suffix
Definition: excerpt.php:13
after($output, $interval)
Printers handler result.
Definition: Cron.php:166
elgg_get_site_entity()
Get the current site entity.
Definition: entities.php:98
getLogger()
Returns logger.
Definition: Loggable.php:37
getLog($setting, $interval)
Get the log contents of a cron interval.
Definition: Cron.php:207
A generic parent class for cron exceptions.
run(array $intervals=null, $force=false)
Executes handlers for periods that have elapsed since last cron.
Definition: Cron.php:59
$output
Definition: download.php:9
if(!empty($title)&&!empty($icon_name)) if(!empty($title)) if(!empty($menu)) if(!empty($header)) if(!empty($body)) $contents
Definition: message.php:73
cronLog($setting, $interval, $msg= '')
Log the results of a cron interval.
Definition: Cron.php:187
__construct(EventsService $events)
Constructor.
Definition: Cron.php:46