8 use Elgg\Traits\Loggable;
 
    9 use Elgg\Traits\TimeUsing;
 
   23     protected const LOG_FILES_TO_KEEP = 5;
 
   25     protected array $default_intervals = [
 
   26         'minute' => 
'* * * * *',
 
   27         'fiveminute' => 
'*/5 * * * *',
 
   28         'fifteenmin' => 
'*/15 * * * *',
 
   29         'halfhour' => 
'*/30 * * * *',
 
   30         'hourly' => 
'0 * * * *',
 
   31         'daily' => 
'0 0 * * *',
 
   32         'weekly' => 
'0 0 * * 0',
 
   33         'monthly' => 
'0 0 1 * *',
 
   34         'yearly' => 
'0 0 1 1 *',
 
   55     public function run(?array $intervals = 
null, 
bool $force = 
false): array {
 
   56         if (!isset($intervals)) {
 
   57             $intervals = array_keys($this->default_intervals);
 
   60         $allowed_intervals = $this->getConfiguredIntervals();
 
   62         $scheduler = 
new Scheduler();
 
   63         $time = $this->getCurrentTime();
 
   65         foreach ($intervals as $interval) {
 
   66             if (!array_key_exists($interval, $allowed_intervals)) {
 
   67                 throw new CronException(
"{$interval} is not a recognized cron interval. Please use one of the following: " . implode(
', ', array_keys($allowed_intervals)));
 
   70             $cron_interval = $force ? $allowed_intervals[
'minute'] : $allowed_intervals[$interval];
 
   73             $cron_logger = \Elgg\Logger\Cron::factory([
 
   74                 'interval' => $interval,
 
   79                 ->call(
function () use ($interval, 
$time, $cron_logger, 
$filename) {
 
   83                 ->before(
function () use ($interval, 
$time, $cron_logger) {
 
   84                     $this->before($interval, $cron_logger, 
$time);
 
   86                 ->then(
function (
$output) use ($interval, $cron_logger) {
 
   87                     $this->after(
$output, $interval, $cron_logger);
 
   91         return $scheduler->run(\DateTime::createFromInterface(
$time));
 
  105             $this->events->triggerBefore(
'cron', $interval, 
$time);
 
  106         } 
catch (\Throwable $t) {
 
  107             $this->getLogger()->error($t);
 
  111         set_time_limit((
int) ini_get(
'max_execution_time'));
 
  113         $now = 
new DateTime();
 
  115         $cron_logger->notice($this->translator->translate(
'admin:cron:started', [$interval, 
$time->format(DATE_RFC2822)]));
 
  116         $cron_logger->notice($this->translator->translate(
'admin:cron:started:actual', [$interval, $now->format(DATE_RFC2822)]));
 
  131             $begin_callback = function (array 
$params) use ($cron_logger) {
 
  134                 $cron_logger->notice(
"Starting {$readable_callable}");
 
  137             $end_callback = 
function (array 
$params) use ($cron_logger) {
 
  140                 $cron_logger->notice(
"Finished {$readable_callable}");
 
  144             $this->events->triggerResults(
'cron', $interval, [
 
  145                 'time' => 
$time->getTimestamp(),
 
  147                 'logger' => $cron_logger,
 
  149                 EventsService::OPTION_BEGIN_CALLBACK => $begin_callback,
 
  150                 EventsService::OPTION_END_CALLBACK => $end_callback,
 
  151                 EventsService::OPTION_CONTINUE_ON_EXCEPTION => 
true,
 
  153         } 
catch (\Throwable $t) {
 
  157         $now = 
new DateTime();
 
  159         $complete = $this->translator->translate(
'admin:cron:complete', [$interval, $now->format(DATE_RFC2822)]);
 
  160         $cron_logger->notice($complete);
 
  179         $this->getLogger()->info(
$output);
 
  182             $this->events->triggerAfter(
'cron', $interval, 
new \
DateTime());
 
  183         } 
catch (\Throwable $t) {
 
  184             $this->getLogger()->error($t);
 
  187         $cron_logger->close();
 
  188         $this->rotateLogs($interval);
 
  189         $this->logCompletion($interval);
 
  202     public function getLogs(
string $interval, 
bool $filenames_only = 
false): array {
 
  205         $fh->setFilename(
"cron/{$interval}/dummy.log");
 
  207         $dir = pathinfo($fh->getFilenameOnFilestore(), PATHINFO_DIRNAME);
 
  208         if (!is_dir($dir) || !is_readable($dir)) {
 
  212         $dh = new \DirectoryIterator($dir);
 
  215         foreach ($dh as $file) {
 
  216             if ($file->isDot() || !$file->isFile() || $file->getExtension() !== 
'log') {
 
  220             if ($filenames_only) {
 
  221                 $files[] = $file->getFilename();
 
  223                 $files[$file->getFilename()] = file_get_contents($file->getPathname());
 
  227         if ($filenames_only) {
 
  230             uksort($files, 
'strnatcasecmp');
 
  233         return array_reverse($files);
 
  246         $fh->setFilename(
"cron/{$interval}.complete");
 
  248         if (!$fh->exists()) {
 
  252         $date = $fh->grabFile();
 
  259             return Values::normalizeTime($date);
 
  260         } 
catch (\
Elgg\Exceptions\ExceptionInterface $e) {
 
  276         $result = $this->events->triggerResults(
'cron:intervals', 
'system', [], $this->default_intervals);
 
  278             $this->getLogger()->warning(
"The event 'cron:intervals', 'system' should return an array, " . gettype(
$result) . 
' given');
 
  280             $result = $this->default_intervals;
 
  299         $date = 
$time->format(\DateTimeInterface::ATOM);
 
  300         $date = str_replace(
'+', 
'p', $date);
 
  301         $date = preg_replace(
'/[^a-zA-Z0-9_-]+/', 
'-', $date);
 
  303         $fh = new \ElggFile();
 
  305         $fh->setFilename(
"cron/{$interval}/{$date}.log");
 
  307         return $fh->getFilenameOnFilestore();
 
  318         $files = $this->getLogs($interval, true);
 
  319         if (count($files) <= self::LOG_FILES_TO_KEEP) {
 
  323         $fh = new \ElggFile();
 
  326         while (count($files) > self::LOG_FILES_TO_KEEP) {
 
  329             $fh->setFilename(
"cron/{$interval}/{$filename}");
 
  344         $fh->setFilename(
"cron/{$interval}.complete");
 
  347             if ($fh->open(
'write') === 
false) {
 
  351             $this->getLogger()->warning($e);
 
  355         $now = 
new DateTime();
 
  356         $fh->write($now->format(\DateTimeInterface::ATOM));
 
getLogger()
Returns logger.
$params
Saves global plugin settings.
if(! $annotation instanceof ElggAnnotation) $time
before(string $interval, \Elgg\Logger\Cron $cron_logger, \DateTimeImmutable $time)
Execute commands before cron interval is run.
execute(string $interval, \Elgg\Logger\Cron $cron_logger, string $filename, \DateTimeImmutable $time)
Execute handlers attached to a specific cron interval.
getLogFilename(string $interval, \DateTimeInterface $time)
Get a filename to log in.
logCompletion(string $interval)
Log the completion time of a cron interval.
getLogs(string $interval, bool $filenames_only=false)
Get the log files for a given cron interval.
getLastCompletion(string $interval)
Get the time of the last completion of a cron interval.
run(?array $intervals=null, bool $force=false)
Executes handlers for periods that have elapsed since last cron.
after(string $output, string $interval, \Elgg\Logger\Cron $cron_logger)
Printers handler result.
getConfiguredIntervals(bool $only_names=false)
Get the cron interval configuration.
__construct(protected EventsService $events, protected Translator $translator)
Constructor.
rotateLogs(string $interval)
Rotate the log files.
A generic parent class for cron exceptions.
Extension of the DateTime class to support formatting a date using the locale.
elgg_extract($key, $array, $default=null, bool $strict=true)
Checks for $array[$key] and returns its value if it exists, else returns $default.
elgg_get_site_entity()
Get the current site entity.
Generic interface which allows catching of all exceptions thrown in Elgg.
if(parse_url(elgg_get_site_url(), PHP_URL_PATH) !=='/') if(file_exists(elgg_get_root_path() . 'robots.txt'))
Set robots.txt.