1 | <?php |
||||||
2 | |||||||
3 | namespace Elgg; |
||||||
4 | |||||||
5 | use DateTime; |
||||||
6 | use GO\Job; |
||||||
7 | use GO\Scheduler; |
||||||
8 | use Zend\Validator\Date; |
||||||
9 | |||||||
10 | /** |
||||||
11 | * Cron |
||||||
12 | * |
||||||
13 | * @internal |
||||||
14 | */ |
||||||
15 | class Cron { |
||||||
16 | |||||||
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 | |||||||
31 | /** |
||||||
32 | * @var PluginHooksService |
||||||
33 | */ |
||||||
34 | protected $hooks; |
||||||
35 | |||||||
36 | /** |
||||||
37 | * @var Printer |
||||||
38 | */ |
||||||
39 | protected $printer; |
||||||
40 | |||||||
41 | /** |
||||||
42 | * Constructor |
||||||
43 | * |
||||||
44 | * @param PluginHooksService $hooks Hooks service |
||||||
45 | * @param Printer $printer Printer |
||||||
46 | */ |
||||||
47 | 7 | public function __construct(PluginHooksService $hooks, Printer $printer) { |
|||||
48 | 7 | $this->hooks = $hooks; |
|||||
49 | 7 | $this->printer = $printer; |
|||||
50 | 7 | } |
|||||
51 | |||||||
52 | /** |
||||||
53 | * Executes handlers for periods that have elapsed since last cron |
||||||
54 | * |
||||||
55 | * @param array $intervals Interval names to run |
||||||
56 | * |
||||||
57 | * @return Job[] |
||||||
58 | * @throws \CronException |
||||||
59 | */ |
||||||
60 | 6 | public function run(array $intervals = null) { |
|||||
61 | |||||||
62 | 6 | if (!isset($intervals)) { |
|||||
63 | 2 | $intervals = array_keys(self::$intervals); |
|||||
64 | } |
||||||
65 | |||||||
66 | 6 | $scheduler = new Scheduler(); |
|||||
67 | |||||||
68 | 6 | $time = $this->getCurrentTime(); |
|||||
69 | |||||||
70 | 6 | foreach ($intervals as $interval) { |
|||||
71 | 6 | if (!array_key_exists($interval, self::$intervals)) { |
|||||
72 | 1 | throw new \CronException("$interval is not a recognized cron interval"); |
|||||
73 | } |
||||||
74 | |||||||
75 | $scheduler |
||||||
76 | 5 | ->call(function () use ($interval, $time) { |
|||||
77 | 5 | return $this->execute($interval, $time); |
|||||
78 | 5 | }) |
|||||
79 | 5 | ->at(self::$intervals[$interval]) |
|||||
80 | 5 | ->before(function () use ($interval, $time) { |
|||||
81 | 5 | $this->before($interval, $time); |
|||||
82 | 5 | }) |
|||||
83 | 5 | ->then(function ($output) use ($interval) { |
|||||
84 | 5 | $this->after($output, $interval); |
|||||
85 | 5 | }); |
|||||
86 | } |
||||||
87 | |||||||
88 | 5 | return $scheduler->run($time); |
|||||
89 | } |
||||||
90 | |||||||
91 | /** |
||||||
92 | * Execute commands before cron interval is run |
||||||
93 | * |
||||||
94 | * @param string $interval Interval name |
||||||
95 | * @param DateTime $time Time of the cron initialization |
||||||
96 | * |
||||||
97 | * @return void |
||||||
98 | */ |
||||||
99 | 5 | protected function before($interval, DateTime $time = null) { |
|||||
100 | |||||||
101 | 5 | if (!isset($time)) { |
|||||
102 | $time = $this->getCurrentTime(); |
||||||
103 | } |
||||||
104 | |||||||
105 | 5 | $this->hooks->getEvents()->triggerBefore('cron', $interval, $time); |
|||||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||||
106 | |||||||
107 | // give every period at least 'max_execution_time' (PHP ini setting) |
||||||
108 | 5 | set_time_limit((int) ini_get('max_execution_time')); |
|||||
109 | |||||||
110 | 5 | $formatted_time = $time->format('r'); |
|||||
111 | |||||||
112 | 5 | $msg = elgg_echo('admin:cron:started', [$interval, $formatted_time]) . PHP_EOL; |
|||||
113 | |||||||
114 | 5 | $this->log('output', $interval, $msg); |
|||||
115 | 5 | } |
|||||
116 | |||||||
117 | /** |
||||||
118 | * Execute handlers attached to a specific cron interval |
||||||
119 | * |
||||||
120 | * @param string $interval Cron interval to execute |
||||||
121 | * @param DateTime $time Time of cron initialization |
||||||
122 | * |
||||||
123 | * @return string |
||||||
124 | */ |
||||||
125 | 5 | protected function execute($interval, DateTime $time = null) { |
|||||
126 | |||||||
127 | 5 | if (!isset($time)) { |
|||||
128 | $time = $this->getCurrentTime(); |
||||||
129 | } |
||||||
130 | |||||||
131 | 5 | $output = []; |
|||||
132 | |||||||
133 | 5 | $output[] = elgg_echo('admin:cron:started', [$interval, $time->format('r')]); |
|||||
134 | |||||||
135 | 5 | ob_start(); |
|||||
136 | |||||||
137 | 5 | $old_stdout = $this->hooks->trigger('cron', $interval, [ |
|||||
138 | 5 | 'time' => $time->getTimestamp(), |
|||||
139 | 5 | 'dt' => $time, |
|||||
140 | 5 | ], ''); |
|||||
141 | |||||||
142 | 5 | $output[] = ob_get_clean(); |
|||||
143 | 5 | $output[] = $old_stdout; |
|||||
144 | |||||||
145 | 5 | $time = $this->getCurrentTime(); |
|||||
146 | |||||||
147 | 5 | $output[] = elgg_echo('admin:cron:complete', [$interval, $time->format('r')]); |
|||||
148 | |||||||
149 | 5 | return implode(PHP_EOL, array_filter($output)); |
|||||
150 | } |
||||||
151 | |||||||
152 | /** |
||||||
153 | * Printers handler result |
||||||
154 | * |
||||||
155 | * @param string $output Output string |
||||||
156 | * @param string $interval Interval name |
||||||
157 | * |
||||||
158 | * @return void |
||||||
159 | */ |
||||||
160 | 5 | protected function after($output, $interval) { |
|||||
161 | |||||||
162 | 5 | $time = new \DateTime(); |
|||||
163 | |||||||
164 | 5 | $this->log('output', $interval, $output); |
|||||
165 | 5 | $this->log('completion', $interval, $time->getTimestamp()); |
|||||
166 | |||||||
167 | 5 | $this->printer->write($output, null, Logger::$verbosity); |
|||||
0 ignored issues
–
show
The call to
Elgg\Printer::write() has too many arguments starting with Elgg\Logger::verbosity .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.
Loading history...
|
|||||||
168 | |||||||
169 | 5 | $this->hooks->getEvents()->triggerAfter('cron', $interval, $time); |
|||||
0 ignored issues
–
show
$time of type DateTime is incompatible with the type string expected by parameter $object of Elgg\EventsService::triggerAfter() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
170 | 5 | } |
|||||
171 | |||||||
172 | /** |
||||||
173 | * Populate sites private settings with cron info |
||||||
174 | * |
||||||
175 | * @param string $setting 'output'|'completion' |
||||||
176 | * @param string $interval Interval name |
||||||
177 | * @param string $msg Logged message |
||||||
178 | * |
||||||
179 | * @return void |
||||||
180 | */ |
||||||
181 | 5 | protected function log($setting, $interval, $msg = '') { |
|||||
182 | 5 | $suffix = $setting === 'completion' ? 'ts' : 'msg'; |
|||||
183 | 5 | $msg_key = "cron_latest:$interval:$suffix"; |
|||||
184 | |||||||
185 | 5 | elgg_get_site_entity()->setPrivateSetting($msg_key, $msg); |
|||||
186 | 5 | } |
|||||
187 | |||||||
188 | } |
||||||
189 |