ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
CronJob.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
21 namespace ILIAS\Cron;
22 
25 
26 abstract class CronJob
27 {
29  protected ?int $schedule_value = null;
30  protected ?\Closure $date_time_provider = null;
31 
32  private function checkWeeklySchedule(\DateTimeImmutable $last_run, \DateTimeImmutable $now): bool
33  {
34  if ($last_run > $now) {
35  // Defensive check: last run is in the future → don't run again
36  return false;
37  }
38 
39  // We are using ISO week/year to handle issues with week #52/#53 (see: https://mantis.ilias.de/view.php?id=36118 / https://en.wikipedia.org/wiki/ISO_8601#Week_dates)
40  return $last_run->format('o-W') !== $now->format('o-W');
41  }
42 
43  private function checkSchedule(
44  ?\DateTimeImmutable $last_run,
45  ?JobScheduleType $schedule_type,
46  ?int $schedule_value
47  ): bool {
48  if (null === $schedule_type) {
49  return false;
50  }
51 
52  if (null === $last_run) {
53  return true;
54  }
55 
56  if ($this->date_time_provider === null) {
57  $now = new \DateTimeImmutable('@' . time(), new \DateTimeZone(date_default_timezone_get()));
58  } else {
59  $now = ($this->date_time_provider)();
60  }
61 
62  switch ($schedule_type) {
63  case JobScheduleType::DAILY:
64  $last = $last_run->format('Y-m-d');
65  $ref = $now->format('Y-m-d');
66  return ($last !== $ref);
67 
68  case JobScheduleType::WEEKLY:
69  return $this->checkWeeklySchedule($last_run, $now);
70 
71  case JobScheduleType::MONTHLY:
72  $last = $last_run->format('Y-n');
73  $ref = $now->format('Y-n');
74  return ($last !== $ref);
75 
76  case JobScheduleType::QUARTERLY:
77  $last = $last_run->format('Y') . '-' . ceil(((int) $last_run->format('n')) / 3);
78  $ref = $now->format('Y') . '-' . ceil(((int) $now->format('n')) / 3);
79  return ($last !== $ref);
80 
82  $last = $last_run->format('Y');
83  $ref = $now->format('Y');
84  return ($last !== $ref);
85 
86  case JobScheduleType::IN_MINUTES:
87  $diff = floor(($now->getTimestamp() - $last_run->getTimestamp()) / 60);
88  return ($diff >= $schedule_value);
89 
90  case JobScheduleType::IN_HOURS:
91  $diff = floor(($now->getTimestamp() - $last_run->getTimestamp()) / (60 * 60));
92  return ($diff >= $schedule_value);
93 
94  case JobScheduleType::IN_DAYS:
95  $diff = floor(($now->getTimestamp() - $last_run->getTimestamp()) / (60 * 60 * 24));
96  return ($diff >= $schedule_value);
97  }
98 
99  return false;
100  }
101 
105  public function setDateTimeProvider(?\Closure $date_time_provider): void
106  {
107  if ($date_time_provider !== null) {
108  $r = new \ReflectionFunction($date_time_provider);
109  $return_type = $r->getReturnType();
110  if ($return_type instanceof \ReflectionNamedType) {
111  $return_type = $return_type->getName();
112  }
113  $expected_type = \DateTimeInterface::class;
114  if (!is_subclass_of($return_type, $expected_type)) {
115  throw new \InvalidArgumentException(
116  \sprintf(
117  'The return type of the datetime provider must be of type %s',
118  $expected_type
119  )
120  );
121  }
122 
123  $r = new \ReflectionFunction($date_time_provider);
124  $parameters = $r->getParameters();
125  if ($parameters !== []) {
126  throw new \InvalidArgumentException(
127  'The datetime provider must not define any parameters',
128  );
129  }
130  }
131 
132  $this->date_time_provider = $date_time_provider;
133  }
134 
135  public function isDue(
136  ?\DateTimeImmutable $last_run,
137  ?JobScheduleType $schedule_type,
138  ?int $schedule_value,
139  bool $is_manually_executed = false
140  ): bool {
141  if ($is_manually_executed) {
142  return true;
143  }
144 
145  if (!$this->hasFlexibleSchedule()) {
146  $schedule_type = $this->getDefaultScheduleType();
147  $schedule_value = $this->getDefaultScheduleValue();
148  }
149 
150  return $this->checkSchedule($last_run, $schedule_type, $schedule_value);
151  }
152 
156  public function getScheduleType(): ?JobScheduleType
157  {
158  if ($this->schedule_type && $this->hasFlexibleSchedule()) {
159  return $this->schedule_type;
160  }
161 
162  return null;
163  }
164 
168  public function getScheduleValue(): ?int
169  {
170  if ($this->schedule_value && $this->hasFlexibleSchedule()) {
171  return $this->schedule_value;
172  }
173 
174  return null;
175  }
176 
180  public function setSchedule(?JobScheduleType $a_type, ?int $a_value): void
181  {
182  if (
183  $a_value &&
184  $this->hasFlexibleSchedule() &&
185  \in_array($a_type, $this->getValidScheduleTypes(), true)
186  ) {
187  $this->schedule_type = $a_type;
188  $this->schedule_value = $a_value;
189  }
190  }
191 
196  public function getAllScheduleTypes(): array
197  {
198  return JobScheduleType::cases();
199  }
200 
204  public function getScheduleTypesWithValues(): array
205  {
206  return [
207  JobScheduleType::IN_MINUTES,
208  JobScheduleType::IN_HOURS,
209  JobScheduleType::IN_DAYS,
210  ];
211  }
212 
217  public function getValidScheduleTypes(): array
218  {
219  return $this->getAllScheduleTypes();
220  }
221 
222  public function isManuallyExecutable(): bool
223  {
224  return true;
225  }
226 
227  public function hasCustomSettings(): bool
228  {
229  return false;
230  }
231 
235  #[\Deprecated('Will be removed without any alternative, KS/UI forms will be expected', since: '13.0')]
236  public function usesLegacyForms(): bool
237  {
238  return true;
239  }
240 
242  \ILIAS\UI\Factory $ui_factory,
243  \ILIAS\Refinery\Factory $factory,
245  ): \ILIAS\UI\Component\Input\Container\Form\FormInput {
246  throw new \RuntimeException('Not implemented');
247  }
248 
252  #[\Deprecated('Will be removed without any alternative, KS/UI forms will be expected', since: '13.0')]
253  public function addCustomSettingsToForm(\ilPropertyFormGUI $a_form): void
254  {
255  }
256 
262  public function saveCustomConfiguration(mixed $form_data): void
263  {
264  throw new \RuntimeException('Not implemented');
265  }
266 
270  #[\Deprecated('Will be removed without any alternative, KS/UI forms will be expected', since: '13.0')]
271  public function saveCustomSettings(\ilPropertyFormGUI $a_form): bool
272  {
273  return true;
274  }
275 
279  public function addToExternalSettingsForm(int $a_form_id, array &$a_fields, bool $a_is_active): void
280  {
281  }
282 
287  public function activationWasToggled(\ilDBInterface $db, \ilSetting $setting, bool $a_currently_active): void
288  {
289  }
290 
291  abstract public function getId(): string;
292 
293  abstract public function getTitle(): string;
294 
295  abstract public function getDescription(): string;
296 
300  abstract public function hasAutoActivation(): bool;
301 
302  abstract public function hasFlexibleSchedule(): bool;
303 
304  abstract public function getDefaultScheduleType(): JobScheduleType;
305 
306  abstract public function getDefaultScheduleValue(): ?int;
307 
308  abstract public function run(): JobResult;
309 }
JobScheduleType $schedule_type
Definition: CronJob.php:28
activationWasToggled(\ilDBInterface $db, \ilSetting $setting, bool $a_currently_active)
Important: This method is (also) called from the setup process, where the constructor of an ilCronJob...
Definition: CronJob.php:287
getScheduleType()
Get current schedule type (if flexible)
Definition: CronJob.php:156
checkWeeklySchedule(\DateTimeImmutable $last_run, \DateTimeImmutable $now)
Definition: CronJob.php:32
Interface Observer Contains several chained tasks and infos about them.
isDue(?\DateTimeImmutable $last_run, ?JobScheduleType $schedule_type, ?int $schedule_value, bool $is_manually_executed=false)
Definition: CronJob.php:135
hasAutoActivation()
Is to be activated on "installation", does only work for ILIAS core cron jobs.
saveCustomConfiguration(mixed $form_data)
Definition: CronJob.php:262
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
ilSetting $setting
Definition: class.ilias.php:68
addToExternalSettingsForm(int $a_form_id, array &$a_fields, bool $a_is_active)
Definition: CronJob.php:279
getCustomConfigurationInput(\ILIAS\UI\Factory $ui_factory, \ILIAS\Refinery\Factory $factory, \ilLanguage $lng)
Definition: CronJob.php:241
setSchedule(?JobScheduleType $a_type, ?int $a_value)
Update current schedule (if flexible)
Definition: CronJob.php:180
addCustomSettingsToForm(\ilPropertyFormGUI $a_form)
Definition: CronJob.php:253
getScheduleValue()
Get current schedule value (if flexible)
Definition: CronJob.php:168
Builds data types.
Definition: Factory.php:35
saveCustomSettings(\ilPropertyFormGUI $a_form)
Definition: CronJob.php:271
getValidScheduleTypes()
Returns a collection of all valid schedule types for a specific job.
Definition: CronJob.php:217
setDateTimeProvider(?\Closure $date_time_provider)
Definition: CronJob.php:105
Closure $date_time_provider
Definition: CronJob.php:30
global $lng
Definition: privfeed.php:31
getScheduleTypesWithValues()
Definition: CronJob.php:204
getAllScheduleTypes()
Get all available schedule types.
Definition: CronJob.php:196
checkSchedule(?\DateTimeImmutable $last_run, ?JobScheduleType $schedule_type, ?int $schedule_value)
Definition: CronJob.php:43
$r