ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.ilCronManagerGUI.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
33 
39 {
40  private const array TABLE_ACTION_NAMESPACE = ['cron', 'jobs'];
41  private const string TABLE_ACTION_PARAM_NAME = 'table_action';
42  private const string TABLE_ACTION_IDENTIFIER_NAME = 'jid';
43  private const string FORM_PARAM_SCHEDULE_PREFIX = 'schedule_';
44  public const FORM_PARAM_MAIN_SECTION = 'main';
45  public const FORM_PARAM_JOB_INPUT = 'additional_job_input';
46  public const FORM_PARAM_GROUP_SCHEDULE = 'schedule';
47 
48  private readonly ilLanguage $lng;
49  private readonly ilCtrlInterface $ctrl;
50  private readonly ilSetting $settings;
51  private readonly ilGlobalTemplateInterface $tpl;
52  private readonly Factory $ui_factory;
53  private readonly Renderer $ui_renderer;
54  private readonly ilUIService $ui_service;
55  private readonly JobRepository $cron_repository;
56  private readonly \ILIAS\DI\RBACServices $rbac;
57  private readonly ilErrorHandling $error;
58  private readonly WrapperFactory $http_wrapper;
59  private readonly \ILIAS\HTTP\GlobalHttpState $http;
60  private readonly \ILIAS\Refinery\Factory $refinery;
61  private readonly JobManager $cron_manager;
62  private readonly ilObjUser $actor;
63 
64  public function __construct()
65  {
67  global $DIC;
68 
69  $this->lng = $DIC->language();
70  $this->ctrl = $DIC->ctrl();
71  $this->settings = $DIC->settings();
72  $this->tpl = $DIC->ui()->mainTemplate();
73  $this->ui_factory = $DIC->ui()->factory();
74  $this->ui_renderer = $DIC->ui()->renderer();
75  $this->ui_service = $DIC->uiService();
76  $this->rbac = $DIC->rbac();
77  $this->error = $DIC['ilErr'];
78  $this->http_wrapper = $DIC->http()->wrapper();
79  $this->http = $DIC->http();
80  $this->refinery = $DIC->refinery();
81  $this->actor = $DIC->user();
82  $this->cron_repository = $DIC->cron()->repository();
83  $this->cron_manager = $DIC->cron()->manager();
84 
85  $this->lng->loadLanguageModule('cron');
86  $this->lng->loadLanguageModule('cmps');
87  }
88 
92  private function retrieveTableActionJobIds(): array
93  {
94  $retrieval = $this->http_wrapper->query();
95  if (strtoupper($this->http->request()->getMethod()) === 'POST') {
96  $retrieval = $this->http_wrapper->post();
97  }
98 
99  $trafo = $this->refinery->byTrying([
100  $this->refinery->kindlyTo()->listOf($this->refinery->kindlyTo()->string()),
101  $this->refinery->always([])
102  ]);
103 
104  $ids = $retrieval->retrieve(
105  $this->getJobIdParameterName(),
106  $trafo
107  );
108 
109  if (count($ids) === 1 && $ids[0] === 'ALL_OBJECTS') {
110  $tableFilterMediator = new JobTableFilterMediator(
111  $this->cron_repository->findAll(),
114  $this->lng
115  );
116  $filter = $tableFilterMediator->filter(
117  $this->ctrl->getFormAction(
118  $this,
119  'render',
120  '',
121  true
122  )
123  );
124  $ids = array_map(
125  static fn(JobEntity $entity): string => $entity->getEffectiveJobId(),
126  $tableFilterMediator->filteredJobs(
127  $filter
128  )->toArray()
129  );
130  }
131 
132  return $ids;
133  }
134 
135  private function getTableActionParameterName(): string
136  {
137  return implode('_', array_merge(self::TABLE_ACTION_NAMESPACE, [self::TABLE_ACTION_PARAM_NAME]));
138  }
139 
144  private function addProblematicItemsInfo(
145  \ILIAS\Cron\Job\JobCollection $filtered_jobs,
146  \ILIAS\UI\Component\MessageBox\MessageBox $message,
147  array $components
148  ): array {
149  $problematic_jobs = $filtered_jobs->filter(static function (JobEntity $entity): bool {
150  return $entity->getJobResultStatus() === JobResult::STATUS_CRASHED;
151  });
152  if (count($problematic_jobs) > 0) {
153  $problematic_jobs_info = $this->ui_factory->messageBox()->info(
154  $this->lng->txt('cron_jobs_with_required_intervention')
155  )->withLinks(
156  array_map(
157  function (JobEntity $entity): \ILIAS\UI\Component\Link\Standard {
158  return $this->ui_factory->link()->standard(
159  $entity->getEffectiveTitle(),
160  '#job-' . $entity->getEffectiveJobId()
161  );
162  },
163  (new OrderedJobEntities(
164  $problematic_jobs,
165  OrderedJobEntities::ORDER_BY_NAME
166  ))->toArray()
167  )
168  );
169 
170  if (in_array($message, $components, true)) {
171  $components = array_merge(
172  array_slice($components, 0, array_search($message, $components, true) + 1),
173  [$problematic_jobs_info],
174  array_slice($components, array_search($message, $components, true) + 1)
175  );
176  } else {
177  array_unshift($components, $problematic_jobs_info);
178  }
179  }
180 
181  return $components;
182  }
183 
184  private function getJobIdParameterName(): string
185  {
186  return implode('_', array_merge(self::TABLE_ACTION_NAMESPACE, [self::TABLE_ACTION_IDENTIFIER_NAME]));
187  }
188 
193  private function getRequestValue(
194  string $key,
195  \ILIAS\Refinery\Transformation $trafo,
196  bool $force_retrieval = false,
197  $default = null
198  ) {
199  $exc = null;
200 
201  try {
202  if ($force_retrieval || $this->http_wrapper->query()->has($key)) {
203  return $this->http_wrapper->query()->retrieve($key, $trafo);
204  }
205  } catch (OutOfBoundsException $e) {
206  $exc = $e;
207  }
208 
209  try {
210  if ($force_retrieval || $this->http_wrapper->post()->has($key)) {
211  return $this->http_wrapper->post()->retrieve($key, $trafo);
212  }
213  } catch (OutOfBoundsException $e) {
214  $exc = $e;
215  }
216 
217  if ($force_retrieval && $exc) {
218  throw $exc;
219  }
220 
221  return $default ?? null;
222  }
223 
224  public function executeCommand(): void
225  {
226  if (!$this->rbac->system()->checkAccess('visible,read', SYSTEM_FOLDER_ID)) {
227  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
228  }
229 
230  $class = $this->ctrl->getNextClass($this) ?? '';
231 
232  switch (strtolower($class)) {
233  case strtolower(ilPropertyFormGUI::class):
234  $job_id = $this->getRequestValue($this->getJobIdParameterName(), $this->refinery->kindlyTo()->string());
235  $job = $this->cron_repository->getJobInstanceById(ilUtil::stripSlashes($job_id));
236  $form = $this->initLegacyEditForm($job);
237  $this->ctrl->forwardCommand($form);
238  break;
239  }
240 
241  $cmd = $this->ctrl->getCmd('render');
242  $this->$cmd();
243  }
244 
245  private function handleTableActions(): void
246  {
247  $action = $this->http_wrapper->query()->retrieve(
249  $this->refinery->byTrying([
250  $this->refinery->kindlyTo()->string(),
251  $this->refinery->always('')
252  ])
253  );
254  match ($action) {
255  'run' => $this->run(),
256  'activate' => $this->activate(),
257  'deactivate' => $this->deactivate(),
258  'reset' => $this->reset(),
259  'edit' => $this->edit(),
260  default => $this->render()
261  };
262  }
263 
264  protected function render(): void
265  {
266  $tstamp = $this->lng->txt('cronjob_last_start_unknown');
267  if ($this->settings->get('last_cronjob_start_ts')) {
269  new ilDateTime(
270  $this->settings->get('last_cronjob_start_ts'),
272  )
273  );
274  }
275 
276  $message = $this->ui_factory->messageBox()->info($this->lng->txt('cronjob_last_start') . ': ' . $tstamp);
277 
278  $cronJobs = $this->cron_repository->findAll();
279 
280  $tableFilterMediator = new JobTableFilterMediator(
281  $cronJobs,
282  $this->ui_factory,
283  $this->ui_service,
284  $this->lng
285  );
286  $filter = $tableFilterMediator->filter(
287  $this->ctrl->getFormAction(
288  $this,
289  'render',
290  '',
291  true
292  )
293  );
294 
295  $filtered_jobs = $tableFilterMediator->filteredJobs(
296  $filter
297  );
298 
299  $tbl = new JobTable(
300  $this,
301  'handleTableActions',
302  self::TABLE_ACTION_NAMESPACE,
303  self::TABLE_ACTION_PARAM_NAME,
304  self::TABLE_ACTION_IDENTIFIER_NAME,
305  $this->ui_factory,
306  $this->http->request(),
307  $this->ctrl,
308  $this->lng,
309  $filtered_jobs,
311  $this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)
312  );
313 
314  $this->tpl->setContent(
315  $this->ui_renderer->render(
316  $this->addProblematicItemsInfo(
317  $filtered_jobs,
318  $message,
319  [$message, $filter, $tbl->getComponent()]
320  )
321  )
322  );
323  }
324 
325  public function edit(?ILIAS\UI\Component\Input\Container\Form\Form $form = null): void
326  {
327  if (!$this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)) {
328  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
329  }
330 
331  if ($form === null) {
332  $job_ids = $this->retrieveTableActionJobIds();
333  if (count($job_ids) !== 1) {
334  $this->ctrl->redirect($this, 'render');
335  }
336 
337  $job_id = current($job_ids);
338  $job = $this->cron_repository->getJobInstanceById($job_id);
339  if ($job && $job->usesLegacyForms()) {
340  $this->ctrl->setParameter($this, $this->getJobIdParameterName(), $job->getId());
341  $this->ctrl->redirect($this, 'editLegacy');
342  }
343 
344  $form = $this->initEditForm($job);
345  }
346 
347  $this->tpl->setContent($this->ui_renderer->render($form));
348  }
349 
350  public function editLegacy(?ilPropertyFormGUI $a_form = null): void
351  {
352  if (!$this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)) {
353  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
354  }
355 
356  if ($a_form === null) {
357  $job_ids = $this->retrieveTableActionJobIds();
358  if (count($job_ids) !== 1) {
359  $this->ctrl->redirect($this, 'render');
360  }
361 
362  $job_id = current($job_ids);
363  $job = $this->cron_repository->getJobInstanceById($job_id);
364  $a_form = $this->initLegacyEditForm($job);
365  }
366 
367  $this->tpl->setContent($a_form->getHTML());
368  }
369 
370  private function getScheduleTypeFormElementName(JobScheduleType $schedule_type): string
371  {
372  return match ($schedule_type) {
373  JobScheduleType::DAILY => $this->lng->txt('cron_schedule_daily'),
374  JobScheduleType::WEEKLY => $this->lng->txt('cron_schedule_weekly'),
375  JobScheduleType::MONTHLY => $this->lng->txt('cron_schedule_monthly'),
376  JobScheduleType::QUARTERLY => $this->lng->txt('cron_schedule_quarterly'),
377  JobScheduleType::YEARLY => $this->lng->txt('cron_schedule_yearly'),
378  JobScheduleType::IN_MINUTES => sprintf($this->lng->txt('cron_schedule_in_minutes'), 'x'),
379  JobScheduleType::IN_HOURS => sprintf($this->lng->txt('cron_schedule_in_hours'), 'x'),
380  JobScheduleType::IN_DAYS => sprintf($this->lng->txt('cron_schedule_in_days'), 'x'),
381  };
382  }
383 
384  protected function getScheduleValueFormElementName(JobScheduleType $schedule_type): string
385  {
386  return match ($schedule_type) {
387  JobScheduleType::IN_MINUTES => 'smini',
388  JobScheduleType::IN_HOURS => 'shri',
389  JobScheduleType::IN_DAYS => 'sdyi',
390  default => throw new InvalidArgumentException(
391  sprintf(
392  'The passed argument %s is invalid!',
393  var_export($schedule_type, true)
394  )
395  ),
396  };
397  }
398 
399  protected function hasScheduleValue(JobScheduleType $schedule_type): bool
400  {
401  return in_array($schedule_type, [
402  JobScheduleType::IN_MINUTES,
403  JobScheduleType::IN_HOURS,
404  JobScheduleType::IN_DAYS
405  ], true);
406  }
407 
408  protected function initEditForm(?CronJob $job): ILIAS\UI\Component\Input\Container\Form\Form
409  {
410  if (!($job instanceof CronJob)) {
411  $this->ctrl->redirect($this, 'render');
412  }
413 
414  $this->ctrl->setParameter($this, $this->getJobIdParameterName(), $job->getId());
415 
416  $jobs_data = $this->cron_repository->getCronJobData($job->getId());
417  $job_data = $jobs_data[0];
418 
419  $section_inputs = [];
420  if ($job->hasFlexibleSchedule()) {
421  $schedule_type_groups = [];
422  foreach ($job->getAllScheduleTypes() as $schedule_type) {
423  if (!in_array($schedule_type, $job->getValidScheduleTypes(), true)) {
424  continue;
425  }
426 
427  $schedule_type_inputs = [];
428  if (in_array($schedule_type, $job->getScheduleTypesWithValues(), true)) {
429  $schedule_value_input = $this->ui_factory
430  ->input()
431  ->field()
432  ->numeric(
433  $this->lng->txt('cron_schedule_value')
435  $this->refinery->in()->series([
436  $this->refinery->int()->isGreaterThanOrEqual(1)
437  ])
438  )->withRequired(true);
439 
440  if (is_numeric($job_data['schedule_type']) &&
441  JobScheduleType::tryFrom((int) $job_data['schedule_type']) === $schedule_type) {
442  $schedule_value_input = $schedule_value_input->withValue(
443  $job_data['schedule_value'] === null ? null : (int) $job_data['schedule_value']
444  );
445  }
446 
447  $schedule_type_inputs = [
448  $this->getScheduleValueFormElementName($schedule_type) => $schedule_value_input
449  ];
450  }
451 
452  $schedule_type_groups[self::FORM_PARAM_SCHEDULE_PREFIX . $schedule_type->value] = $this->ui_factory
453  ->input()
454  ->field()
455  ->group(
456  $schedule_type_inputs,
457  $this->getScheduleTypeFormElementName($schedule_type)
458  )
459  ->withDedicatedName(self::FORM_PARAM_SCHEDULE_PREFIX . $schedule_type->value);
460  }
461 
462  $default_schedule_type = current($job->getValidScheduleTypes())->value;
463 
464  $section_inputs['schedule'] = $this->ui_factory
465  ->input()
466  ->field()
467  ->switchableGroup(
468  $schedule_type_groups,
469  $this->lng->txt('cron_schedule_type')
470  )
471  ->withRequired(true)
472  ->withValue(
473  $job_data['schedule_type'] === null ?
474  self::FORM_PARAM_SCHEDULE_PREFIX . $default_schedule_type :
475  self::FORM_PARAM_SCHEDULE_PREFIX . $job_data['schedule_type']
476  );
477  }
478 
479  $main_section = $this->ui_factory->input()->field()->section(
480  $section_inputs,
481  $this->lng->txt('cron_action_edit') . ': "' . $job->getTitle() . '"'
482  );
483 
484  $inputs = [
485  self::FORM_PARAM_MAIN_SECTION => $main_section
486  ];
487 
488  if ($job->hasCustomSettings()) {
489  $inputs = array_merge(
490  $inputs,
491  [
492  self::FORM_PARAM_JOB_INPUT =>
494  $this->ui_factory,
495  $this->refinery,
496  $this->lng
497  )
498  ]
499  );
500  }
501 
502  return $this->ui_factory
503  ->input()
504  ->container()
505  ->form()
506  ->standard($this->ctrl->getFormAction($this, 'update'), $inputs)
507  ->withDedicatedName('cron_form');
508  }
509 
513  #[\Deprecated('Will be removed without any alternative, KS/UI forms will be expected', since: '13.0')]
514  protected function initLegacyEditForm(?CronJob $job): ilPropertyFormGUI
515  {
516  if (!($job instanceof CronJob)) {
517  $this->ctrl->redirect($this, 'render');
518  }
519 
520  $this->ctrl->setParameter($this, $this->getJobIdParameterName(), $job->getId());
521 
522  $jobs_data = $this->cron_repository->getCronJobData($job->getId());
523  $job_data = $jobs_data[0];
524 
525  $form = new ilPropertyFormGUI();
526  $form->setFormAction($this->ctrl->getFormAction($this, 'updateLegacy'));
527  $form->setTitle($this->lng->txt('cron_action_edit') . ': "' . $job->getTitle() . '"');
528 
529  if ($job->hasFlexibleSchedule()) {
530  $type = new ilRadioGroupInputGUI($this->lng->txt('cron_schedule_type'), 'type');
531  $type->setRequired(true);
532  $type->setValue($job_data['schedule_type'] === null ? null : (string) $job_data['schedule_type']);
533 
534  foreach ($job->getAllScheduleTypes() as $schedule_type) {
535  if (!in_array($schedule_type, $job->getValidScheduleTypes(), true)) {
536  continue;
537  }
538 
539  $option = new ilRadioOption(
540  $this->getScheduleTypeFormElementName($schedule_type),
541  (string) $schedule_type->value
542  );
543  $type->addOption($option);
544 
545  if (in_array($schedule_type, $job->getScheduleTypesWithValues(), true)) {
546  $scheduleValue = new ilNumberInputGUI(
547  $this->lng->txt('cron_schedule_value'),
548  $this->getScheduleValueFormElementName($schedule_type)
549  );
550  $scheduleValue->allowDecimals(false);
551  $scheduleValue->setRequired(true);
552  $scheduleValue->setSize(5);
553  if (is_numeric($job_data['schedule_type']) &&
554  JobScheduleType::tryFrom((int) $job_data['schedule_type']) === $schedule_type) {
555  $scheduleValue->setValue(
556  $job_data['schedule_value'] === null ? null : (string) $job_data['schedule_value']
557  );
558  }
559  $option->addSubItem($scheduleValue);
560  }
561  }
562 
563  $form->addItem($type);
564  }
565 
566  if ($job->hasCustomSettings()) {
567  $job->addCustomSettingsToForm($form);
568  }
569 
570  $form->addCommandButton('updateLegacy', $this->lng->txt('save'));
571  $form->addCommandButton('render', $this->lng->txt('cancel'));
572 
573  return $form;
574  }
575 
576  public function update(): void
577  {
578  if (!$this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)) {
579  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
580  }
581 
582  $job_id = $this->getRequestValue($this->getJobIdParameterName(), $this->refinery->kindlyTo()->string());
583  if (!$job_id) {
584  $this->ctrl->redirect($this, 'render');
585  }
586 
587  $job = $this->cron_repository->getJobInstanceById($job_id);
588  $form = $this->initEditForm($job);
589 
590  $form_valid = false;
591  $form_data = null;
592  if ($this->http->request()->getMethod() === 'POST') {
593  $form = $form->withRequest($this->http->request());
594  $form_data = $form->getData();
595  $form_valid = $form_data !== null;
596  }
597 
598  if (!$form_valid) {
599  $this->edit($form);
600  return;
601  }
602 
603  if ($job instanceof CronJob) {
604  if ($job->hasFlexibleSchedule()) {
605  $schedule_group = $form_data[self::FORM_PARAM_MAIN_SECTION][self::FORM_PARAM_GROUP_SCHEDULE];
606 
607  $type = JobScheduleType::from(
608  (int) ltrim($schedule_group[0], self::FORM_PARAM_SCHEDULE_PREFIX)
609  );
610 
611  $value = match (true) {
612  $this->hasScheduleValue($type) => (int) $schedule_group[1][$this->getScheduleValueFormElementName(
613  $type
614  )],
615  default => null,
616  };
617 
618  $this->cron_repository->updateJobSchedule($job, $type, $value);
619  }
620 
621  if ($job->hasCustomSettings()) {
622  $job->saveCustomConfiguration($form_data[self::FORM_PARAM_JOB_INPUT]);
623  }
624 
625  $this->tpl->setOnScreenMessage('success', $this->lng->txt('cron_action_edit_success'), true);
626  $this->ctrl->redirect($this, 'render');
627  }
628 
629  $this->edit($form);
630  }
631 
635  #[\Deprecated('Will be removed without any alternative, KS/UI forms will be expected', since: '12.0')]
636  public function updateLegacy(): void
637  {
638  if (!$this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)) {
639  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
640  }
641 
642  $job_id = $this->getRequestValue($this->getJobIdParameterName(), $this->refinery->kindlyTo()->string());
643  if (!$job_id) {
644  $this->ctrl->redirect($this, 'render');
645  }
646 
647  $job = $this->cron_repository->getJobInstanceById($job_id);
648 
649  $form = $this->initLegacyEditForm($job);
650  if ($job instanceof CronJob && $form->checkInput()) {
651  $valid = true;
652  if ($job->hasCustomSettings() && !$job->saveCustomSettings($form)) {
653  $valid = false;
654  }
655 
656  if ($valid && $job->hasFlexibleSchedule()) {
657  $type = JobScheduleType::from((int) $form->getInput('type'));
658  $value = match (true) {
659  $this->hasScheduleValue($type) => (int) $form->getInput(
660  $this->getScheduleValueFormElementName($type)
661  ),
662  default => null,
663  };
664 
665  $this->cron_repository->updateJobSchedule($job, $type, $value);
666  }
667 
668  if ($valid) {
669  $this->tpl->setOnScreenMessage('success', $this->lng->txt('cron_action_edit_success'), true);
670  $this->ctrl->redirect($this, 'render');
671  }
672  }
673 
674  $form->setValuesByPost();
675  $this->editLegacy($form);
676  }
677 
678  public function run(): void
679  {
680  $this->confirm('run');
681  }
682 
683  public function confirmedRun(): void
684  {
685  if (!$this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)) {
686  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
687  }
688 
689  $job_ids = $this->retrieveTableActionJobIds();
690  if (count($job_ids) !== 1) {
691  $this->ctrl->redirect($this, 'render');
692  }
693 
694  $job_id = current($job_ids);
695  if ($this->cron_manager->runJobManual($job_id, $this->actor)) {
696  $this->tpl->setOnScreenMessage('success', $this->lng->txt('cron_action_run_success'), true);
697  } else {
698  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('cron_action_run_fail'), true);
699  }
700 
701  $this->ctrl->redirect($this, 'render');
702  }
703 
704  public function activate(): void
705  {
706  $this->confirm('activate');
707  }
708 
709  public function confirmedActivate(): void
710  {
711  if (!$this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)) {
712  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
713  }
714 
715  $jobs = $this->getMultiActionData();
716  if ($jobs !== []) {
717  foreach ($jobs as $job) {
718  if ($this->cron_manager->isJobInactive($job->getId())) {
719  $this->cron_manager->resetJob($job, $this->actor);
720  }
721  }
722 
723  $this->tpl->setOnScreenMessage('success', $this->lng->txt('cron_action_activate_success'), true);
724  } else {
725  $this->tpl->setOnScreenMessage('info', $this->lng->txt('no_checkbox'), true);
726  }
727 
728  $this->ctrl->redirect($this, 'render');
729  }
730 
731  public function deactivate(): void
732  {
733  $this->confirm('deactivate');
734  }
735 
736  public function confirmedDeactivate(): void
737  {
738  if (!$this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)) {
739  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
740  }
741 
742  $jobs = $this->getMultiActionData();
743  if ($jobs !== []) {
744  foreach ($jobs as $job) {
745  if ($this->cron_manager->isJobActive($job->getId())) {
746  $this->cron_manager->deactivateJob($job, $this->actor, true);
747  }
748  }
749 
750  $this->tpl->setOnScreenMessage('success', $this->lng->txt('cron_action_deactivate_success'), true);
751  } else {
752  $this->tpl->setOnScreenMessage('info', $this->lng->txt('no_checkbox'), true);
753  }
754 
755  $this->ctrl->redirect($this, 'render');
756  }
757 
758  public function reset(): void
759  {
760  $this->confirm('reset');
761  }
762 
763  public function confirmedReset(): void
764  {
765  if (!$this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)) {
766  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
767  }
768 
769  $jobs = $this->getMultiActionData();
770  if ($jobs !== []) {
771  foreach ($jobs as $job) {
772  $this->cron_manager->resetJob($job, $this->actor);
773  }
774  $this->tpl->setOnScreenMessage('success', $this->lng->txt('cron_action_reset_success'), true);
775  } else {
776  $this->tpl->setOnScreenMessage('info', $this->lng->txt('no_checkbox'), true);
777  }
778 
779  $this->ctrl->redirect($this, 'render');
780  }
781 
785  protected function getMultiActionData(): array
786  {
787  $res = [];
788 
789  $job_ids = [];
790  try {
791  $job_ids = $this->retrieveTableActionJobIds();
792  } catch (\ILIAS\Refinery\ConstraintViolationException|OutOfBoundsException) {
793  }
794 
795  foreach ($job_ids as $job_id) {
796  $job = $this->cron_repository->getJobInstanceById($job_id);
797  if ($job instanceof CronJob) {
798  $res[$job_id] = $job;
799  }
800  }
801 
802  return $res;
803  }
804 
805  protected function confirm(string $a_action): void
806  {
807  if (!$this->rbac->system()->checkAccess('write', SYSTEM_FOLDER_ID)) {
808  $this->error->raiseError($this->lng->txt('no_permission'), $this->error->WARNING);
809  }
810 
811  $jobs = $this->getMultiActionData();
812  if ($jobs === []) {
813  $this->tpl->setOnScreenMessage('info', $this->lng->txt('no_checkbox'), true);
814  $this->ctrl->redirect($this, 'render');
815  }
816 
817  if ($a_action === 'run') {
818  $jobs = array_filter($jobs, static function (CronJob $job): bool {
819  return $job->isManuallyExecutable();
820  });
821 
822  if ($jobs === []) {
823  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('cron_no_executable_job_selected'), true);
824  $this->ctrl->redirect($this, 'render');
825  }
826  }
827 
828  $cgui = new ilConfirmationGUI();
829 
830  if (count($jobs) === 1) {
831  $jobKeys = array_keys($jobs);
832  $job_id = array_pop($jobKeys);
833  $job = array_pop($jobs);
834  $title = $job->getTitle();
835  if (!$title) {
836  $title = preg_replace('[^A-Za-z0-9_\-]', '', $job->getId());
837  }
838 
839  $cgui->setHeaderText(
840  sprintf(
841  $this->lng->txt('cron_action_' . $a_action . '_sure'),
842  $title
843  )
844  );
845 
846  $cgui->addHiddenItem($this->getJobIdParameterName() . '[]', $job_id);
847  } else {
848  $cgui->setHeaderText($this->lng->txt('cron_action_' . $a_action . '_sure_multi'));
849 
850  foreach ($jobs as $job_id => $job) {
851  $cgui->addItem($this->getJobIdParameterName() . '[]', $job_id, $job->getTitle());
852  }
853  }
854 
855  $cgui->setFormAction($this->ctrl->getFormAction($this, 'confirmed' . ucfirst($a_action)));
856  $cgui->setCancel($this->lng->txt('cancel'), 'render');
857  $cgui->setConfirm($this->lng->txt('cron_action_' . $a_action), 'confirmed' . ucfirst($a_action));
858 
859  $this->tpl->setContent($cgui->getHTML());
860  }
861 
865  public function addToExternalSettingsForm(int $a_form_id): array
866  {
867  $form_elements = [];
868  $fields = [];
869  $data = $this->cron_repository->getCronJobData();
870  foreach ($data as $item) {
871  $job = $this->cron_repository->getJobInstance(
872  $item['job_id'],
873  $item['component'],
874  $item['class']
875  );
876  if ($job !== null) {
877  $job->addToExternalSettingsForm($a_form_id, $fields, (bool) $item['job_status']);
878  }
879  }
880 
881  if ($fields !== []) {
882  $form_elements = [
883  'cron_jobs' => [
884  'jumpToCronJobs',
885  $fields
886  ]
887  ];
888  }
889 
890  return $form_elements;
891  }
892 }
hasScheduleValue(JobScheduleType $schedule_type)
This class represents an option in a radio group.
$res
Definition: ltiservices.php:66
const array TABLE_ACTION_NAMESPACE
readonly ilCtrlInterface $ctrl
getScheduleTypeFormElementName(JobScheduleType $schedule_type)
readonly ILIAS Refinery Factory $refinery
getRequestValue(string $key, \ILIAS\Refinery\Transformation $trafo, bool $force_retrieval=false, $default=null)
Interface Observer Contains several chained tasks and infos about them.
readonly Renderer $ui_renderer
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
$valid
readonly JobManager $cron_manager
const string TABLE_ACTION_IDENTIFIER_NAME
const IL_CAL_UNIX
readonly ilGlobalTemplateInterface $tpl
readonly ilSetting $settings
readonly ilErrorHandling $error
const SYSTEM_FOLDER_ID
Definition: constants.php:35
readonly ilUIService $ui_service
const string FORM_PARAM_SCHEDULE_PREFIX
confirm(string $a_action)
$components
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
allowDecimals(bool $a_value)
readonly WrapperFactory $http_wrapper
getCustomConfigurationInput(\ILIAS\UI\Factory $ui_factory, \ILIAS\Refinery\Factory $factory, \ilLanguage $lng)
Definition: CronJob.php:241
editLegacy(?ilPropertyFormGUI $a_form=null)
addCustomSettingsToForm(\ilPropertyFormGUI $a_form)
Definition: CronJob.php:253
static http()
Fetches the global http state from ILIAS.
This class represents a property in a property form.
readonly ilObjUser $actor
readonly Factory $ui_factory
getScheduleValueFormElementName(JobScheduleType $schedule_type)
This is how the factory for UI elements looks.
Definition: Factory.php:37
This class represents a number property in a property form.
readonly ILIAS DI RBACServices $rbac
readonly ILIAS HTTP GlobalHttpState $http
global $DIC
Definition: shib_login.php:26
setRequired(bool $a_required)
getValidScheduleTypes()
Returns a collection of all valid schedule types for a specific job.
Definition: CronJob.php:217
addToExternalSettingsForm(int $a_form_id)
readonly JobRepository $cron_repository
edit(?ILIAS\UI\Component\Input\Container\Form\Form $form=null)
__construct(Container $dic, ilPlugin $plugin)
getScheduleTypesWithValues()
Definition: CronJob.php:204
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false, ?ilObjUser $user=null,)
ilCronManagerGUI: ilPropertyFormGUI ilCronManagerGUI: ilAdministrationGUI
$message
Definition: xapiexit.php:31
const string TABLE_ACTION_PARAM_NAME
getAllScheduleTypes()
Get all available schedule types.
Definition: CronJob.php:196
addProblematicItemsInfo(\ILIAS\Cron\Job\JobCollection $filtered_jobs, \ILIAS\UI\Component\MessageBox\MessageBox $message, array $components)
initLegacyEditForm(?CronJob $job)
readonly ilLanguage $lng