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 $job_id = $this->getRequestValue($this->getJobIdParameterName(), $this->
refinery->kindlyTo()->string());
229 $form = $this->initLegacyEditForm($job);
230 $this->
ctrl->forwardCommand($form);
233 case strtolower(ilPermissionGUI::class):
238 $this->tabs_gui->activateTab(self::VIEW);
239 $cmd = $this->
ctrl->getCmd(self::VIEW);
245 $action = $this->http_wrapper->query()->retrieve(
246 $this->getTableActionParameterName(),
248 $this->refinery->kindlyTo()->string(),
249 $this->refinery->always(
'')
253 'run' => $this->run(),
254 'activate' => $this->activate(),
255 'deactivate' => $this->deactivate(),
256 'reset' => $this->reset(),
257 'edit' => $this->edit(),
258 default => $this->view()
262 protected function view(): void
264 $tstamp = $this->
lng->txt(
'cronjob_last_start_unknown');
265 if ($this->
settings->get(
'last_cronjob_start_ts')) {
268 $this->
settings->get(
'last_cronjob_start_ts'),
274 $message = $this->ui_factory->messageBox()->info($this->
lng->txt(
'cronjob_last_start') .
': ' . $tstamp);
276 $cronJobs = $this->cron_repository->findAll();
284 $filter = $tableFilterMediator->filter(
285 $this->
ctrl->getFormAction(
293 $filtered_jobs = $tableFilterMediator->filteredJobs(
298 $this->data_factory->uri(
ilUtil::_getHttpPath() .
'/' . $this->ctrl->getLinkTarget($this,
'handleTableActions')),
299 self::TABLE_ACTION_NAMESPACE,
300 self::TABLE_ACTION_PARAM_NAME,
301 self::TABLE_ACTION_IDENTIFIER_NAME,
303 $this->http->request(),
306 $this->cron_repository,
307 $this->rbac->system()->checkAccess(
'write', $this->ref_id)
310 $this->tpl->setContent(
311 $this->ui_renderer->render(
312 $this->addProblematicItemsInfo(
315 [$message, $filter, $tbl->getComponent()]
323 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
324 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
327 if ($form ===
null) {
328 $job_ids = $this->retrieveTableActionJobIds();
329 if (count($job_ids) !== 1) {
330 $this->
ctrl->redirect($this, self::VIEW);
333 $job_id = current($job_ids);
334 $job = $this->cron_repository->getJobInstanceById($job_id);
335 if ($job && $job->usesLegacyForms()) {
336 $this->
ctrl->setParameter($this, $this->getJobIdParameterName(), $job->getId());
337 $this->
ctrl->redirect($this,
'editLegacy');
340 $form = $this->buildForm($job);
343 $this->tpl->setContent($this->ui_renderer->render($form));
348 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
349 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
352 if ($a_form ===
null) {
353 $job_ids = $this->retrieveTableActionJobIds();
354 if (count($job_ids) !== 1) {
355 $this->
ctrl->redirect($this, self::VIEW);
358 $job_id = current($job_ids);
359 $job = $this->cron_repository->getJobInstanceById($job_id);
360 $a_form = $this->initLegacyEditForm($job);
363 $this->tpl->setContent($a_form->getHTML());
368 return match ($schedule_type) {
369 JobScheduleType::DAILY => $this->
lng->txt(
'cron_schedule_daily'),
370 JobScheduleType::WEEKLY => $this->
lng->txt(
'cron_schedule_weekly'),
371 JobScheduleType::MONTHLY => $this->
lng->txt(
'cron_schedule_monthly'),
372 JobScheduleType::QUARTERLY => $this->
lng->txt(
'cron_schedule_quarterly'),
374 JobScheduleType::IN_MINUTES => sprintf($this->
lng->txt(
'cron_schedule_in_minutes'),
'x'),
375 JobScheduleType::IN_HOURS => sprintf($this->
lng->txt(
'cron_schedule_in_hours'),
'x'),
376 JobScheduleType::IN_DAYS => sprintf($this->
lng->txt(
'cron_schedule_in_days'),
'x'),
382 return match ($schedule_type) {
383 JobScheduleType::IN_MINUTES =>
'smini',
384 JobScheduleType::IN_HOURS =>
'shri',
385 JobScheduleType::IN_DAYS =>
'sdyi',
386 default =>
throw new InvalidArgumentException(
388 'The passed argument %s is invalid!',
389 var_export($schedule_type,
true)
397 return in_array($schedule_type, [
398 JobScheduleType::IN_MINUTES,
399 JobScheduleType::IN_HOURS,
400 JobScheduleType::IN_DAYS
406 if (!($job instanceof
CronJob)) {
407 $this->
ctrl->redirect($this, self::VIEW);
410 $this->
ctrl->setParameter($this, $this->getJobIdParameterName(), $job->
getId());
412 $jobs_data = $this->cron_repository->getCronJobData($job->
getId());
413 $job_data = $jobs_data[0];
415 $section_inputs = [];
417 $schedule_type_groups = [];
423 $schedule_type_inputs = [];
425 $schedule_value_input = $this->ui_factory
429 $this->
lng->txt(
'cron_schedule_value')
430 )->withAdditionalTransformation(
432 $this->refinery->int()->isGreaterThanOrEqual(1)
434 )->withRequired(
true);
436 if (is_numeric($job_data[
'schedule_type']) &&
437 JobScheduleType::tryFrom((
int) $job_data[
'schedule_type']) === $schedule_type) {
438 $schedule_value_input = $schedule_value_input->withValue(
439 $job_data[
'schedule_value'] ===
null ?
null : (
int) $job_data[
'schedule_value']
443 $schedule_type_inputs = [
444 $this->getScheduleValueFormElementName($schedule_type) => $schedule_value_input
448 $schedule_type_groups[self::FORM_PARAM_SCHEDULE_PREFIX . $schedule_type->value] = $this->ui_factory
452 $schedule_type_inputs,
453 $this->getScheduleTypeFormElementName($schedule_type)
455 ->withDedicatedName(self::FORM_PARAM_SCHEDULE_PREFIX . $schedule_type->value);
460 $section_inputs[
'schedule'] = $this->ui_factory
464 $schedule_type_groups,
465 $this->
lng->txt(
'cron_schedule_type')
469 $job_data[
'schedule_type'] ===
null ?
470 self::FORM_PARAM_SCHEDULE_PREFIX . $default_schedule_type :
471 self::FORM_PARAM_SCHEDULE_PREFIX . $job_data[
'schedule_type']
475 $main_section = $this->ui_factory->input()->field()->section(
477 $this->
lng->txt(
'cron_action_edit') .
': "' . $job->
getTitle() .
'"'
481 self::FORM_PARAM_MAIN_SECTION => $main_section
488 self::FORM_PARAM_JOB_INPUT =>
498 return $this->ui_factory
502 ->standard($this->
ctrl->getFormAction($this,
'update'),
$inputs)
503 ->withDedicatedName(
'cron_form');
509 #[\Deprecated('Will be removed without any alternative, KS/UI forms will be expected', since: '13.0')]
512 if (!($job instanceof
CronJob)) {
513 $this->
ctrl->redirect($this, self::VIEW);
516 $this->
ctrl->setParameter($this, $this->getJobIdParameterName(), $job->
getId());
518 $jobs_data = $this->cron_repository->getCronJobData($job->
getId());
519 $job_data = $jobs_data[0];
522 $form->setFormAction($this->
ctrl->getFormAction($this,
'updateLegacy'));
523 $form->setTitle($this->
lng->txt(
'cron_action_edit') .
': "' . $job->
getTitle() .
'"');
527 $type->setRequired(
true);
528 $type->setValue($job_data[
'schedule_type'] ===
null ?
null : (
string) $job_data[
'schedule_type']);
536 $this->getScheduleTypeFormElementName($schedule_type),
537 (
string) $schedule_type->value
539 $type->addOption($option);
543 $this->
lng->txt(
'cron_schedule_value'),
544 $this->getScheduleValueFormElementName($schedule_type)
546 $scheduleValue->allowDecimals(
false);
547 $scheduleValue->setRequired(
true);
548 $scheduleValue->setSize(5);
549 if (is_numeric($job_data[
'schedule_type']) &&
550 JobScheduleType::tryFrom((
int) $job_data[
'schedule_type']) === $schedule_type) {
551 $scheduleValue->setValue(
552 $job_data[
'schedule_value'] ===
null ?
null : (
string) $job_data[
'schedule_value']
555 $option->addSubItem($scheduleValue);
559 $form->addItem($type);
566 $form->addCommandButton(
'updateLegacy', $this->
lng->txt(
'save'));
567 $form->addCommandButton(self::VIEW, $this->
lng->txt(
'cancel'));
574 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
575 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
578 $job_id = $this->getRequestValue($this->getJobIdParameterName(), $this->
refinery->kindlyTo()->string());
580 $this->
ctrl->redirect($this, self::VIEW);
583 $job = $this->cron_repository->getJobInstanceById($job_id);
584 $form = $this->buildForm($job);
588 if ($this->
http->request()->getMethod() ===
'POST') {
589 $form = $form->withRequest($this->
http->request());
590 $form_data = $form->getData();
591 $form_valid = $form_data !==
null;
600 if ($job->hasFlexibleSchedule()) {
601 $schedule_group = $form_data[self::FORM_PARAM_MAIN_SECTION][self::FORM_PARAM_GROUP_SCHEDULE];
604 (
int) ltrim($schedule_group[0], self::FORM_PARAM_SCHEDULE_PREFIX)
607 $value = match (
true) {
608 $this->hasScheduleValue($type) => (
int) $schedule_group[1][$this->getScheduleValueFormElementName(
614 $this->cron_repository->updateJobSchedule($job, $type, $value);
617 if ($job->hasCustomSettings()) {
618 $job->saveCustomConfiguration($form_data[self::FORM_PARAM_JOB_INPUT]);
621 $this->tpl->setOnScreenMessage(
'success', $this->
lng->txt(
'cron_action_edit_success'),
true);
622 $this->
ctrl->redirect($this, self::VIEW);
631 #[\Deprecated('Will be removed without any alternative, KS/UI forms will be expected', since: '12.0')]
634 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
635 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
638 $job_id = $this->getRequestValue($this->getJobIdParameterName(), $this->
refinery->kindlyTo()->string());
640 $this->
ctrl->redirect($this, self::VIEW);
643 $job = $this->cron_repository->getJobInstanceById($job_id);
645 $form = $this->initLegacyEditForm($job);
646 if ($job instanceof
CronJob && $form->checkInput()) {
648 if ($job->hasCustomSettings() && !$job->saveCustomSettings($form)) {
652 if (
$valid && $job->hasFlexibleSchedule()) {
654 $value = match (
true) {
655 $this->hasScheduleValue($type) => (
int) $form->getInput(
656 $this->getScheduleValueFormElementName($type)
661 $this->cron_repository->updateJobSchedule($job, $type, $value);
665 $this->tpl->setOnScreenMessage(
'success', $this->
lng->txt(
'cron_action_edit_success'),
true);
666 $this->
ctrl->redirect($this, self::VIEW);
670 $form->setValuesByPost();
671 $this->editLegacy($form);
674 public function run(): void
676 $this->confirm(
'run');
681 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
682 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
685 $job_ids = $this->retrieveTableActionJobIds();
686 if (count($job_ids) !== 1) {
687 $this->
ctrl->redirect($this, self::VIEW);
690 $job_id = current($job_ids);
691 if ($this->cron_manager->runJobManual($job_id, $this->user)) {
692 $this->tpl->setOnScreenMessage(
'success', $this->
lng->txt(
'cron_action_run_success'),
true);
694 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
'cron_action_run_fail'),
true);
697 $this->
ctrl->redirect($this, self::VIEW);
702 $this->confirm(
'activate');
707 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
708 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
711 $jobs = $this->getMultiActionData();
713 foreach ($jobs as $job) {
714 if ($this->cron_manager->isJobInactive($job->getId())) {
715 $this->cron_manager->resetJob($job, $this->
user);
719 $this->tpl->setOnScreenMessage(
'success', $this->
lng->txt(
'cron_action_activate_success'),
true);
721 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'no_checkbox'),
true);
724 $this->
ctrl->redirect($this, self::VIEW);
729 $this->confirm(
'deactivate');
734 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
735 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
738 $jobs = $this->getMultiActionData();
740 foreach ($jobs as $job) {
741 if ($this->cron_manager->isJobActive($job->getId())) {
742 $this->cron_manager->deactivateJob($job, $this->
user,
true);
746 $this->tpl->setOnScreenMessage(
'success', $this->
lng->txt(
'cron_action_deactivate_success'),
true);
748 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'no_checkbox'),
true);
751 $this->
ctrl->redirect($this, self::VIEW);
756 $this->confirm(
'reset');
761 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
762 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
765 $jobs = $this->getMultiActionData();
767 foreach ($jobs as $job) {
768 $this->cron_manager->resetJob($job, $this->
user);
770 $this->tpl->setOnScreenMessage(
'success', $this->
lng->txt(
'cron_action_reset_success'),
true);
772 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'no_checkbox'),
true);
775 $this->
ctrl->redirect($this, self::VIEW);
787 $job_ids = $this->retrieveTableActionJobIds();
788 }
catch (\
ILIAS\Refinery\ConstraintViolationException|OutOfBoundsException) {
791 foreach ($job_ids as $job_id) {
792 $job = $this->cron_repository->getJobInstanceById($job_id);
794 $res[$job_id] = $job;
801 protected function confirm(
string $a_action): void
803 if (!$this->
rbac->system()->checkAccess(
'write', $this->ref_id)) {
804 $this->
error->raiseError($this->
lng->txt(
'no_permission'), $this->error->WARNING);
807 $jobs = $this->getMultiActionData();
809 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'no_checkbox'),
true);
810 $this->
ctrl->redirect($this, self::VIEW);
813 if ($a_action ===
'run') {
814 $jobs = array_filter($jobs,
static function (
CronJob $job):
bool {
819 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
'cron_no_executable_job_selected'),
true);
820 $this->
ctrl->redirect($this, self::VIEW);
826 if (count($jobs) === 1) {
827 $jobKeys = array_keys($jobs);
828 $job_id = array_pop($jobKeys);
829 $job = array_pop($jobs);
830 $title = $job->getTitle();
832 $title = preg_replace(
'[^A-Za-z0-9_\-]',
'', $job->getId());
835 $cgui->setHeaderText(
837 $this->
lng->txt(
'cron_action_' . $a_action .
'_sure'),
842 $cgui->addHiddenItem($this->getJobIdParameterName() .
'[]', $job_id);
844 $cgui->setHeaderText($this->
lng->txt(
'cron_action_' . $a_action .
'_sure_multi'));
846 foreach ($jobs as $job_id => $job) {
847 $cgui->addItem($this->getJobIdParameterName() .
'[]', $job_id, $job->getTitle());
851 $cgui->setFormAction($this->
ctrl->getFormAction($this,
'confirmed' . ucfirst($a_action)));
852 $cgui->setCancel($this->
lng->txt(
'cancel'), self::VIEW);
853 $cgui->setConfirm($this->
lng->txt(
'cron_action_' . $a_action),
'confirmed' . ucfirst($a_action));
855 $this->tpl->setContent($cgui->getHTML());
865 $data = $this->cron_repository->getCronJobData();
866 foreach (
$data as $item) {
867 $job = $this->cron_repository->getJobInstance(
873 $job->addToExternalSettingsForm($a_form_id, $fields, (
bool) $item[
'job_status']);
877 if ($fields !== []) {
getCustomConfigurationInput(\ILIAS\UI\Factory $ui_factory, \ILIAS\Refinery\Factory $factory, \ilLanguage $lng)
getAllScheduleTypes()
Get all available schedule types.
getScheduleTypesWithValues()
getValidScheduleTypes()
Returns a collection of all valid schedule types for a specific job.
addCustomSettingsToForm(\ilPropertyFormGUI $a_form)
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
initLegacyEditForm(?CronJob $job)
getScheduleValueFormElementName(JobScheduleType $schedule_type)
const FORM_PARAM_MAIN_SECTION
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.