19declare(strict_types=1);
44 public const string VIEW =
'view';
51 private readonly \ILIAS\DI\RBACServices
$rbac;
61 $this->ui_service =
$DIC->uiService();
62 $this->
rbac = $DIC->rbac();
63 $this->http_wrapper =
$DIC->http()->wrapper();
64 $this->cron_repository =
$DIC->cron()->repository();
65 $this->cron_manager =
$DIC->cron()->manager();
66 $this->data_factory =
new DataFactory();
68 $this->
lng->loadLanguageModule(
'cron');
69 $this->
lng->loadLanguageModule(
'cmps');
72 public static function create(): self
76 )[
'id'])),
true,
false);
84 $retrieval = $this->http_wrapper->query();
85 if (strtoupper($this->
http->request()->getMethod()) ===
'POST') {
86 $retrieval = $this->http_wrapper->post();
90 $this->
refinery->kindlyTo()->listOf($this->refinery->kindlyTo()->string()),
91 $this->refinery->always([])
94 $ids = $retrieval->retrieve(
99 if (count($ids) === 1 && $ids[0] ===
'ALL_OBJECTS') {
101 $this->cron_repository->findAll(),
106 $filter = $tableFilterMediator->filter(
107 $this->
ctrl->getFormAction(
116 $tableFilterMediator->filteredJobs(
127 return implode(
'_', array_merge(self::TABLE_ACTION_NAMESPACE, [self::TABLE_ACTION_PARAM_NAME]));
135 \
ILIAS\Cron\Job\JobCollection $filtered_jobs,
139 $problematic_jobs = $filtered_jobs->
filter(static function (
JobEntity $entity): bool {
142 if (count($problematic_jobs) > 0) {
143 $problematic_jobs_info = $this->ui_factory->messageBox()->info(
144 $this->
lng->txt(
'cron_jobs_with_required_intervention')
148 return $this->ui_factory->link()->
standard(
155 OrderedJobEntities::ORDER_BY_NAME
163 [$problematic_jobs_info],
167 array_unshift(
$components, $problematic_jobs_info);
176 return implode(
'_', array_merge(self::TABLE_ACTION_NAMESPACE, [self::TABLE_ACTION_IDENTIFIER_NAME]));
185 \
ILIAS\Refinery\Transformation $trafo,
186 bool $force_retrieval =
false,
192 if ($force_retrieval || $this->http_wrapper->query()->has($key)) {
193 return $this->http_wrapper->query()->retrieve($key, $trafo);
195 }
catch (OutOfBoundsException
$e) {
200 if ($force_retrieval || $this->http_wrapper->post()->has($key)) {
201 return $this->http_wrapper->post()->retrieve($key, $trafo);
203 }
catch (OutOfBoundsException
$e) {
207 if ($force_retrieval && $exc) {
211 return $default ??
null;
216 if (!$this->
rbac->system()->checkAccess(
'read', $this->ref_id)) {
217 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
220 $this->prepareOutput();
222 $class = $this->
ctrl->getNextClass($this) ??
'';
224 switch (strtolower($class)) {
225 case strtolower(ilPropertyFormGUI::class):
226 $this->tabs_gui->activateTab(self::VIEW);
227 $entity = $this->cron_repository->getEntityById(
229 $this->getRequestValue($this->getJobIdParameterName(), $this->
refinery->kindlyTo()->string())
232 if ($entity ===
null) {
233 $this->
ctrl->redirect($this, self::VIEW);
236 $form = $this->initLegacyEditForm($entity);
237 $this->
ctrl->forwardCommand($form);
240 case strtolower(ilPermissionGUI::class):
245 $this->tabs_gui->activateTab(self::VIEW);
246 $cmd = $this->
ctrl->getCmd(self::VIEW);
252 $action = $this->http_wrapper->query()->retrieve(
253 $this->getTableActionParameterName(),
255 $this->refinery->kindlyTo()->string(),
256 $this->refinery->always(
'')
260 'run' => $this->run(),
261 'activate' => $this->activate(),
262 'deactivate' => $this->deactivate(),
263 'reset' => $this->reset(),
264 'edit' => $this->edit(),
265 default => $this->view()
269 protected function view(): void
271 $tstamp = $this->
lng->txt(
'cronjob_last_start_unknown');
272 if ($this->
settings->get(
'last_cronjob_start_ts')) {
275 $this->
settings->get(
'last_cronjob_start_ts'),
281 $message = $this->ui_factory->messageBox()->info($this->
lng->txt(
'cronjob_last_start') .
': ' . $tstamp);
283 $cronJobs = $this->cron_repository->findAll();
291 $filter = $tableFilterMediator->filter(
292 $this->
ctrl->getFormAction(
300 $filtered_jobs = $tableFilterMediator->filteredJobs(
305 $this->data_factory->uri(
ilUtil::_getHttpPath() .
'/' . $this->ctrl->getLinkTarget($this,
'handleTableActions')),
306 self::TABLE_ACTION_NAMESPACE,
307 self::TABLE_ACTION_PARAM_NAME,
308 self::TABLE_ACTION_IDENTIFIER_NAME,
310 $this->http->request(),
313 $this->cron_repository,
314 $this->rbac->system()->checkAccess(
'write', $this->ref_id)
317 $this->tpl->setContent(
318 $this->ui_renderer->render(
319 $this->addProblematicItemsInfo(
322 [$message, $filter, $tbl->getComponent()]
330 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
331 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
334 if ($form ===
null) {
335 $job_ids = $this->retrieveTableActionJobIds();
336 if (count($job_ids) !== 1) {
337 $this->
ctrl->redirect($this, self::VIEW);
340 $job_id = current($job_ids);
341 $entity = $this->cron_repository->getEntityById($job_id);
342 if ($entity ===
null) {
343 $this->
ctrl->redirect($this, self::VIEW);
346 if ($entity->
getJob()->usesLegacyForms()) {
348 $this->
ctrl->redirect($this,
'editLegacy');
351 $form = $this->buildForm($entity);
354 $this->tpl->setContent($this->ui_renderer->render($form));
359 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
360 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
363 if ($a_form ===
null) {
364 $job_ids = $this->retrieveTableActionJobIds();
365 if (count($job_ids) !== 1) {
366 $this->
ctrl->redirect($this, self::VIEW);
369 $job_id = current($job_ids);
370 $entity = $this->cron_repository->getEntityById($job_id);
371 if ($entity ===
null) {
372 $this->
ctrl->redirect($this, self::VIEW);
375 $a_form = $this->initLegacyEditForm($entity);
378 $this->tpl->setContent($a_form->getHTML());
383 return match ($schedule_type) {
384 JobScheduleType::DAILY => $this->
lng->txt(
'cron_schedule_daily'),
385 JobScheduleType::WEEKLY => $this->
lng->txt(
'cron_schedule_weekly'),
386 JobScheduleType::MONTHLY => $this->
lng->txt(
'cron_schedule_monthly'),
387 JobScheduleType::QUARTERLY => $this->
lng->txt(
'cron_schedule_quarterly'),
389 JobScheduleType::IN_MINUTES => sprintf($this->
lng->txt(
'cron_schedule_in_minutes'),
'x'),
390 JobScheduleType::IN_HOURS => sprintf($this->
lng->txt(
'cron_schedule_in_hours'),
'x'),
391 JobScheduleType::IN_DAYS => sprintf($this->
lng->txt(
'cron_schedule_in_days'),
'x'),
397 return match ($schedule_type) {
398 JobScheduleType::IN_MINUTES =>
'smini',
399 JobScheduleType::IN_HOURS =>
'shri',
400 JobScheduleType::IN_DAYS =>
'sdyi',
401 default =>
throw new InvalidArgumentException(
403 'The passed argument %s is invalid!',
404 var_export($schedule_type,
true)
412 return in_array($schedule_type, [
413 JobScheduleType::IN_MINUTES,
414 JobScheduleType::IN_HOURS,
415 JobScheduleType::IN_DAYS
425 $section_inputs = [];
426 if ($job->hasFlexibleSchedule()) {
427 $schedule_type_groups = [];
428 foreach ($job->getAllScheduleTypes() as $schedule_type) {
429 if (!in_array($schedule_type, $job->getValidScheduleTypes(),
true)) {
433 $schedule_type_inputs = [];
434 if (in_array($schedule_type, $job->getScheduleTypesWithValues(),
true)) {
435 $schedule_value_input = $this->ui_factory
439 $this->
lng->txt(
'cron_schedule_value')
440 )->withAdditionalTransformation(
442 $this->refinery->int()->isGreaterThanOrEqual(1)
444 )->withRequired(
true);
448 $schedule_value_input = $schedule_value_input->withValue(
453 $schedule_type_inputs = [
454 $this->getScheduleValueFormElementName($schedule_type) => $schedule_value_input
458 $schedule_type_groups[self::FORM_PARAM_SCHEDULE_PREFIX . $schedule_type->value] = $this->ui_factory
462 $schedule_type_inputs,
463 $this->getScheduleTypeFormElementName($schedule_type)
465 ->withDedicatedName(self::FORM_PARAM_SCHEDULE_PREFIX . $schedule_type->value);
468 $default_schedule_type = current($job->getValidScheduleTypes())->value;
470 $section_inputs[
'schedule'] = $this->ui_factory
474 $schedule_type_groups,
475 $this->
lng->txt(
'cron_schedule_type')
480 self::FORM_PARAM_SCHEDULE_PREFIX . $default_schedule_type :
485 $main_section = $this->ui_factory->input()->field()->section(
487 $this->
lng->txt(
'cron_action_edit') .
': "' . $job->getTitle() .
'"'
491 self::FORM_PARAM_MAIN_SECTION => $main_section
494 if ($job->hasCustomSettings()) {
498 self::FORM_PARAM_JOB_INPUT =>
499 $job->getCustomConfigurationInput(
508 return $this->ui_factory
512 ->standard($this->
ctrl->getFormAction($this,
'update'),
$inputs)
513 ->withDedicatedName(
'cron_form');
519 #[\Deprecated('Will be removed without any alternative, KS/UI forms will be expected', since: '11.0')]
527 $form->setFormAction($this->
ctrl->getFormAction($this,
'updateLegacy'));
528 $form->setTitle($this->
lng->txt(
'cron_action_edit') .
': "' . $job->getTitle() .
'"');
530 if ($job->hasFlexibleSchedule()) {
532 $type->setRequired(
true);
537 foreach ($job->getAllScheduleTypes() as $schedule_type) {
538 if (!in_array($schedule_type, $job->getValidScheduleTypes(),
true)) {
543 $this->getScheduleTypeFormElementName($schedule_type),
544 (
string) $schedule_type->value
546 $type->addOption($option);
548 if (in_array($schedule_type, $job->getScheduleTypesWithValues(),
true)) {
550 $this->
lng->txt(
'cron_schedule_value'),
551 $this->getScheduleValueFormElementName($schedule_type)
553 $scheduleValue->allowDecimals(
false);
554 $scheduleValue->setRequired(
true);
555 $scheduleValue->setSize(5);
558 $scheduleValue->setValue(
562 $option->addSubItem($scheduleValue);
566 $form->addItem($type);
569 if ($job->hasCustomSettings()) {
570 $job->addCustomSettingsToForm($form);
573 $form->addCommandButton(
'updateLegacy', $this->
lng->txt(
'save'));
574 $form->addCommandButton(self::VIEW, $this->
lng->txt(
'cancel'));
581 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
582 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
585 $job_id = $this->getRequestValue($this->getJobIdParameterName(), $this->
refinery->kindlyTo()->string());
587 $this->
ctrl->redirect($this, self::VIEW);
590 $entity = $this->cron_repository->getEntityById($job_id);
591 if ($entity ===
null) {
592 $this->
ctrl->redirect($this, self::VIEW);
595 $form = $this->buildForm($entity);
599 if ($this->
http->request()->getMethod() ===
'POST') {
600 $form = $form->withRequest($this->
http->request());
601 $form_data = $form->getData();
602 $form_valid = $form_data !==
null;
611 if ($job->hasFlexibleSchedule()) {
612 $schedule_group = $form_data[self::FORM_PARAM_MAIN_SECTION][self::FORM_PARAM_GROUP_SCHEDULE];
615 (
int) ltrim($schedule_group[0], self::FORM_PARAM_SCHEDULE_PREFIX)
618 $value = match (
true) {
619 $this->hasScheduleValue($type) => (
int) $schedule_group[1][$this->getScheduleValueFormElementName(
625 $this->cron_repository->updateJobSchedule($job, $type, $value);
628 if ($job->hasCustomSettings()) {
629 $job->saveCustomConfiguration($form_data[self::FORM_PARAM_JOB_INPUT]);
632 $this->tpl->setOnScreenMessage(
'success', $this->
lng->txt(
'cron_action_edit_success'),
true);
633 $this->
ctrl->redirect($this, self::VIEW);
639 #[\Deprecated('Will be removed without any alternative, KS/UI forms will be expected', since: '11.0')]
642 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
643 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
646 $job_id = $this->getRequestValue($this->getJobIdParameterName(), $this->
refinery->kindlyTo()->string());
648 $this->
ctrl->redirect($this, self::VIEW);
651 $entity = $this->cron_repository->getEntityById($job_id);
652 if ($entity ===
null) {
653 $this->
ctrl->redirect($this, self::VIEW);
656 $form = $this->initLegacyEditForm($entity);
658 if ($form->checkInput()) {
660 if ($job->hasCustomSettings() && !$job->saveCustomSettings($form)) {
664 if (
$valid && $job->hasFlexibleSchedule()) {
666 $value = match (
true) {
667 $this->hasScheduleValue($type) => (
int) $form->getInput(
668 $this->getScheduleValueFormElementName($type)
673 $this->cron_repository->updateJobSchedule($job, $type, $value);
677 $this->tpl->setOnScreenMessage(
'success', $this->
lng->txt(
'cron_action_edit_success'),
true);
678 $this->
ctrl->redirect($this, self::VIEW);
682 $form->setValuesByPost();
683 $this->editLegacy($form);
686 public function run(): void
688 $this->confirm(
'run');
693 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
694 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
697 $job_ids = $this->retrieveTableActionJobIds();
698 if (count($job_ids) !== 1) {
699 $this->
ctrl->redirect($this, self::VIEW);
702 $job_id = current($job_ids);
703 if ($this->cron_manager->runJobManual($job_id, $this->user)) {
704 $this->tpl->setOnScreenMessage(
'success', $this->
lng->txt(
'cron_action_run_success'),
true);
706 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
'cron_action_run_fail'),
true);
709 $this->
ctrl->redirect($this, self::VIEW);
714 $this->confirm(
'activate');
719 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
720 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
723 $jobs = $this->getMultiActionData();
725 foreach ($jobs as $job) {
726 if ($this->cron_manager->isJobInactive($job->getId())) {
727 $this->cron_manager->resetJob($job, $this->
user);
731 $this->tpl->setOnScreenMessage(
'success', $this->
lng->txt(
'cron_action_activate_success'),
true);
733 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'no_checkbox'),
true);
736 $this->
ctrl->redirect($this, self::VIEW);
741 $this->confirm(
'deactivate');
746 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
747 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
750 $jobs = $this->getMultiActionData();
752 foreach ($jobs as $job) {
753 if ($this->cron_manager->isJobActive($job->getId())) {
754 $this->cron_manager->deactivateJob($job, $this->
user,
true);
758 $this->tpl->setOnScreenMessage(
'success', $this->
lng->txt(
'cron_action_deactivate_success'),
true);
760 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'no_checkbox'),
true);
763 $this->
ctrl->redirect($this, self::VIEW);
768 $this->confirm(
'reset');
773 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
774 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
777 $jobs = $this->getMultiActionData();
779 foreach ($jobs as $job) {
780 $this->cron_manager->resetJob($job, $this->
user);
782 $this->tpl->setOnScreenMessage(
'success', $this->
lng->txt(
'cron_action_reset_success'),
true);
784 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'no_checkbox'),
true);
787 $this->
ctrl->redirect($this, self::VIEW);
799 $job_ids = $this->retrieveTableActionJobIds();
800 }
catch (\
ILIAS\Refinery\ConstraintViolationException|OutOfBoundsException) {
803 foreach ($job_ids as $job_id) {
804 $job = $this->cron_repository->getJobInstanceById($job_id);
806 $res[$job_id] = $job;
813 protected function confirm(
string $a_action): void
815 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
816 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
819 $jobs = $this->getMultiActionData();
821 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'no_checkbox'),
true);
822 $this->
ctrl->redirect($this, self::VIEW);
825 if ($a_action ===
'run') {
826 $jobs = array_filter($jobs,
static function (
CronJob $job):
bool {
831 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
'cron_no_executable_job_selected'),
true);
832 $this->
ctrl->redirect($this, self::VIEW);
838 if (count($jobs) === 1) {
839 $jobKeys = array_keys($jobs);
840 $job_id = array_pop($jobKeys);
841 $job = array_pop($jobs);
842 $title = $job->getTitle();
844 $title = preg_replace(
'[^A-Za-z0-9_\-]',
'', $job->getId());
847 $cgui->setHeaderText(
849 $this->
lng->txt(
'cron_action_' . $a_action .
'_sure'),
854 $cgui->addHiddenItem($this->getJobIdParameterName() .
'[]', $job_id);
856 $cgui->setHeaderText($this->
lng->txt(
'cron_action_' . $a_action .
'_sure_multi'));
858 foreach ($jobs as $job_id => $job) {
859 $cgui->addItem($this->getJobIdParameterName() .
'[]', $job_id, $job->getTitle());
863 $cgui->setFormAction($this->
ctrl->getFormAction($this,
'confirmed' . ucfirst($a_action)));
864 $cgui->setCancel($this->
lng->txt(
'cancel'), self::VIEW);
865 $cgui->setConfirm($this->
lng->txt(
'cron_action_' . $a_action),
'confirmed' . ucfirst($a_action));
867 $this->tpl->setContent($cgui->getHTML());
877 $data = $this->cron_repository->getCronJobData();
878 foreach (
$data as $item) {
879 $job = $this->cron_repository->getJobInstance(
885 $job->addToExternalSettingsForm($a_form_id, $fields, (
bool) $item[
'job_status']);
889 if ($fields !== []) {
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false, ?ilObjUser $user=null,)
@classDescription Date and time handling
@ilCtrl_isCalledBy ilObjCronGUI: ilAdministrationGUI @ilCtrl_Calls ilObjCronGUI: ilPropertyFormGUI @i...
hasScheduleValue(JobScheduleType $schedule_type)
confirm(string $a_action)
const FORM_PARAM_JOB_INPUT
editLegacy(?ilPropertyFormGUI $a_form=null)
readonly ilUIService $ui_service
const string TABLE_ACTION_PARAM_NAME
const string TABLE_ACTION_IDENTIFIER_NAME
addToExternalSettingsForm(int $a_form_id)
const string FORM_PARAM_SCHEDULE_PREFIX
const FORM_PARAM_GROUP_SCHEDULE
getRequestValue(string $key, \ILIAS\Refinery\Transformation $trafo, bool $force_retrieval=false, $default=null)
readonly JobManager $cron_manager
retrieveTableActionJobIds()
readonly JobRepository $cron_repository
readonly DataFactory $data_factory
readonly WrapperFactory $http_wrapper
getTableActionParameterName()
addProblematicItemsInfo(\ILIAS\Cron\Job\JobCollection $filtered_jobs, \ILIAS\UI\Component\MessageBox\MessageBox $message, array $components)
const array TABLE_ACTION_NAMESPACE
edit(?ILIAS\UI\Component\Input\Container\Form\Form $form=null)
getScheduleTypeFormElementName(JobScheduleType $schedule_type)
readonly ILIAS DI RBACServices $rbac
getScheduleValueFormElementName(JobScheduleType $schedule_type)
const FORM_PARAM_MAIN_SECTION
initLegacyEditForm(JobEntity $entity)
buildForm(JobEntity $entity)
Class ilObjectGUI Basic methods of all Output classes.
static _getAllReferences(int $id)
get all reference ids for object ID
static _getObjectsDataForType(string $type, bool $omit_trash=false)
get all objects of a certain type
This class represents an option in a radio group.
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
return['delivery_method'=> 'php',]
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static http()
Fetches the global http state from ILIAS.
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
filter(string $filter_id, array $class_path, string $cmd, bool $activated=true, bool $expanded=true)
Interface Observer \BackgroundTasks Contains several chained tasks and infos about them.