ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.ilCronManagerGUI.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
25 
34 {
35  private readonly ilLanguage $lng;
36  private readonly ilCtrlInterface $ctrl;
37  private readonly ilSetting $settings;
38  private readonly ilGlobalTemplateInterface $tpl;
39  private readonly Factory $uiFactory;
40  private readonly Renderer $uiRenderer;
41  private readonly ilUIService $uiService;
43  private readonly \ILIAS\DI\RBACServices $rbac;
44  private readonly ilErrorHandling $error;
45  private readonly WrapperFactory $httpRequest;
46  private readonly \ILIAS\Refinery\Factory $refinery;
47  private readonly ilCronManager $cronManager;
48  private readonly ilObjUser $actor;
49 
50  public function __construct()
51  {
53  global $DIC;
54 
55  $this->lng = $DIC->language();
56  $this->ctrl = $DIC->ctrl();
57  $this->settings = $DIC->settings();
58  $this->tpl = $DIC->ui()->mainTemplate();
59  $this->uiFactory = $DIC->ui()->factory();
60  $this->uiRenderer = $DIC->ui()->renderer();
61  $this->uiService = $DIC->uiService();
62  $this->rbac = $DIC->rbac();
63  $this->error = $DIC['ilErr'];
64  $this->httpRequest = $DIC->http()->wrapper();
65  $this->refinery = $DIC->refinery();
66  $this->actor = $DIC->user();
67  $this->cronRepository = $DIC->cron()->repository();
68  $this->cronManager = $DIC->cron()->manager();
69 
70  $this->lng->loadLanguageModule('cron');
71  $this->lng->loadLanguageModule('cmps');
72  }
73 
78  protected function getRequestValue(
79  string $key,
80  \ILIAS\Refinery\Transformation $trafo,
81  bool $forceRetrieval = false,
82  $default = null
83  ) {
84  $exc = null;
85 
86  try {
87  if ($forceRetrieval || $this->httpRequest->query()->has($key)) {
88  return $this->httpRequest->query()->retrieve($key, $trafo);
89  }
90  } catch (OutOfBoundsException $e) {
91  $exc = $e;
92  }
93 
94  try {
95  if ($forceRetrieval || $this->httpRequest->post()->has($key)) {
96  return $this->httpRequest->post()->retrieve($key, $trafo);
97  }
98  } catch (OutOfBoundsException $e) {
99  $exc = $e;
100  }
101 
102  if ($forceRetrieval && $exc) {
103  throw $exc;
104  }
105 
106  return $default ?? null;
107  }
108 
109  public function executeCommand(): void
110  {
111  if (!$this->rbac->system()->checkAccess('visible,read', SYSTEM_FOLDER_ID)) {
112  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
113  }
114 
115  $class = $this->ctrl->getNextClass($this);
116 
118  switch (strtolower($class)) {
119  case strtolower(ilPropertyFormGUI::class):
120  $job_id = $this->getRequestValue('jid', $this->refinery->kindlyTo()->string());
121  $form = $this->initEditForm(ilUtil::stripSlashes($job_id));
122  $this->ctrl->forwardCommand($form);
123  break;
124  }
125 
126  $cmd = $this->ctrl->getCmd('render');
127  $this->$cmd();
128  }
129 
130  protected function render(): void
131  {
132  $tstamp = $this->lng->txt('cronjob_last_start_unknown');
133  if ($this->settings->get('last_cronjob_start_ts')) {
135  new ilDateTime(
136  $this->settings->get('last_cronjob_start_ts'),
138  )
139  );
140  }
141 
142  $message = $this->uiFactory->messageBox()->info($this->lng->txt('cronjob_last_start') . ': ' . $tstamp);
143 
144  $cronJobs = $this->cronRepository->findAll();
145 
146  $tableFilterMediator = new ilCronManagerTableFilterMediator(
147  $cronJobs,
148  $this->uiFactory,
149  $this->uiService,
150  $this->lng
151  );
152  $filter = $tableFilterMediator->filter($this->ctrl->getFormAction(
153  $this,
154  'render',
155  '',
156  true
157  ));
158 
159  $tbl = new ilCronManagerTableGUI(
160  $this,
161  $this->cronRepository,
162  'render',
163  $this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)
164  );
165  $this->tpl->setContent(implode('', [
166  $this->uiRenderer->render([$message, $filter]),
167  $tbl->populate(
168  $tableFilterMediator->filteredJobs(
169  $filter
170  )
171  )->getHTML()
172  ]));
173  }
174 
175  public function edit(ilPropertyFormGUI $a_form = null): void
176  {
177  if (!$this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)) {
178  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
179  }
180 
181  $job_id = $this->getRequestValue('jid', $this->refinery->kindlyTo()->string());
182  if (!$job_id) {
183  $this->ctrl->redirect($this, 'render');
184  }
185 
186  if ($a_form === null) {
187  $a_form = $this->initEditForm($job_id);
188  }
189 
190  $this->tpl->setContent($a_form->getHTML());
191  }
192 
193  private function getScheduleTypeFormElementName(CronJobScheduleType $schedule_type): string
194  {
195  return match ($schedule_type) {
196  CronJobScheduleType::SCHEDULE_TYPE_DAILY => $this->lng->txt('cron_schedule_daily'),
197  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY => $this->lng->txt('cron_schedule_weekly'),
198  CronJobScheduleType::SCHEDULE_TYPE_MONTHLY => $this->lng->txt('cron_schedule_monthly'),
199  CronJobScheduleType::SCHEDULE_TYPE_QUARTERLY => $this->lng->txt('cron_schedule_quarterly'),
200  CronJobScheduleType::SCHEDULE_TYPE_YEARLY => $this->lng->txt('cron_schedule_yearly'),
201  CronJobScheduleType::SCHEDULE_TYPE_IN_MINUTES => sprintf($this->lng->txt('cron_schedule_in_minutes'), 'x'),
202  CronJobScheduleType::SCHEDULE_TYPE_IN_HOURS => sprintf($this->lng->txt('cron_schedule_in_hours'), 'x'),
203  CronJobScheduleType::SCHEDULE_TYPE_IN_DAYS => sprintf($this->lng->txt('cron_schedule_in_days'), 'x'),
204  };
205  }
206 
207  protected function getScheduleValueFormElementName(CronJobScheduleType $schedule_type): string
208  {
209  return match ($schedule_type) {
210  CronJobScheduleType::SCHEDULE_TYPE_IN_MINUTES => 'smini',
211  CronJobScheduleType::SCHEDULE_TYPE_IN_HOURS => 'shri',
212  CronJobScheduleType::SCHEDULE_TYPE_IN_DAYS => 'sdyi',
213  default => throw new InvalidArgumentException(sprintf(
214  'The passed argument %s is invalid!',
215  var_export($schedule_type, true)
216  )),
217  };
218  }
219 
220  protected function hasScheduleValue(CronJobScheduleType $schedule_type): bool
221  {
222  return in_array($schedule_type, [
223  CronJobScheduleType::SCHEDULE_TYPE_IN_MINUTES,
224  CronJobScheduleType::SCHEDULE_TYPE_IN_HOURS,
225  CronJobScheduleType::SCHEDULE_TYPE_IN_DAYS
226  ], true);
227  }
228 
229  protected function initEditForm(string $a_job_id): ilPropertyFormGUI
230  {
231  $job = $this->cronRepository->getJobInstanceById($a_job_id);
232  if (!($job instanceof ilCronJob)) {
233  $this->ctrl->redirect($this, 'render');
234  }
235 
236  $this->ctrl->setParameter($this, 'jid', $a_job_id);
237 
238  $jobs_data = $this->cronRepository->getCronJobData($job->getId());
239  $job_data = $jobs_data[0];
240 
241  $form = new ilPropertyFormGUI();
242  $form->setFormAction($this->ctrl->getFormAction($this, 'update'));
243  $form->setTitle($this->lng->txt('cron_action_edit') . ': "' . $job->getTitle() . '"');
244 
245  if ($job->hasFlexibleSchedule()) {
246  $type = new ilRadioGroupInputGUI($this->lng->txt('cron_schedule_type'), 'type');
247  $type->setRequired(true);
248  $type->setValue($job_data['schedule_type'] === null ? null : (string) $job_data['schedule_type']);
249 
250  foreach ($job->getAllScheduleTypes() as $schedule_type) {
251  if (!in_array($schedule_type, $job->getValidScheduleTypes(), true)) {
252  continue;
253  }
254 
255  $option = new ilRadioOption(
256  $this->getScheduleTypeFormElementName($schedule_type),
257  (string) $schedule_type->value
258  );
259  $type->addOption($option);
260 
261  if (in_array($schedule_type, $job->getScheduleTypesWithValues(), true)) {
262  $scheduleValue = new ilNumberInputGUI(
263  $this->lng->txt('cron_schedule_value'),
264  $this->getScheduleValueFormElementName($schedule_type)
265  );
266  $scheduleValue->allowDecimals(false);
267  $scheduleValue->setRequired(true);
268  $scheduleValue->setSize(5);
269  if (is_numeric($job_data['schedule_type']) &&
270  CronJobScheduleType::tryFrom((int) $job_data['schedule_type']) === $schedule_type) {
271  $scheduleValue->setValue($job_data['schedule_value'] === null ? null : (string) $job_data['schedule_value']);
272  }
273  $option->addSubItem($scheduleValue);
274  }
275  }
276 
277  $form->addItem($type);
278  }
279 
280  if ($job->hasCustomSettings()) {
281  $job->addCustomSettingsToForm($form);
282  }
283 
284  $form->addCommandButton('update', $this->lng->txt('save'));
285  $form->addCommandButton('render', $this->lng->txt('cancel'));
286 
287  return $form;
288  }
289 
290  public function update(): void
291  {
292  if (!$this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)) {
293  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
294  }
295 
296  $job_id = $this->getRequestValue('jid', $this->refinery->kindlyTo()->string());
297  if (!$job_id) {
298  $this->ctrl->redirect($this, 'render');
299  }
300 
301  $form = $this->initEditForm($job_id);
302  if ($form->checkInput()) {
303  $job = $this->cronRepository->getJobInstanceById($job_id);
304  if ($job instanceof ilCronJob) {
305  $valid = true;
306  if ($job->hasCustomSettings() && !$job->saveCustomSettings($form)) {
307  $valid = false;
308  }
309 
310  if ($valid && $job->hasFlexibleSchedule()) {
311  $type = CronJobScheduleType::from((int) $form->getInput('type'));
312  $value = match (true) {
313  $this->hasScheduleValue($type) => (int) $form->getInput($this->getScheduleValueFormElementName($type)),
314  default => null,
315  };
316 
317  $this->cronRepository->updateJobSchedule($job, $type, $value);
318  }
319 
320  if ($valid) {
321  $this->tpl->setOnScreenMessage('success', $this->lng->txt('cron_action_edit_success'), true);
322  $this->ctrl->redirect($this, 'render');
323  }
324  }
325  }
326 
327  $form->setValuesByPost();
328  $this->edit($form);
329  }
330 
331  public function run(): void
332  {
333  $this->confirm('run');
334  }
335 
336  public function confirmedRun(): void
337  {
338  if (!$this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)) {
339  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
340  }
341 
342  $job_id = $this->getRequestValue('jid', $this->refinery->kindlyTo()->string());
343  if ($job_id) {
344  if ($this->cronManager->runJobManual($job_id, $this->actor)) {
345  $this->tpl->setOnScreenMessage('success', $this->lng->txt('cron_action_run_success'), true);
346  } else {
347  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('cron_action_run_fail'), true);
348  }
349  }
350 
351  $this->ctrl->redirect($this, 'render');
352  }
353 
354  public function activate(): void
355  {
356  $this->confirm('activate');
357  }
358 
359  public function confirmedActivate(): void
360  {
361  if (!$this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)) {
362  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
363  }
364 
365  $jobs = $this->getMultiActionData();
366  if ($jobs !== []) {
367  foreach ($jobs as $job) {
368  if ($this->cronManager->isJobInactive($job->getId())) {
369  $this->cronManager->resetJob($job, $this->actor);
370  }
371  }
372 
373  $this->tpl->setOnScreenMessage('success', $this->lng->txt('cron_action_activate_success'), true);
374  } else {
375  $this->tpl->setOnScreenMessage('info', $this->lng->txt('no_checkbox'), true);
376  }
377 
378  $this->ctrl->redirect($this, 'render');
379  }
380 
381  public function deactivate(): void
382  {
383  $this->confirm('deactivate');
384  }
385 
386  public function confirmedDeactivate(): void
387  {
388  if (!$this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)) {
389  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
390  }
391 
392  $jobs = $this->getMultiActionData();
393  if ($jobs !== []) {
394  foreach ($jobs as $job) {
395  if ($this->cronManager->isJobActive($job->getId())) {
396  $this->cronManager->deactivateJob($job, $this->actor, true);
397  }
398  }
399 
400  $this->tpl->setOnScreenMessage('success', $this->lng->txt('cron_action_deactivate_success'), true);
401  } else {
402  $this->tpl->setOnScreenMessage('info', $this->lng->txt('no_checkbox'), true);
403  }
404 
405  $this->ctrl->redirect($this, 'render');
406  }
407 
408  public function reset(): void
409  {
410  $this->confirm('reset');
411  }
412 
413  public function confirmedReset(): void
414  {
415  if (!$this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)) {
416  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
417  }
418 
419  $jobs = $this->getMultiActionData();
420  if ($jobs !== []) {
421  foreach ($jobs as $job) {
422  $this->cronManager->resetJob($job, $this->actor);
423  }
424  $this->tpl->setOnScreenMessage('success', $this->lng->txt('cron_action_reset_success'), true);
425  } else {
426  $this->tpl->setOnScreenMessage('info', $this->lng->txt('no_checkbox'), true);
427  }
428 
429  $this->ctrl->redirect($this, 'render');
430  }
431 
435  protected function getMultiActionData(): array
436  {
437  $res = [];
438 
439  $job_ids = [];
440  try {
441  try {
442  $job_ids = [$this->getRequestValue('jid', $this->refinery->kindlyTo()->string(), true)];
443  } catch (\ILIAS\Refinery\ConstraintViolationException | OutOfBoundsException) {
444  $job_ids = $this->getRequestValue('mjid', $this->refinery->kindlyTo()->listOf(
445  $this->refinery->kindlyTo()->string()
446  ), false, []);
447  }
448  } catch (\ILIAS\Refinery\ConstraintViolationException | OutOfBoundsException) {
449  }
450 
451  foreach ($job_ids as $job_id) {
452  $job = $this->cronRepository->getJobInstanceById($job_id);
453  if ($job instanceof ilCronJob) {
454  $res[$job_id] = $job;
455  }
456  }
457 
458  return $res;
459  }
460 
461  protected function confirm(string $a_action): void
462  {
463  if (!$this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)) {
464  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
465  }
466 
467  $jobs = $this->getMultiActionData();
468  if ($jobs === []) {
469  $this->tpl->setOnScreenMessage('info', $this->lng->txt('no_checkbox'), true);
470  $this->ctrl->redirect($this, 'render');
471  }
472 
473  if ('run' === $a_action) {
474  $jobs = array_filter($jobs, static function (ilCronJob $job): bool {
475  return $job->isManuallyExecutable();
476  });
477 
478  if ($jobs === []) {
479  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('cron_no_executable_job_selected'), true);
480  $this->ctrl->redirect($this, 'render');
481  }
482  }
483 
484  $cgui = new ilConfirmationGUI();
485 
486  if (1 === count($jobs)) {
487  $jobKeys = array_keys($jobs);
488  $job_id = array_pop($jobKeys);
489  $job = array_pop($jobs);
490  $title = $job->getTitle();
491  if (!$title) {
492  $title = preg_replace('[^A-Za-z0-9_\-]', '', $job->getId());
493  }
494 
495  $cgui->setHeaderText(sprintf(
496  $this->lng->txt('cron_action_' . $a_action . '_sure'),
497  $title
498  ));
499 
500  $this->ctrl->setParameter($this, 'jid', $job_id);
501  } else {
502  $cgui->setHeaderText($this->lng->txt('cron_action_' . $a_action . '_sure_multi'));
503 
504  foreach ($jobs as $job_id => $job) {
505  $cgui->addItem('mjid[]', $job_id, $job->getTitle());
506  }
507  }
508 
509  $cgui->setFormAction($this->ctrl->getFormAction($this, 'confirmed' . ucfirst($a_action)));
510  $cgui->setCancel($this->lng->txt('cancel'), 'render');
511  $cgui->setConfirm($this->lng->txt('cron_action_' . $a_action), 'confirmed' . ucfirst($a_action));
512 
513  $this->tpl->setContent($cgui->getHTML());
514  }
515 
516  public function addToExternalSettingsForm(int $a_form_id): array
517  {
518  $form_elements = [];
519  $fields = [];
520  $data = $this->cronRepository->getCronJobData();
521  foreach ($data as $item) {
522  $job = $this->cronRepository->getJobInstance(
523  $item['job_id'],
524  $item['component'],
525  $item['class']
526  );
527  if (!is_null($job)) {
528  $job->addToExternalSettingsForm($a_form_id, $fields, (bool) $item['job_status']);
529  }
530  }
531 
532  if ($fields !== []) {
533  $form_elements = [
534  'cron_jobs' => [
535  'jumpToCronJobs',
536  $fields
537  ]
538  ];
539  }
540 
541  return $form_elements;
542  }
543 }
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
An entity that renders components to a string output.
Definition: Renderer.php:30
$res
Definition: ltiservices.php:69
readonly ilCronJobRepository $cronRepository
readonly ilCtrlInterface $ctrl
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
readonly ILIAS Refinery Factory $refinery
Class ChatMainBarProvider .
readonly Factory $uiFactory
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
$valid
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false)
initEditForm(string $a_job_id)
readonly ilCronManager $cronManager
const IL_CAL_UNIX
Filter service.
readonly ilGlobalTemplateInterface $tpl
readonly ilSetting $settings
readonly ilErrorHandling $error
const SYSTEM_FOLDER_ID
Definition: constants.php:35
readonly Renderer $uiRenderer
confirm(string $a_action)
global $DIC
Definition: feed.php:28
This class represents a property in a property form.
__construct(VocabulariesInterface $vocabularies)
readonly ilObjUser $actor
readonly ILIAS DI RBACServices $rbac
getScheduleTypeFormElementName(CronJobScheduleType $schedule_type)
string $key
Consumer key/client ID value.
Definition: System.php:193
readonly ilUIService $uiService
setRequired(bool $a_required)
getScheduleValueFormElementName(CronJobScheduleType $schedule_type)
hasScheduleValue(CronJobScheduleType $schedule_type)
addToExternalSettingsForm(int $a_form_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Error Handling & global info handling.
readonly WrapperFactory $httpRequest
edit(ilPropertyFormGUI $a_form=null)
Class ilCronManagerGUI.
$message
Definition: xapiexit.php:32
getRequestValue(string $key, \ILIAS\Refinery\Transformation $trafo, bool $forceRetrieval=false, $default=null)
readonly ilLanguage $lng