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