Elgg  Version 3.0
Cron.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg;
4 
5 use DateTime;
6 use GO\Job;
7 use GO\Scheduler;
8 
14 class Cron {
15 
16  use Loggable;
17  use TimeUsing;
18 
19  static $intervals = [
20  'minute' => '* * * * *',
21  'fiveminute' => '*/5 * * * *',
22  'fifteenmin' => '*/15 * * * *',
23  'halfhour' => '*/30 * * * *',
24  'hourly' => '0 * * * *',
25  'daily' => '0 0 * * *',
26  'weekly' => '0 0 * * 0',
27  'monthly' => '0 0 1 * *',
28  'yearly' => '0 0 1 1 *',
29  ];
30 
34  protected $hooks;
35 
39  protected $events;
40 
48  public function __construct(PluginHooksService $hooks, Logger $logger, EventsService $events) {
49  $this->hooks = $hooks;
50  $this->logger = $logger;
51  $this->events = $events;
52  }
53 
63  public function run(array $intervals = null, $force = false) {
64 
65  if (!isset($intervals)) {
66  $intervals = array_keys(self::$intervals);
67  }
68 
69  $scheduler = new Scheduler();
70 
71  $time = $this->getCurrentTime();
72 
73  foreach ($intervals as $interval) {
74  if (!array_key_exists($interval, self::$intervals)) {
75  throw new \CronException("$interval is not a recognized cron interval");
76  }
77 
78  $cron_interval = $force ? self::$intervals['minute'] : self::$intervals[$interval];
79 
80  $scheduler
81  ->call(function () use ($interval, $time) {
82  return $this->execute($interval, $time);
83  })
84  ->at($cron_interval)
85  ->before(function () use ($interval, $time) {
86  $this->before($interval, $time);
87  })
88  ->then(function ($output) use ($interval) {
89  $this->after($output, $interval);
90  });
91  }
92 
93  return $scheduler->run($time);
94  }
95 
104  protected function before($interval, DateTime $time = null) {
105 
106  if (!isset($time)) {
107  $time = $this->getCurrentTime();
108  }
109 
110  $this->events->triggerBefore('cron', $interval, $time);
111 
112  // give every period at least 'max_execution_time' (PHP ini setting)
113  set_time_limit((int) ini_get('max_execution_time'));
114 
115  $now = new DateTime();
116 
117  $msg = elgg_echo('admin:cron:started', [$interval, $time->format(DATE_RFC2822)]) . PHP_EOL;
118  $msg .= elgg_echo('admin:cron:started:actual', [$interval, $now->format(DATE_RFC2822)]) . PHP_EOL;
119 
120  $this->log('output', $interval, $msg);
121  }
122 
131  protected function execute($interval, DateTime $time = null) {
132 
133  if (!isset($time)) {
134  $time = $this->getCurrentTime();
135  }
136 
137  $now = new DateTime();
138 
139  $output = [];
140 
141  $output[] = elgg_echo('admin:cron:started', [$interval, $time->format(DATE_RFC2822)]);
142  $output[] = elgg_echo('admin:cron:started:actual', [$interval, $now->format(DATE_RFC2822)]);
143 
144  ob_start();
145 
146  $old_stdout = $this->hooks->trigger('cron', $interval, [
147  'time' => $time->getTimestamp(),
148  'dt' => $time,
149  ], '');
150 
151  $output[] = ob_get_clean();
152  $output[] = $old_stdout;
153 
154  $now = new DateTime();
155 
156  $output[] = elgg_echo('admin:cron:complete', [$interval, $now->format(DATE_RFC2822)]);
157 
158  return implode(PHP_EOL, array_filter($output));
159  }
160 
169  protected function after($output, $interval) {
170 
171  $time = new DateTime();
172 
173  $this->log('output', $interval, $output);
174  $this->log('completion', $interval, $time->getTimestamp());
175 
176  $this->logger->info($output);
177 
178  $this->events->triggerAfter('cron', $interval, $time);
179  }
180 
190  protected function log($setting, $interval, $msg = '') {
191  $suffix = $setting ? : 'output';
192 
193  $fh = new \ElggFile();
194  $fh->owner_guid = elgg_get_site_entity()->guid;
195  $fh->setFilename("{$interval}-{$suffix}.log");
196 
197  $fh->open('write');
198  $fh->write($msg);
199  $fh->close();
200  }
201 
210  public function getLog($setting, $interval) {
211  $suffix = $setting ? : 'output';
212 
213  $fh = new \ElggFile();
214  $fh->owner_guid = elgg_get_site_entity()->guid;
215  $fh->setFilename("{$interval}-{$suffix}.log");
216 
217  if (!$fh->exists()) {
218  return '';
219  }
220 
221  $contents = $fh->grabFile();
222  if (!is_string($contents)) {
223  $contents = '';
224  }
225 
226  return $contents;
227  }
228 }
log($msg, $level=LogLevel::NOTICE)
Log a message.
Definition: Seeding.php:762
$events
Definition: Cron.php:39
if(!empty($title)&&!empty($icon_name)) if(!empty($title)) if(!empty($header)) if(!empty($body)) $contents
Definition: message.php:60
trait Loggable
Enables adding a logger.
Definition: Loggable.php:12
Events service.
getCurrentTime($modifier= '')
Get the (cloned) time.
Definition: TimeUsing.php:27
catch(LoginException $e) if($request->isXhr()) $output
Definition: login.php:56
elgg_echo($message_key, array $args=[], $language="")
Given a message key, returns an appropriately translated full-text string.
Definition: languages.php:21
Cron.
Definition: Cron.php:14
execute($interval, DateTime $time=null)
Execute handlers attached to a specific cron interval.
Definition: Cron.php:131
Logger.
Definition: Logger.php:25
Configuration exception.
$suffix
Definition: excerpt.php:13
if(!$entity instanceof ElggEntity) $time
Definition: time.php:21
__construct(PluginHooksService $hooks, Logger $logger, EventsService $events)
Constructor.
Definition: Cron.php:48
log($setting, $interval, $msg= '')
Log the results of a cron interval.
Definition: Cron.php:190
$hooks
Definition: Cron.php:34
after($output, $interval)
Printers handler result.
Definition: Cron.php:169
elgg_get_site_entity()
Get the current site entity.
Definition: entities.php:130
before($interval, DateTime $time=null)
Execute commands before cron interval is run.
Definition: Cron.php:104
getLog($setting, $interval)
Get the log contents of a cron interval.
Definition: Cron.php:210
trait TimeUsing
Adds methods for setting the current time (for testing)
Definition: TimeUsing.php:12
run(array $intervals=null, $force=false)
Executes handlers for periods that have elapsed since last cron.
Definition: Cron.php:63