From 0d8bf94e7dbaa3b632b32dd3de7ee7a6870f6429 Mon Sep 17 00:00:00 2001 From: mjansen Date: Thu, 2 Apr 2026 13:32:03 +0200 Subject: [PATCH] [FEATURE] Cron: Use "Component" mechanisms to gather and register jobs Co-authored-by: Nils Haagen --- .../ILIAS/Authentication/Authentication.php | 11 +- ...class.ilAuthDestroyExpiredSessionsCron.php | 17 +- components/ILIAS/Authentication/service.xml | 3 - .../ILIAS/BookingManager/BookingManager.php | 13 + .../classes/class.ilBookCronNotification.php | 21 +- .../classes/class.ilBookingPrefBookCron.php | 28 +- components/ILIAS/BookingManager/module.xml | 4 - components/ILIAS/COPage/COPage.php | 6 + .../class.ilCleanCOPageHistoryCronjob.php | 22 +- components/ILIAS/COPage/service.xml | 3 - components/ILIAS/Calendar/Calendar.php | 13 + .../class.ilConsultationHourCron.php | 18 +- .../Cron/class.ilCalendarCronRemoteReader.php | 20 +- components/ILIAS/Calendar/service.xml | 4 - components/ILIAS/Certificate/Certificate.php | 9 +- .../classes/API/UserCertificateAPI.php | 7 +- .../classes/class.ilCertificateCron.php | 50 ++- .../class.ilObjCertificateSettingsGUI.php | 7 +- components/ILIAS/Certificate/service.xml | 3 - .../tests/ilCertificateCronTest.php | 58 ++- components/ILIAS/CmiXapi/CmiXapi.php | 13 + .../classes/class.ilCmiXapiDelCron.php | 19 +- .../classes/class.ilXapiResultsCronjob.php | 19 +- components/ILIAS/CmiXapi/module.xml | 4 - ....ilComponentDefinitionsStoredObjective.php | 6 - components/ILIAS/Course/Course.php | 7 + .../classes/class.ilTimingsCronReminder.php | 18 +- components/ILIAS/Course/module.xml | 3 - components/ILIAS/Cron/Cron.php | 16 +- components/ILIAS/Cron/README.md | 34 +- components/ILIAS/Cron/ROADMAP.md | 17 +- components/ILIAS/Cron/phpunit.xml | 4 +- components/ILIAS/Cron/service.xml | 3 - components/ILIAS/Cron/src/AbstractCronJob.php | 330 +++++++++++++++++ components/ILIAS/Cron/src/CronJob.php | 241 +++--------- ...CronHookPlugin.php => CronJobRegistry.php} | 11 +- .../Cron/src/InMemoryCronJobRegistry.php | 51 +++ components/ILIAS/Cron/src/Job/JobEntity.php | 40 +- components/ILIAS/Cron/src/Job/JobManager.php | 12 +- .../ILIAS/Cron/src/Job/JobRepository.php | 62 ++-- .../Cron/src/Job/Manager/JobManagerImpl.php | 93 +++-- .../src/Job/Manager/StrictCliJobManager.php | 24 +- .../Cron/src/Job/Manager/UI/JobTable.php | 11 +- .../Job/Manager/UI/JobTableFilterMediator.php | 30 +- .../src/Job/Repository/JobRepositoryImpl.php | 345 +++++++----------- components/ILIAS/Cron/src/Setup/Agent.php | 77 ---- .../Cron/src/Setup/CronDBUpdateSteps12.php | 41 +++ .../Cron/src/Setup/CronJobSetupAgent.php | 102 ++++++ .../Cron/src/Setup/DefinitionProcessor.php | 95 ----- .../StoreCronJobsInDatabaseObjective.php | 104 ++++++ .../ILIAS/Cron/src/class.ilObjCronGUI.php | 12 +- .../ILIAS/Cron/tests/CronJobEntityTest.php | 13 +- .../ILIAS/Cron/tests/CronJobScheduleTest.php | 102 ++++-- .../tests/InMemoryCronJobRegistryTest.php | 64 ++++ components/ILIAS/Exercise/Exercise.php | 13 + .../class.ilExcCronFeedbackNotification.php | 27 +- .../classes/class.ilExcCronReminders.php | 28 +- components/ILIAS/Exercise/module.xml | 4 - components/ILIAS/Filesystem/Filesystem.php | 7 + .../class.ilFileSystemCleanTempDirCron.php | 30 +- components/ILIAS/Filesystem/service.xml | 3 - components/ILIAS/Forum/Forum.php | 15 +- .../classes/class.ilForumCronNotification.php | 46 +-- components/ILIAS/Forum/module.xml | 3 - components/ILIAS/Init/Init.php | 1 + .../Init/classes/class.ilInitialisation.php | 97 ++--- .../ILIAS/Init/src/AllModernComponents.php | 2 + components/ILIAS/LDAP/LDAP.php | 9 +- .../class.ilLDAPCronSynchronization.php | 37 +- components/ILIAS/LDAP/service.xml | 3 - components/ILIAS/LTIProvider/LTIProvider.php | 7 + .../classes/class.ilLTICronOutcomeService.php | 21 +- components/ILIAS/LTIProvider/service.xml | 3 - components/ILIAS/Logging/Logging.php | 56 +++ .../class.ilLoggerCronCleanErrorFiles.php | 21 +- .../classes/public/class.ilLoggerFactory.php | 17 +- components/ILIAS/Logging/service.xml | 3 - .../src/LoggerFactory.php} | 17 +- components/ILIAS/Mail/Mail.php | 29 +- .../classes/class.ilMailCronNotification.php | 37 +- .../classes/class.ilMailCronOrphanedMails.php | 63 ++-- components/ILIAS/Mail/service.xml | 5 - .../Mail/src/Cron/ScheduledMailsCron.php | 69 ++-- components/ILIAS/Membership/Membership.php | 13 +- .../Cron/class.ilMembershipCronMinMembers.php | 17 +- .../class.ilMembershipCronNotifications.php | 16 +- components/ILIAS/Membership/service.xml | 4 - components/ILIAS/MetaData/MetaData.php | 7 + .../classes/class.ilCronOerHarvester.php | 6 +- components/ILIAS/MetaData/service.xml | 3 - components/ILIAS/OrgUnit/OrgUnit.php | 7 + .../class.ilCronUpdateOrgUnitPaths.php | 20 +- components/ILIAS/OrgUnit/module.xml | 3 - components/ILIAS/Search/Search.php | 7 + .../classes/Lucene/class.ilLuceneIndexer.php | 13 +- components/ILIAS/Search/service.xml | 3 - components/ILIAS/Skill/Skill.php | 7 + .../classes/class.ilSkillNotifications.php | 31 +- components/ILIAS/Skill/service.xml | 3 - .../ILIAS/StudyProgramme/StudyProgramme.php | 31 ++ ...lPrgInvalidateExpiredProgressesCronJob.php | 20 +- .../class.ilPrgRestartAssignmentsCronJob.php | 20 +- .../class.ilPrgUpdateProgressCronJob.php | 15 +- .../class.ilPrgUserNotRestartedCronJob.php | 21 +- .../class.ilPrgUserRiskyToFailCronJob.php | 20 +- components/ILIAS/StudyProgramme/module.xml | 7 - .../ilPrgRestartAssignmentsCronJobTest.php | 21 +- .../ilStudyProgrammeCronAboutToExpireTest.php | 22 +- .../ilStudyProgrammeCronRiskyToFailTest.php | 22 +- components/ILIAS/Survey/Survey.php | 7 + .../class.ilSurveyCronNotification.php | 24 +- components/ILIAS/Survey/module.xml | 3 - components/ILIAS/SystemCheck/SystemCheck.php | 7 +- .../classes/class.ilSCCronTrash.php | 25 +- components/ILIAS/SystemCheck/service.xml | 3 - components/ILIAS/Test/Test.php | 7 + ...class.ilCronFinishUnfinishedTestPasses.php | 16 +- components/ILIAS/Test/module.xml | 3 - .../ilCronFinishUnfinishedTestPassesTest.php | 18 +- components/ILIAS/Tracking/Tracking.php | 7 + .../class.ilLPCronObjectStatistics.php | 16 +- components/ILIAS/Tracking/service.xml | 3 - components/ILIAS/User/User.php | 25 ++ ...ss.ilCronDeleteInactivatedUserAccounts.php | 76 ++-- ...class.ilCronDeleteInactiveUserAccounts.php | 108 ++---- ....ilCronDeleteNeverLoggedInUserAccounts.php | 71 ++-- .../Cron/class.ilUserCronCheckAccounts.php | 26 +- components/ILIAS/User/service.xml | 6 - components/ILIAS/WOPI/WOPI.php | 7 + .../WOPI/classes/Cron/class.ilWOPICrawler.php | 9 +- components/ILIAS/WOPI/service.xml | 11 +- components/ILIAS/WebServices/WebServices.php | 7 + .../classes/class.ilCronEcsTaskScheduler.php | 15 +- components/ILIAS/WebServices/service.xml | 47 ++- 134 files changed, 2122 insertions(+), 1797 deletions(-) create mode 100644 components/ILIAS/Cron/src/AbstractCronJob.php rename components/ILIAS/Cron/src/{CronHookPlugin.php => CronJobRegistry.php} (72%) create mode 100644 components/ILIAS/Cron/src/InMemoryCronJobRegistry.php delete mode 100644 components/ILIAS/Cron/src/Setup/Agent.php create mode 100644 components/ILIAS/Cron/src/Setup/CronDBUpdateSteps12.php create mode 100644 components/ILIAS/Cron/src/Setup/CronJobSetupAgent.php delete mode 100644 components/ILIAS/Cron/src/Setup/DefinitionProcessor.php create mode 100644 components/ILIAS/Cron/src/Setup/StoreCronJobsInDatabaseObjective.php create mode 100644 components/ILIAS/Cron/tests/InMemoryCronJobRegistryTest.php rename components/ILIAS/{Cron/src/Job/JobProvider.php => Logging/src/LoggerFactory.php} (62%) diff --git a/components/ILIAS/Authentication/Authentication.php b/components/ILIAS/Authentication/Authentication.php index 6b52a8a2bb31..20d3293871ce 100644 --- a/components/ILIAS/Authentication/Authentication.php +++ b/components/ILIAS/Authentication/Authentication.php @@ -47,7 +47,7 @@ public function offsetGet(mixed $offset): mixed } public function offsetSet(mixed $offset, mixed $value): void { - if (!is_string($offset)) { + if (!\is_string($offset)) { throw new \InvalidArgumentException('Offset needs to be of type string.'); } \ilSession::set($offset, $value); @@ -67,7 +67,14 @@ public function offsetUnset(mixed $offset): void new Component\Resource\Endpoint($this, 'sessioncheck.php'); $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\ComponentJS($this, 'js/dist/SessionReminder.min.js'); - $contribute[User\Settings\UserSettings::class] = fn() => + $contribute[User\Settings\UserSettings::class] = static fn() => new Authentication\UserSettings\Settings(); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilAuthDestroyExpiredSessionsCron( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/Authentication/classes/Cron/class.ilAuthDestroyExpiredSessionsCron.php b/components/ILIAS/Authentication/classes/Cron/class.ilAuthDestroyExpiredSessionsCron.php index 7f38fe762170..7e4132bdc1b9 100755 --- a/components/ILIAS/Authentication/classes/Cron/class.ilAuthDestroyExpiredSessionsCron.php +++ b/components/ILIAS/Authentication/classes/Cron/class.ilAuthDestroyExpiredSessionsCron.php @@ -19,18 +19,13 @@ declare(strict_types=1); use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; -class ilAuthDestroyExpiredSessionsCron extends CronJob +class ilAuthDestroyExpiredSessionsCron extends AbstractCronJob { - protected ilLanguage $lng; - - public function __construct() + public function init(): void { - global $DIC; - - $this->lng = $DIC->language(); - $this->lng->loadLanguageModule('auth'); + $this->language->loadLanguageModule('auth'); } public function getId(): string @@ -40,12 +35,12 @@ public function getId(): string public function getTitle(): string { - return $this->lng->txt('auth_cron_destroy_expired_sessions'); + return $this->language->txt('auth_cron_destroy_expired_sessions'); } public function getDescription(): string { - return $this->lng->txt('auth_cron_destroy_expired_sessions_desc'); + return $this->language->txt('auth_cron_destroy_expired_sessions_desc'); } public function hasAutoActivation(): bool diff --git a/components/ILIAS/Authentication/service.xml b/components/ILIAS/Authentication/service.xml index ab8ba0262925..78b703afe9b3 100755 --- a/components/ILIAS/Authentication/service.xml +++ b/components/ILIAS/Authentication/service.xml @@ -23,7 +23,4 @@ - - - diff --git a/components/ILIAS/BookingManager/BookingManager.php b/components/ILIAS/BookingManager/BookingManager.php index f49fde78f512..aee12e570ebd 100644 --- a/components/ILIAS/BookingManager/BookingManager.php +++ b/components/ILIAS/BookingManager/BookingManager.php @@ -39,5 +39,18 @@ public function init( $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\ComponentJS($this, "ScheduleInput.js"); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilBookCronNotification( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilBookingPrefBookCron( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/BookingManager/classes/class.ilBookCronNotification.php b/components/ILIAS/BookingManager/classes/class.ilBookCronNotification.php index 5df801256446..0882b8e0beef 100755 --- a/components/ILIAS/BookingManager/classes/class.ilBookCronNotification.php +++ b/components/ILIAS/BookingManager/classes/class.ilBookCronNotification.php @@ -18,25 +18,24 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Cron for booking manager notification * @author Alexander Killing */ -class ilBookCronNotification extends CronJob +class ilBookCronNotification extends AbstractCronJob { protected \ILIAS\BookingManager\InternalRepoService $repo; - protected ilLanguage $lng; protected ilLogger $book_log; - public function __construct() + public function init(): void { global $DIC; - $this->lng = $DIC->language(); + $this->language->loadLanguageModule('book'); - $this->book_log = ilLoggerFactory::getLogger("book"); + $this->book_log = $this->logger_factory->getComponentLogger('book'); $this->repo = $DIC->bookingManager() ->internal() ->repo(); @@ -49,18 +48,12 @@ public function getId(): string public function getTitle(): string { - $lng = $this->lng; - - $lng->loadLanguageModule("book"); - return $lng->txt("book_notification"); + return $this->language->txt("book_notification"); } public function getDescription(): string { - $lng = $this->lng; - - $lng->loadLanguageModule("book"); - return $lng->txt("book_notification_info"); + return $this->language->txt("book_notification_info"); } public function getDefaultScheduleType(): JobScheduleType diff --git a/components/ILIAS/BookingManager/classes/class.ilBookingPrefBookCron.php b/components/ILIAS/BookingManager/classes/class.ilBookingPrefBookCron.php index ad40d8800db1..1b08dbb3767b 100755 --- a/components/ILIAS/BookingManager/classes/class.ilBookingPrefBookCron.php +++ b/components/ILIAS/BookingManager/classes/class.ilBookingPrefBookCron.php @@ -18,7 +18,7 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Cron for booking pools @@ -26,38 +26,26 @@ * * @author Alexander Killing */ -class ilBookingPrefBookCron extends CronJob +class ilBookingPrefBookCron extends AbstractCronJob { - protected ilLanguage $lng; - - public function __construct() + public function getId(): string { - global $DIC; - - $this->lng = $DIC->language(); + return "book_pref_book"; } - public function getId(): string + public function init(): void { - return "book_pref_book"; + $this->language->loadLanguageModule('book'); } public function getTitle(): string { - $lng = $this->lng; - - $lng->loadLanguageModule("book"); - - return $lng->txt("book_pref_book_cron"); + return $this->language->txt("book_pref_book_cron"); } public function getDescription(): string { - $lng = $this->lng; - - $lng->loadLanguageModule("book"); - - return $lng->txt("book_pref_book_cron_info"); + return $this->language->txt("book_pref_book_cron_info"); } public function getDefaultScheduleType(): JobScheduleType diff --git a/components/ILIAS/BookingManager/module.xml b/components/ILIAS/BookingManager/module.xml index a5f775ba7db2..41226d366bc1 100755 --- a/components/ILIAS/BookingManager/module.xml +++ b/components/ILIAS/BookingManager/module.xml @@ -21,9 +21,5 @@ - - - - diff --git a/components/ILIAS/COPage/COPage.php b/components/ILIAS/COPage/COPage.php index 9b050da8a00c..3e0cbc82e7fb 100644 --- a/components/ILIAS/COPage/COPage.php +++ b/components/ILIAS/COPage/COPage.php @@ -123,5 +123,11 @@ public function getTarget(): string } }; + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilCleanCOPageHistoryCronjob( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/COPage/Cron/class.ilCleanCOPageHistoryCronjob.php b/components/ILIAS/COPage/Cron/class.ilCleanCOPageHistoryCronjob.php index bb36dc939983..9a924e282565 100755 --- a/components/ILIAS/COPage/Cron/class.ilCleanCOPageHistoryCronjob.php +++ b/components/ILIAS/COPage/Cron/class.ilCleanCOPageHistoryCronjob.php @@ -21,22 +21,22 @@ use ILIAS\COPage\History\HistoryManager; use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * @author Alexander Killing */ -class ilCleanCOPageHistoryCronjob extends CronJob +class ilCleanCOPageHistoryCronjob extends AbstractCronJob { protected HistoryManager $history_manager; protected ilSetting $settings; - protected ilLanguage $lng; - public function __construct() + public function init(): void { global $DIC; - $this->lng = $DIC->language(); + $this->language->loadLanguageModule("copg"); + $this->settings = $DIC->settings(); $this->history_manager = $DIC ->copage() @@ -52,18 +52,12 @@ public function getId(): string public function getTitle(): string { - $lng = $this->lng; - - $lng->loadLanguageModule("copg"); - return $lng->txt("copg_history_cleanup_cron"); + return $this->language->txt("copg_history_cleanup_cron"); } public function getDescription(): string { - $lng = $this->lng; - - $lng->loadLanguageModule("copg"); - return $lng->txt("copg_history_cleanup_cron_info"); + return $this->language->txt("copg_history_cleanup_cron_info"); } public function getDefaultScheduleType(): JobScheduleType @@ -117,7 +111,7 @@ public function run(): JobResult public function addCustomSettingsToForm(ilPropertyFormGUI $a_form): void { - $lng = $this->lng; + $lng = $this->language; $lng->loadLanguageModule("copg"); $ti = new ilNumberInputGUI( diff --git a/components/ILIAS/COPage/service.xml b/components/ILIAS/COPage/service.xml index 66bb1ff5466d..3301dded0a88 100755 --- a/components/ILIAS/COPage/service.xml +++ b/components/ILIAS/COPage/service.xml @@ -38,9 +38,6 @@ - - - diff --git a/components/ILIAS/Calendar/Calendar.php b/components/ILIAS/Calendar/Calendar.php index 4d1df89d0a5b..af468f4cbfe3 100644 --- a/components/ILIAS/Calendar/Calendar.php +++ b/components/ILIAS/Calendar/Calendar.php @@ -53,5 +53,18 @@ public function init( $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\NodeModule("eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js"); */ + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilCalendarCronRemoteReader( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilConsultationHourCron( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/Calendar/classes/ConsultationHours/class.ilConsultationHourCron.php b/components/ILIAS/Calendar/classes/ConsultationHours/class.ilConsultationHourCron.php index 1a0942589464..7eea5e57b7d1 100755 --- a/components/ILIAS/Calendar/classes/ConsultationHours/class.ilConsultationHourCron.php +++ b/components/ILIAS/Calendar/classes/ConsultationHours/class.ilConsultationHourCron.php @@ -20,24 +20,24 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Reminders for consultation hours * @author Stefan Meyer */ -class ilConsultationHourCron extends CronJob +class ilConsultationHourCron extends AbstractCronJob { - protected ilLanguage $lng; protected ilDBInterface $db; protected ilSetting $setting; - public function __construct() + + public function init(): void { global $DIC; - $this->lng = $DIC->language(); - $this->lng->loadLanguageModule('dateplaner'); + $this->language->loadLanguageModule('dateplaner'); + $this->db = $DIC->database(); $this->setting = $DIC->settings(); } @@ -49,12 +49,12 @@ public function getId(): string public function getTitle(): string { - return $this->lng->txt("cal_ch_cron_reminder"); + return $this->language->txt("cal_ch_cron_reminder"); } public function getDescription(): string { - return $this->lng->txt("cal_ch_cron_reminder_info"); + return $this->language->txt("cal_ch_cron_reminder_info"); } public function getDefaultScheduleType(): JobScheduleType @@ -124,7 +124,7 @@ public function run(): JobResult public function addCustomSettingsToForm(ilPropertyFormGUI $a_form): void { - $consultation_days = new ilNumberInputGUI($this->lng->txt('cal_ch_cron_reminder_days'), 'ch_reminder_days'); + $consultation_days = new ilNumberInputGUI($this->language->txt('cal_ch_cron_reminder_days'), 'ch_reminder_days'); $consultation_days->setMinValue(1); $consultation_days->setMaxLength(2); $consultation_days->setSize(2); diff --git a/components/ILIAS/Calendar/classes/Cron/class.ilCalendarCronRemoteReader.php b/components/ILIAS/Calendar/classes/Cron/class.ilCalendarCronRemoteReader.php index ad72b3726d32..a32391d55a57 100755 --- a/components/ILIAS/Calendar/classes/Cron/class.ilCalendarCronRemoteReader.php +++ b/components/ILIAS/Calendar/classes/Cron/class.ilCalendarCronRemoteReader.php @@ -20,22 +20,22 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType as CronJobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; -class ilCalendarCronRemoteReader extends CronJob +class ilCalendarCronRemoteReader extends AbstractCronJob { private const DEFAULT_SYNC_HOURS = 1; - private ilLanguage $lng; private ilLogger $logger; private ?ilCalendarSettings $calendar_settings = null; - public function __construct() + public function init(): void { global $DIC; - $this->lng = $DIC->language(); + $this->language->loadLanguageModule('dateplaner'); + $this->logger = $DIC->logger()->cal(); $this->calendar_settings = ilCalendarSettings::_getInstance(); } @@ -47,14 +47,12 @@ public function getId(): string public function getTitle(): string { - $this->lng->loadLanguageModule('dateplaner'); - return $this->lng->txt('cal_cronjob_remote_title'); + return $this->language->txt('cal_cronjob_remote_title'); } public function getDescription(): string { - $this->lng->loadLanguageModule('dateplaner'); - return $this->lng->txt('cal_cronjob_remote_description'); + return $this->language->txt('cal_cronjob_remote_description'); } public function hasAutoActivation(): bool @@ -72,8 +70,8 @@ public function addToExternalSettingsForm(int $a_form_id, array &$a_fields, bool switch ($a_form_id) { case ilAdministrationSettingsFormHandler::FORM_CALENDAR: $a_fields['cal_webcal_sync'] = $a_is_active ? - $this->lng->txt('enabled') : - $this->lng->txt('disabled'); + $this->language->txt('enabled') : + $this->language->txt('disabled'); break; } } diff --git a/components/ILIAS/Calendar/service.xml b/components/ILIAS/Calendar/service.xml index cdb7cda6246a..3bf74812cc04 100755 --- a/components/ILIAS/Calendar/service.xml +++ b/components/ILIAS/Calendar/service.xml @@ -16,10 +16,6 @@ - - - - diff --git a/components/ILIAS/Certificate/Certificate.php b/components/ILIAS/Certificate/Certificate.php index 952bd54700c7..2db909cb3ed9 100644 --- a/components/ILIAS/Certificate/Certificate.php +++ b/components/ILIAS/Certificate/Certificate.php @@ -33,8 +33,13 @@ public function init( array | \ArrayAccess &$internal, ): void { $contribute[\ILIAS\Setup\Agent::class] = static fn() => - new \ilCertificatSetupAgent( - $pull[\ILIAS\Refinery\Factory::class] + new \ilCertificatSetupAgent(); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilCertificateCron( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] ); } } diff --git a/components/ILIAS/Certificate/classes/API/UserCertificateAPI.php b/components/ILIAS/Certificate/classes/API/UserCertificateAPI.php index 67f3b1dcfb07..f9bd0f981c4e 100755 --- a/components/ILIAS/Certificate/classes/API/UserCertificateAPI.php +++ b/components/ILIAS/Certificate/classes/API/UserCertificateAPI.php @@ -175,7 +175,12 @@ private function processEntry( 'persistent_certificate_mode_cron' ); if ($mode === 'persistent_certificate_mode_instant') { - $cronjob = new ilCertificateCron(); + global $DIC; + $cronjob = new ilCertificateCron( + \ILIAS\Certificate::class, + $DIC->language(), + \ilLoggerFactory::getInstance() + ); $cronjob->init(); $cronjob->processEntry(0, $entry, []); return; diff --git a/components/ILIAS/Certificate/classes/class.ilCertificateCron.php b/components/ILIAS/Certificate/classes/class.ilCertificateCron.php index cc484473c582..fc9263182daf 100755 --- a/components/ILIAS/Certificate/classes/class.ilCertificateCron.php +++ b/components/ILIAS/Certificate/classes/class.ilCertificateCron.php @@ -22,98 +22,90 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobManager; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; -/** - * @author Niels Theen - */ -class ilCertificateCron extends CronJob +class ilCertificateCron extends AbstractCronJob { - protected ?ilLanguage $lng; private ?Container $dic; public function __construct( + string $component, + \ILIAS\Language\Language $language, + \ILIAS\Logging\LoggerFactory $logger_factory, private ?ilCertificateQueueRepository $queueRepository = null, private ?ilCertificateTemplateRepository $templateRepository = null, private ?ilUserCertificateRepository $userRepository = null, private ?ilCertificateValueReplacement $valueReplacement = null, private ?ilLogger $logger = null, ?Container $dic = null, - ?ilLanguage $language = null, private ?ilCertificateObjectHelper $objectHelper = null, private ?ilSetting $settings = null, - private ?JobManager $cronManager = null, + private ?JobManager $cronManager = null ) { - if (null === $dic) { + parent::__construct($component, $language, $logger_factory); + if ($dic === null) { global $DIC; $dic = $DIC; } $this->dic = $dic; - - if ($dic && isset($dic['lng'])) { - $language = $dic->language(); - $language->loadLanguageModule('certificate'); - } - - $this->lng = $language; } public function getTitle(): string { - return $this->lng->txt('cert_cron_task_title'); + return $this->language->txt('cert_cron_task_title'); } public function getDescription(): string { - return $this->lng->txt('cert_cron_task_desc'); + return $this->language->txt('cert_cron_task_desc'); } public function init(): void { - if (null === $this->dic) { + $this->language->loadLanguageModule('certificate'); + + if ($this->dic === null) { global $DIC; $this->dic = $DIC; } $database = $this->dic->database(); - if (null === $this->logger) { + if ($this->logger === null) { $this->logger = $this->dic->logger()->cert(); } - if (null === $this->cronManager) { + if ($this->cronManager === null) { $this->cronManager = $this->dic->cron()->manager(); } - if (null === $this->queueRepository) { + if ($this->queueRepository === null) { $this->queueRepository = new ilCertificateQueueRepository($database, $this->logger); } - if (null === $this->templateRepository) { + if ($this->templateRepository === null) { $this->templateRepository = new ilCertificateTemplateDatabaseRepository($database, $this->logger); } - if (null === $this->userRepository) { + if ($this->userRepository === null) { $this->userRepository = new ilUserCertificateRepository($database, $this->logger); } - if (null === $this->valueReplacement) { + if ($this->valueReplacement === null) { $this->valueReplacement = new ilCertificateValueReplacement(); } - if (null === $this->objectHelper) { + if ($this->objectHelper === null) { $this->objectHelper = new ilCertificateObjectHelper(); } - if (null === $this->settings) { + if ($this->settings === null) { $this->settings = new ilSetting('certificate'); } } public function run(): JobResult { - $this->init(); - $result = new JobResult(); $result->setStatus(JobResult::STATUS_NO_ACTION); diff --git a/components/ILIAS/Certificate/classes/class.ilObjCertificateSettingsGUI.php b/components/ILIAS/Certificate/classes/class.ilObjCertificateSettingsGUI.php index 82f51ac7a054..89bcd84ca5e4 100755 --- a/components/ILIAS/Certificate/classes/class.ilObjCertificateSettingsGUI.php +++ b/components/ILIAS/Certificate/classes/class.ilObjCertificateSettingsGUI.php @@ -327,7 +327,12 @@ public function save(): void ); $previousMode = $form_settings->get('persistent_certificate_mode', 'persistent_certificate_mode_cron'); if ($mode !== $previousMode && $mode === 'persistent_certificate_mode_instant') { - $cron = new ilCertificateCron(); + global $DIC; + $cron = new ilCertificateCron( + \ILIAS\Certificate::class, + $DIC->language(), + \ilLoggerFactory::getInstance() + ); $cron->init(); $cron->run(); } diff --git a/components/ILIAS/Certificate/service.xml b/components/ILIAS/Certificate/service.xml index 430437ec71d9..7f7b5c2dfebd 100755 --- a/components/ILIAS/Certificate/service.xml +++ b/components/ILIAS/Certificate/service.xml @@ -14,8 +14,5 @@ - - - diff --git a/components/ILIAS/Certificate/tests/ilCertificateCronTest.php b/components/ILIAS/Certificate/tests/ilCertificateCronTest.php index d0239faf270c..6cbd59633ba7 100755 --- a/components/ILIAS/Certificate/tests/ilCertificateCronTest.php +++ b/components/ILIAS/Certificate/tests/ilCertificateCronTest.php @@ -22,6 +22,32 @@ class ilCertificateCronTest extends ilCertificateBaseTestCase { + private function makeCertificateCron( + ilLanguage $language_mock, + ilCertificateQueueRepository $queue_repository, + ilCertificateTemplateRepository $template_repository, + ilUserCertificateRepository $user_repository, + ilCertificateValueReplacement $value_replacement, + ilLogger $logger, + \ILIAS\DI\Container $dic, + ?ilCertificateObjectHelper $object_helper = null + ): ilCertificateCron { + $logger_factory = $this->createMock(\ILIAS\Logging\LoggerFactory::class); + + return new ilCertificateCron( + \ILIAS\Certificate::class, + $language_mock, + $logger_factory, + $queue_repository, + $template_repository, + $user_repository, + $value_replacement, + $logger, + $dic, + $object_helper + ); + } + public function testGetTitle(): void { $queueRepository = $this->getMockBuilder(ilCertificateQueueRepository::class) @@ -68,14 +94,14 @@ public function testGetTitle(): void $dic['lng'] = $languageMock; - $cron = new ilCertificateCron( + $cron = $this->makeCertificateCron( + $languageMock, $queueRepository, $templateRepository, $userRepository, $valueReplacement, $logger, - $dic, - $languageMock + $dic ); $title = $cron->getTitle(); @@ -129,14 +155,14 @@ public function testGetDescription(): void $dic['lng'] = $languageMock; - $cron = new ilCertificateCron( + $cron = $this->makeCertificateCron( + $languageMock, $queueRepository, $templateRepository, $userRepository, $valueReplacement, $logger, - $dic, - $languageMock + $dic ); $title = $cron->getDescription(); @@ -208,14 +234,14 @@ public function testGetId(): void $userMock ); - $cron = new ilCertificateCron( + $cron = $this->makeCertificateCron( + $languageMock, $queueRepository, $templateRepository, $userRepository, $valueReplacement, $logger, $dic, - $languageMock, $objectHelper ); @@ -290,14 +316,14 @@ public function testActivation(): void $userMock ); - $cron = new ilCertificateCron( + $cron = $this->makeCertificateCron( + $languageMock, $queueRepository, $templateRepository, $userRepository, $valueReplacement, $logger, $dic, - $languageMock, $objectHelper ); @@ -372,14 +398,14 @@ public function testFlexibleActivation(): void $userMock ); - $cron = new ilCertificateCron( + $cron = $this->makeCertificateCron( + $languageMock, $queueRepository, $templateRepository, $userRepository, $valueReplacement, $logger, $dic, - $languageMock, $objectHelper ); @@ -454,14 +480,14 @@ public function testGetDefaultScheduleType(): void $userMock ); - $cron = new ilCertificateCron( + $cron = $this->makeCertificateCron( + $languageMock, $queueRepository, $templateRepository, $userRepository, $valueReplacement, $logger, $dic, - $languageMock, $objectHelper ); @@ -536,14 +562,14 @@ public function testGetDefaultScheduleValue(): void $userMock ); - $cron = new ilCertificateCron( + $cron = $this->makeCertificateCron( + $languageMock, $queueRepository, $templateRepository, $userRepository, $valueReplacement, $logger, $dic, - $languageMock, $objectHelper ); diff --git a/components/ILIAS/CmiXapi/CmiXapi.php b/components/ILIAS/CmiXapi/CmiXapi.php index 6b7458feab53..6bbe3b2a25f3 100644 --- a/components/ILIAS/CmiXapi/CmiXapi.php +++ b/components/ILIAS/CmiXapi/CmiXapi.php @@ -44,5 +44,18 @@ public function init( $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\Endpoint($this, "xapiexit.php"); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilXapiResultsCronjob( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilCmiXapiDelCron( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/CmiXapi/classes/class.ilCmiXapiDelCron.php b/components/ILIAS/CmiXapi/classes/class.ilCmiXapiDelCron.php index d10652704bb0..d4907a820885 100755 --- a/components/ILIAS/CmiXapi/classes/class.ilCmiXapiDelCron.php +++ b/components/ILIAS/CmiXapi/classes/class.ilCmiXapiDelCron.php @@ -20,7 +20,7 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Class ilCmiXapiDelCron @@ -29,7 +29,7 @@ * @author Stefan Schneider */ -class ilCmiXapiDelCron extends CronJob +class ilCmiXapiDelCron extends AbstractCronJob { public const JOB_ID = 'xapi_deletion_cron'; @@ -39,16 +39,11 @@ class ilCmiXapiDelCron extends CronJob protected ilLogger $log; - private \ILIAS\DI\Container $dic; - - public function __construct() + public function init(): void { - global $DIC; /* @var \ILIAS\DI\Container $DIC */ - $this->dic = $DIC; - - $DIC->language()->loadLanguageModule('cmix'); + $this->language->loadLanguageModule('cmix'); - $this->log = ilLoggerFactory::getLogger('cmix'); + $this->log = $this->logger_factory->getComponentLogger('cmix'); $settings = new ilSetting(self::JOB_ID); $lrsTypeId = $settings->get('lrs_type_id', '0'); @@ -69,12 +64,12 @@ public function getId(): string public function getTitle(): string { - return $this->dic->language()->txt("cron_xapi_del"); + return $this->language->txt('cron_xapi_del'); } public function getDescription(): string { - return $this->dic->language()->txt("cron_xapi_del_desc"); + return $this->language->txt('cron_xapi_del_desc'); } /** diff --git a/components/ILIAS/CmiXapi/classes/class.ilXapiResultsCronjob.php b/components/ILIAS/CmiXapi/classes/class.ilXapiResultsCronjob.php index b716881a04cc..3c3b895c3193 100755 --- a/components/ILIAS/CmiXapi/classes/class.ilXapiResultsCronjob.php +++ b/components/ILIAS/CmiXapi/classes/class.ilXapiResultsCronjob.php @@ -20,7 +20,7 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Class ilXapiResultsCronjob @@ -31,7 +31,7 @@ * * @package Module/CmiXapi */ -class ilXapiResultsCronjob extends CronJob +class ilXapiResultsCronjob extends AbstractCronJob { public const LAST_RUN_TS_SETTING_NAME = 'cron_xapi_res_eval_last_run'; @@ -41,16 +41,11 @@ class ilXapiResultsCronjob extends CronJob protected ilLogger $log; - private \ILIAS\DI\Container $dic; - - public function __construct() + public function init(): void { - global $DIC; /* @var \ILIAS\DI\Container $DIC */ - $this->dic = $DIC; - - $DIC->language()->loadLanguageModule('cmix'); + $this->language->loadLanguageModule('cmix'); - $this->log = ilLoggerFactory::getLogger('cmix'); + $this->log = $this->logger_factory->getComponentLogger('cmix'); $this->initThisRunTS(); $this->readLastRunTS(); @@ -91,12 +86,12 @@ public function getId(): string public function getTitle(): string { - return $this->dic->language()->txt("cron_xapi_results_evaluation"); + return $this->language->txt('cron_xapi_results_evaluation'); } public function getDescription(): string { - return $this->dic->language()->txt("cron_xapi_results_evaluation_desc"); + return $this->language->txt('cron_xapi_results_evaluation_desc'); } public function hasAutoActivation(): bool diff --git a/components/ILIAS/CmiXapi/module.xml b/components/ILIAS/CmiXapi/module.xml index 2406a25b12b2..822525c81ae2 100755 --- a/components/ILIAS/CmiXapi/module.xml +++ b/components/ILIAS/CmiXapi/module.xml @@ -31,10 +31,6 @@ - - - - diff --git a/components/ILIAS/Component/classes/Setup/class.ilComponentDefinitionsStoredObjective.php b/components/ILIAS/Component/classes/Setup/class.ilComponentDefinitionsStoredObjective.php index 1cabac44eaff..1a719b88896e 100755 --- a/components/ILIAS/Component/classes/Setup/class.ilComponentDefinitionsStoredObjective.php +++ b/components/ILIAS/Component/classes/Setup/class.ilComponentDefinitionsStoredObjective.php @@ -144,12 +144,6 @@ public function write(): void new \ilCOPageDefinitionProcessor($db), new \ilComponentInfoDefinitionProcessor(), new \ilLoggingDefinitionProcessor($db), - new \ILIAS\Cron\Setup\DefinitionProcessor( - $db, - $settings_factory->settingsFor(), - $component_repository, - $component_factory - ), new \ilMailTemplateContextDefinitionProcessor($db), new ObjectDefinitionProcessor($db), new \ilSystemCheckDefinitionProcessor($db), diff --git a/components/ILIAS/Course/Course.php b/components/ILIAS/Course/Course.php index 085ff5185c3c..3c5ef4cd5606 100644 --- a/components/ILIAS/Course/Course.php +++ b/components/ILIAS/Course/Course.php @@ -40,5 +40,12 @@ public function init( new \ilCourseSetupAgent( $pull[\ILIAS\Refinery\Factory::class] ); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilTimingsCronReminder( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/Course/classes/class.ilTimingsCronReminder.php b/components/ILIAS/Course/classes/class.ilTimingsCronReminder.php index 88a264feb927..9ab9cfd18d30 100755 --- a/components/ILIAS/Course/classes/class.ilTimingsCronReminder.php +++ b/components/ILIAS/Course/classes/class.ilTimingsCronReminder.php @@ -20,9 +20,9 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; -class ilTimingsCronReminder extends CronJob +class ilTimingsCronReminder extends AbstractCronJob { private static array $objects_information; @@ -31,21 +31,17 @@ class ilTimingsCronReminder extends CronJob private int $now; protected ilLogger $log; - protected ilLanguage $lng; protected ilLanguage $user_lang; protected ilDBInterface $db; protected ilObjectDataCache $obj_data_cache; - /** - * Constructor - */ - public function __construct() + public function init(): void { global $DIC; + $this->language->loadLanguageModule('crs'); + $this->log = $DIC->logger()->crs(); - $this->lng = $DIC->language(); - $this->lng->loadLanguageModule('crs'); $this->db = $DIC->database(); $this->obj_data_cache = $DIC['ilObjDataCache']; @@ -62,12 +58,12 @@ public function getId(): string public function getTitle(): string { - return $this->lng->txt('timings_reminder_notifications'); + return $this->language->txt('timings_reminder_notifications'); } public function getDescription(): string { - return $this->lng->txt('timings_reminder_notifications_info'); + return $this->language->txt('timings_reminder_notifications_info'); } public function getDefaultScheduleType(): JobScheduleType diff --git a/components/ILIAS/Course/module.xml b/components/ILIAS/Course/module.xml index 7fe09d795344..4f60434912ad 100755 --- a/components/ILIAS/Course/module.xml +++ b/components/ILIAS/Course/module.xml @@ -41,9 +41,6 @@ - - - diff --git a/components/ILIAS/Cron/Cron.php b/components/ILIAS/Cron/Cron.php index 86c50929a07b..721a180b8fb5 100644 --- a/components/ILIAS/Cron/Cron.php +++ b/components/ILIAS/Cron/Cron.php @@ -32,9 +32,19 @@ public function init( array | \ArrayAccess &$pull, array | \ArrayAccess &$internal, ): void { - $contribute[\ILIAS\Setup\Agent::class] = fn() => - new \ILIAS\Cron\Setup\Agent( - $pull[\ILIAS\Refinery\Factory::class] + $define[] = \ILIAS\Cron\CronJobRegistry::class; + + $provide[\ILIAS\Cron\CronJobRegistry::class] = static fn() => + $internal[\ILIAS\Cron\InMemoryCronJobRegistry::class]; + + $internal[\ILIAS\Cron\InMemoryCronJobRegistry::class] = static fn() => + new \ILIAS\Cron\InMemoryCronJobRegistry( + $seek[\ILIAS\Cron\CronJob::class] + ); + + $contribute[\ILIAS\Setup\Agent::class] = static fn() => + new \ILIAS\Cron\Setup\CronJobSetupAgent( + $seek[\ILIAS\Cron\CronJob::class] ); } } diff --git a/components/ILIAS/Cron/README.md b/components/ILIAS/Cron/README.md index 48455e007f83..6b7cfe8d0c60 100755 --- a/components/ILIAS/Cron/README.md +++ b/components/ILIAS/Cron/README.md @@ -27,21 +27,30 @@ at some point. ### Providing a Cron-Job -A module or service has to "announce" its cron-jobs to the system by adding them to their respective -module.xml or service.xml. +A component has to "contribute" its cron-jobs to the system by adding them to their respective +component class (the one implementing `\ILIAS\Component\Component`). - The job id has to be unique. -- An optional path can be added if the module/service directory layout differs from the ILIAS standard. +- The cron job must implement `\ILIAS\Cron\CronJob`. ```php - - - ... - - - - +public function init( + array | \ArrayAccess &$define, + array | \ArrayAccess &$implement, + array | \ArrayAccess &$use, + array | \ArrayAccess &$contribute, + array | \ArrayAccess &$seek, + array | \ArrayAccess &$provide, + array | \ArrayAccess &$pull, + array | \ArrayAccess &$internal +): void { + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilMailCronOrphanedMails( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); +} ``` There are 3 basic concepts: cron-job, schedule and cron-result. Using them as intended should make testing @@ -55,7 +64,8 @@ The "condition" of the existing CronCheck would have to be implemented here. Several abstract methods have to be implemented to make a new cron-job usable: -- `getId()`: returns the Id as defined in the module.xml or service.xml +- `getId()`: returns the unique Id of the cron job +- `getComponent()`: returns the component contributing the job - `hasAutoActivation()`: is the cron-job active after "installation" or should it be activated manually? - `hasFlexibleSchedule()`: can the schedule be edited by an adminstrator or is it static? - `getDefaultScheduleType()`: see Schedule diff --git a/components/ILIAS/Cron/ROADMAP.md b/components/ILIAS/Cron/ROADMAP.md index b9842c24c835..3e8e28550e4f 100755 --- a/components/ILIAS/Cron/ROADMAP.md +++ b/components/ILIAS/Cron/ROADMAP.md @@ -11,21 +11,14 @@ could be suggested (needs a Jour Fixe decision). Feature Request: [Define Target Timespan for a Scheduled Cronjob](https://docu.ilias.de/goto_docu_wiki_wpage_5296_1357.html) -### Refactor Registration of Core Cron Jobs +## Past Refactorings -Currently, core cron jobs can be defined in the component XML file. -These files are processed by `\ilCronDefinitionProcessor::beginTag` -and `\ilCronDefinitionProcessor::endTag`, which are called by the -`\ilComponentDefinitionReader`. +### ILIAS 12 -Current Problems: -* `\ilCronJobRepository::getJobInstance` is used in the registration process of a job. -* Certain dependencies (retrieved from `$DIC`) do not exist or are replaced with fake objects during setup, - but the actual services are required in the constructors of the concrete cron job implementations registered. -* There should be an interface segregation for the registration and execution of core cron jobs. -* The problem is currently solved by using the `Reflection API` in the setup context. +**Registration of Core Cron Jobs** -## Past Refactorings +Core cron jobs are now contributed via the component class (`Component::init()`). +The `CronJobRegistry` gathers all contributed jobs. ### ILIAS 8 diff --git a/components/ILIAS/Cron/phpunit.xml b/components/ILIAS/Cron/phpunit.xml index 46365f78cdc9..9224fe9958ae 100755 --- a/components/ILIAS/Cron/phpunit.xml +++ b/components/ILIAS/Cron/phpunit.xml @@ -27,9 +27,7 @@ - classes - interfaces - exceptions + src diff --git a/components/ILIAS/Cron/service.xml b/components/ILIAS/Cron/service.xml index 6e0be1e88bde..6b6f463d3ae8 100755 --- a/components/ILIAS/Cron/service.xml +++ b/components/ILIAS/Cron/service.xml @@ -9,8 +9,5 @@ adm - - - diff --git a/components/ILIAS/Cron/src/AbstractCronJob.php b/components/ILIAS/Cron/src/AbstractCronJob.php new file mode 100644 index 000000000000..5e51f63d02a9 --- /dev/null +++ b/components/ILIAS/Cron/src/AbstractCronJob.php @@ -0,0 +1,330 @@ +component; + } + + public function init(): void + { + } + + private function checkWeeklySchedule(\DateTimeImmutable $last_run, \DateTimeImmutable $now): bool + { + if ($last_run > $now) { + // Defensive check: last run is in the future → don't run again + return false; + } + + // We are using ISO week/year to handle issues with week #52/#53 (see: https://mantis.ilias.de/view.php?id=36118 / https://en.wikipedia.org/wiki/ISO_8601#Week_dates) + return $last_run->format('o-W') !== $now->format('o-W'); + } + + private function checkSchedule( + ?\DateTimeImmutable $last_run, + ?JobScheduleType $schedule_type, + ?int $schedule_value + ): bool { + if (null === $schedule_type) { + return false; + } + + if (null === $last_run) { + return true; + } + + if ($this->date_time_provider === null) { + $now = new \DateTimeImmutable('@' . time(), new \DateTimeZone(date_default_timezone_get())); + } else { + $now = ($this->date_time_provider)(); + } + + switch ($schedule_type) { + case JobScheduleType::DAILY: + $last = $last_run->format('Y-m-d'); + $ref = $now->format('Y-m-d'); + return ($last !== $ref); + + case JobScheduleType::WEEKLY: + return $this->checkWeeklySchedule($last_run, $now); + + case JobScheduleType::MONTHLY: + $last = $last_run->format('Y-n'); + $ref = $now->format('Y-n'); + return ($last !== $ref); + + case JobScheduleType::QUARTERLY: + $last = $last_run->format('Y') . '-' . ceil(((int) $last_run->format('n')) / 3); + $ref = $now->format('Y') . '-' . ceil(((int) $now->format('n')) / 3); + return ($last !== $ref); + + case JobScheduleType::YEARLY: + $last = $last_run->format('Y'); + $ref = $now->format('Y'); + return ($last !== $ref); + + case JobScheduleType::IN_MINUTES: + $diff = floor(($now->getTimestamp() - $last_run->getTimestamp()) / 60); + return ($diff >= $schedule_value); + + case JobScheduleType::IN_HOURS: + $diff = floor(($now->getTimestamp() - $last_run->getTimestamp()) / (60 * 60)); + return ($diff >= $schedule_value); + + case JobScheduleType::IN_DAYS: + $diff = floor(($now->getTimestamp() - $last_run->getTimestamp()) / (60 * 60 * 24)); + return ($diff >= $schedule_value); + } + + return false; + } + + /** + * @param \Closure():\DateTimeInterface|null $date_time_provider + */ + public function setDateTimeProvider(?\Closure $date_time_provider): void + { + if ($date_time_provider !== null) { + $r = new \ReflectionFunction($date_time_provider); + $return_type = $r->getReturnType(); + if ($return_type instanceof \ReflectionNamedType) { + $return_type = $return_type->getName(); + } + $expected_type = \DateTimeInterface::class; + if (!is_subclass_of($return_type, $expected_type)) { + throw new \InvalidArgumentException( + \sprintf( + 'The return type of the datetime provider must be of type %s', + $expected_type + ) + ); + } + + $r = new \ReflectionFunction($date_time_provider); + $parameters = $r->getParameters(); + if ($parameters !== []) { + throw new \InvalidArgumentException( + 'The datetime provider must not define any parameters', + ); + } + } + + $this->date_time_provider = $date_time_provider; + } + + public function isDue( + ?\DateTimeImmutable $last_run, + ?JobScheduleType $schedule_type, + ?int $schedule_value, + bool $is_manually_executed = false + ): bool { + if ($is_manually_executed) { + return true; + } + + if (!$this->hasFlexibleSchedule()) { + $schedule_type = $this->getDefaultScheduleType(); + $schedule_value = $this->getDefaultScheduleValue(); + } + + return $this->checkSchedule($last_run, $schedule_type, $schedule_value); + } + + /** + * Get current schedule type (if flexible) + */ + public function getScheduleType(): ?JobScheduleType + { + if ($this->schedule_type && $this->hasFlexibleSchedule()) { + return $this->schedule_type; + } + + return null; + } + + /** + * Get current schedule value (if flexible) + */ + public function getScheduleValue(): ?int + { + if ($this->schedule_value && $this->hasFlexibleSchedule()) { + return $this->schedule_value; + } + + return null; + } + + /** + * Update current schedule (if flexible) + */ + public function setSchedule(?JobScheduleType $a_type, ?int $a_value): void + { + if ( + $a_value && + $this->hasFlexibleSchedule() && + \in_array($a_type, $this->getValidScheduleTypes(), true) + ) { + $this->schedule_type = $a_type; + $this->schedule_value = $a_value; + } + } + + /** + * Get all available schedule types + * + * @return list + */ + public function getAllScheduleTypes(): array + { + return JobScheduleType::cases(); + } + + /** + * @return list + */ + public function getScheduleTypesWithValues(): array + { + return [ + JobScheduleType::IN_MINUTES, + JobScheduleType::IN_HOURS, + JobScheduleType::IN_DAYS, + ]; + } + + /** + * Returns a collection of all valid schedule types for a specific job + * + * @return list + */ + public function getValidScheduleTypes(): array + { + return $this->getAllScheduleTypes(); + } + + public function isManuallyExecutable(): bool + { + return true; + } + + public function hasCustomSettings(): bool + { + return false; + } + + /** + * @deprecated + */ + #[\Deprecated('Will be removed without any alternative, KS/UI forms will be expected', since: '13.0')] + public function usesLegacyForms(): bool + { + return true; + } + + public function getCustomConfigurationInput( + \ILIAS\UI\Factory $ui_factory, + \ILIAS\Refinery\Factory $factory, + \ilLanguage $lng + ): \ILIAS\UI\Component\Input\Container\Form\FormInput { + throw new \RuntimeException('Not implemented'); + } + + /** + * @deprecated + */ + #[\Deprecated('Will be removed without any alternative, KS/UI forms will be expected', since: '13.0')] + public function addCustomSettingsToForm(\ilPropertyFormGUI $a_form): void + { + } + + /** + * @param mixed $form_data The form data provided by the KS (\ILIAS\UI\Component\Input\Container\Container::getData)). + * The types and structure depend on the structure provided by `getCustomConfigurationInput`. + * It might be a single value or a `array`-like structure. + */ + public function saveCustomConfiguration(mixed $form_data): void + { + throw new \RuntimeException('Not implemented'); + } + + /** + * @deprecated + */ + #[\Deprecated('Will be removed without any alternative, KS/UI forms will be expected', since: '13.0')] + public function saveCustomSettings(\ilPropertyFormGUI $a_form): bool + { + return true; + } + + /** + * @param array $a_fields + */ + public function addToExternalSettingsForm(int $a_form_id, array &$a_fields, bool $a_is_active): void + { + } + + /** + * Important: This method is (also) called from the setup process, where {@see init()} may not have run. + * Furthermore only few dependencies may be available in the $DIC. + */ + public function activationWasToggled(\ilDBInterface $db, \ilSetting $setting, bool $a_currently_active): void + { + } + + abstract public function getId(): string; + + abstract public function getTitle(): string; + + abstract public function getDescription(): string; + + /** + * Is to be activated on "installation", does only work for ILIAS core cron jobs + */ + abstract public function hasAutoActivation(): bool; + + abstract public function hasFlexibleSchedule(): bool; + + abstract public function getDefaultScheduleType(): JobScheduleType; + + abstract public function getDefaultScheduleValue(): ?int; + + abstract public function run(): JobResult; +} diff --git a/components/ILIAS/Cron/src/CronJob.php b/components/ILIAS/Cron/src/CronJob.php index bf9f9b567da1..7e4e9a438dfb 100644 --- a/components/ILIAS/Cron/src/CronJob.php +++ b/components/ILIAS/Cron/src/CronJob.php @@ -23,287 +23,132 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -abstract class CronJob +/** + * A scheduled background job executed by the ILIAS cron subsystem. + * + * Implementations typically extend {@see AbstractCronJob}. + */ +interface CronJob { - protected ?JobScheduleType $schedule_type = null; - protected ?int $schedule_value = null; - protected ?\Closure $date_time_provider = null; - - private function checkWeeklySchedule(\DateTimeImmutable $last_run, \DateTimeImmutable $now): bool - { - if ($last_run > $now) { - // Defensive check: last run is in the future → don't run again - return false; - } - - // We are using ISO week/year to handle issues with week #52/#53 (see: https://mantis.ilias.de/view.php?id=36118 / https://en.wikipedia.org/wiki/ISO_8601#Week_dates) - return $last_run->format('o-W') !== $now->format('o-W'); - } - - private function checkSchedule( - ?\DateTimeImmutable $last_run, - ?JobScheduleType $schedule_type, - ?int $schedule_value - ): bool { - if (null === $schedule_type) { - return false; - } - - if (null === $last_run) { - return true; - } - - if ($this->date_time_provider === null) { - $now = new \DateTimeImmutable('@' . time(), new \DateTimeZone(date_default_timezone_get())); - } else { - $now = ($this->date_time_provider)(); - } - - switch ($schedule_type) { - case JobScheduleType::DAILY: - $last = $last_run->format('Y-m-d'); - $ref = $now->format('Y-m-d'); - return ($last !== $ref); - - case JobScheduleType::WEEKLY: - return $this->checkWeeklySchedule($last_run, $now); - - case JobScheduleType::MONTHLY: - $last = $last_run->format('Y-n'); - $ref = $now->format('Y-n'); - return ($last !== $ref); - - case JobScheduleType::QUARTERLY: - $last = $last_run->format('Y') . '-' . ceil(((int) $last_run->format('n')) / 3); - $ref = $now->format('Y') . '-' . ceil(((int) $now->format('n')) / 3); - return ($last !== $ref); - - case JobScheduleType::YEARLY: - $last = $last_run->format('Y'); - $ref = $now->format('Y'); - return ($last !== $ref); - - case JobScheduleType::IN_MINUTES: - $diff = floor(($now->getTimestamp() - $last_run->getTimestamp()) / 60); - return ($diff >= $schedule_value); - - case JobScheduleType::IN_HOURS: - $diff = floor(($now->getTimestamp() - $last_run->getTimestamp()) / (60 * 60)); - return ($diff >= $schedule_value); - - case JobScheduleType::IN_DAYS: - $diff = floor(($now->getTimestamp() - $last_run->getTimestamp()) / (60 * 60 * 24)); - return ($diff >= $schedule_value); - } + /** + * ILIAS component root class name contributed from `.php`. + */ + public function getComponent(): string; - return false; - } + /** + * Component-specific initialization (former constructor body). Invoked when a job is prepared + * for execution. Once the jobs are properly constructed via ".php", this is obsolete. + */ + public function init(): void; /** * @param \Closure():\DateTimeInterface|null $date_time_provider */ - public function setDateTimeProvider(?\Closure $date_time_provider): void - { - if ($date_time_provider !== null) { - $r = new \ReflectionFunction($date_time_provider); - $return_type = $r->getReturnType(); - if ($return_type instanceof \ReflectionNamedType) { - $return_type = $return_type->getName(); - } - $expected_type = \DateTimeInterface::class; - if (!is_subclass_of($return_type, $expected_type)) { - throw new \InvalidArgumentException( - \sprintf( - 'The return type of the datetime provider must be of type %s', - $expected_type - ) - ); - } - - $r = new \ReflectionFunction($date_time_provider); - $parameters = $r->getParameters(); - if ($parameters !== []) { - throw new \InvalidArgumentException( - 'The datetime provider must not define any parameters', - ); - } - } - - $this->date_time_provider = $date_time_provider; - } + public function setDateTimeProvider(?\Closure $date_time_provider): void; public function isDue( ?\DateTimeImmutable $last_run, ?JobScheduleType $schedule_type, ?int $schedule_value, bool $is_manually_executed = false - ): bool { - if ($is_manually_executed) { - return true; - } - - if (!$this->hasFlexibleSchedule()) { - $schedule_type = $this->getDefaultScheduleType(); - $schedule_value = $this->getDefaultScheduleValue(); - } - - return $this->checkSchedule($last_run, $schedule_type, $schedule_value); - } + ): bool; /** * Get current schedule type (if flexible) */ - public function getScheduleType(): ?JobScheduleType - { - if ($this->schedule_type && $this->hasFlexibleSchedule()) { - return $this->schedule_type; - } - - return null; - } + public function getScheduleType(): ?JobScheduleType; /** * Get current schedule value (if flexible) */ - public function getScheduleValue(): ?int - { - if ($this->schedule_value && $this->hasFlexibleSchedule()) { - return $this->schedule_value; - } - - return null; - } + public function getScheduleValue(): ?int; /** * Update current schedule (if flexible) */ - public function setSchedule(?JobScheduleType $a_type, ?int $a_value): void - { - if ( - $a_value && - $this->hasFlexibleSchedule() && - \in_array($a_type, $this->getValidScheduleTypes(), true) - ) { - $this->schedule_type = $a_type; - $this->schedule_value = $a_value; - } - } + public function setSchedule(?JobScheduleType $a_type, ?int $a_value): void; /** * Get all available schedule types + * * @return list */ - public function getAllScheduleTypes(): array - { - return JobScheduleType::cases(); - } + public function getAllScheduleTypes(): array; /** * @return list */ - public function getScheduleTypesWithValues(): array - { - return [ - JobScheduleType::IN_MINUTES, - JobScheduleType::IN_HOURS, - JobScheduleType::IN_DAYS, - ]; - } + public function getScheduleTypesWithValues(): array; /** * Returns a collection of all valid schedule types for a specific job + * * @return list */ - public function getValidScheduleTypes(): array - { - return $this->getAllScheduleTypes(); - } + public function getValidScheduleTypes(): array; - public function isManuallyExecutable(): bool - { - return true; - } + public function isManuallyExecutable(): bool; - public function hasCustomSettings(): bool - { - return false; - } + public function hasCustomSettings(): bool; /** * @deprecated */ #[\Deprecated('Will be removed without any alternative, KS/UI forms will be expected', since: '11.0')] - public function usesLegacyForms(): bool - { - return true; - } + public function usesLegacyForms(): bool; public function getCustomConfigurationInput( \ILIAS\UI\Factory $ui_factory, \ILIAS\Refinery\Factory $factory, \ilLanguage $lng - ): \ILIAS\UI\Component\Input\Container\Form\FormInput { - throw new \RuntimeException('Not implemented'); - } + ): \ILIAS\UI\Component\Input\Container\Form\FormInput; /** * @deprecated */ #[\Deprecated('Will be removed without any alternative, KS/UI forms will be expected', since: '11.0')] - public function addCustomSettingsToForm(\ilPropertyFormGUI $a_form): void - { - } + public function addCustomSettingsToForm(\ilPropertyFormGUI $a_form): void; /** * @param mixed $form_data The form data provided by the KS (\ILIAS\UI\Component\Input\Container\Container::getData)). * The types and structure depend on the structure provided by `getCustomConfigurationInput`. * It might be a single value or a `array`-like structure. */ - public function saveCustomConfiguration(mixed $form_data): void - { - throw new \RuntimeException('Not implemented'); - } + public function saveCustomConfiguration(mixed $form_data): void; /** * @deprecated */ #[\Deprecated('Will be removed without any alternative, KS/UI forms will be expected', since: '11.0')] - public function saveCustomSettings(\ilPropertyFormGUI $a_form): bool - { - return true; - } + public function saveCustomSettings(\ilPropertyFormGUI $a_form): bool; /** * @param array $a_fields */ - public function addToExternalSettingsForm(int $a_form_id, array &$a_fields, bool $a_is_active): void - { - } + public function addToExternalSettingsForm(int $a_form_id, array &$a_fields, bool $a_is_active): void; /** - * Important: This method is (also) called from the setup process, where the constructor of an ilCronJob ist NOT executed. + * Important: This method is (also) called from the setup process, where {@see init()} may not have run. * Furthermore only few dependencies may be available in the $DIC. */ - public function activationWasToggled(\ilDBInterface $db, \ilSetting $setting, bool $a_currently_active): void - { - } + public function activationWasToggled(\ilDBInterface $db, \ilSetting $setting, bool $a_currently_active): void; - abstract public function getId(): string; + public function getId(): string; - abstract public function getTitle(): string; + public function getTitle(): string; - abstract public function getDescription(): string; + public function getDescription(): string; /** * Is to be activated on "installation", does only work for ILIAS core cron jobs */ - abstract public function hasAutoActivation(): bool; + public function hasAutoActivation(): bool; - abstract public function hasFlexibleSchedule(): bool; + public function hasFlexibleSchedule(): bool; - abstract public function getDefaultScheduleType(): JobScheduleType; + public function getDefaultScheduleType(): JobScheduleType; - abstract public function getDefaultScheduleValue(): ?int; + public function getDefaultScheduleValue(): ?int; - abstract public function run(): JobResult; + public function run(): JobResult; } diff --git a/components/ILIAS/Cron/src/CronHookPlugin.php b/components/ILIAS/Cron/src/CronJobRegistry.php similarity index 72% rename from components/ILIAS/Cron/src/CronHookPlugin.php rename to components/ILIAS/Cron/src/CronJobRegistry.php index 651b1fb99264..7a82668a3731 100644 --- a/components/ILIAS/Cron/src/CronHookPlugin.php +++ b/components/ILIAS/Cron/src/CronJobRegistry.php @@ -20,8 +20,13 @@ namespace ILIAS\Cron; -use ILIAS\Cron\Job\JobProvider; - -abstract class CronHookPlugin extends \ilPlugin implements JobProvider +/** + * All {@see CronJob} instances contributed by components (see Component::init() contributions). + */ +interface CronJobRegistry { + /** + * @return list + */ + public function getAllJobs(): array; } diff --git a/components/ILIAS/Cron/src/InMemoryCronJobRegistry.php b/components/ILIAS/Cron/src/InMemoryCronJobRegistry.php new file mode 100644 index 000000000000..d5ad1a547ee8 --- /dev/null +++ b/components/ILIAS/Cron/src/InMemoryCronJobRegistry.php @@ -0,0 +1,51 @@ + $jobs + */ + public function __construct( + private readonly array $jobs + ) { + $seen = []; + foreach ($this->jobs as $job) { + $id = $job->getId(); + + if ($id === '') { + throw new \InvalidArgumentException('Cron job id must not be empty.'); + } + + if (isset($seen[$id])) { + throw new \LogicException('Duplicate cron job id contributed: ' . $id); + } + + $seen[$id] = true; + } + } + + public function getAllJobs(): array + { + return $this->jobs; + } +} diff --git a/components/ILIAS/Cron/src/Job/JobEntity.php b/components/ILIAS/Cron/src/Job/JobEntity.php index d32847f4c491..fa0a738debbe 100644 --- a/components/ILIAS/Cron/src/Job/JobEntity.php +++ b/components/ILIAS/Cron/src/Job/JobEntity.php @@ -21,6 +21,7 @@ namespace ILIAS\Cron\Job; use ILIAS\Cron\Job\Schedule\JobScheduleType; +use ILIAS\Cron\CronJob; class JobEntity { @@ -49,21 +50,20 @@ class JobEntity /** * @param array $record */ - public function __construct( - private readonly \ILIAS\Cron\CronJob $job, - array $record, - private readonly bool $isPlugin = false - ) { - $this->mapRecord($record); + public function __construct(private readonly CronJob $job, array $record) + { + $job->init(); + + $this->mapRecord($job, $record); } /** * @param array $record */ - private function mapRecord(array $record): void + private function mapRecord(CronJob $job, array $record): void { - $this->job_id = (string) $record['job_id']; - $this->component = (string) $record['component']; + $this->job_id = $job->getId(); + $this->component = $job->getComponent(); $this->schedule_type = is_numeric($record['schedule_type']) ? JobScheduleType::tryFrom( (int) $record['schedule_type'] ) : null; @@ -87,7 +87,7 @@ private function mapRecord(array $record): void $this->alive_timestamp = (int) $record['alive_ts']; } - public function getJob(): \ILIAS\Cron\CronJob + public function getJob(): CronJob { return $this->job; } @@ -97,16 +97,6 @@ public function getJobId(): string return $this->job_id; } - public function getEffectiveJobId(): string - { - $job_id = $this->getJobId(); - if ($this->isPlugin()) { - $job_id = 'pl__' . $this->getComponent() . '__' . $job_id; - } - - return $job_id; - } - public function getComponent(): string { return $this->component; @@ -207,11 +197,6 @@ public function getAliveTimestamp(): int return $this->alive_timestamp; } - public function isPlugin(): bool - { - return $this->isPlugin; - } - public function getEffectiveScheduleType(): JobScheduleType { $type = $this->getScheduleType(); @@ -236,11 +221,8 @@ public function getEffectiveScheduleValue(): int public function getEffectiveTitle(): string { $id = $this->getJobId(); - if ($this->isPlugin()) { - $id = 'pl__' . $this->getComponent() . '__' . $id; - } - $title = $this->getJob()->getTitle(); + if ($title === '') { $title = $id; } diff --git a/components/ILIAS/Cron/src/Job/JobManager.php b/components/ILIAS/Cron/src/Job/JobManager.php index 38983b2f5eca..9e491eb7ea1e 100644 --- a/components/ILIAS/Cron/src/Job/JobManager.php +++ b/components/ILIAS/Cron/src/Job/JobManager.php @@ -24,17 +24,17 @@ interface JobManager { public function runActiveJobs(\ilObjUser $actor): void; - public function runJobManual(string $jobId, \ilObjUser $actor): bool; + public function runJobManual(string $id, \ilObjUser $actor): bool; public function resetJob(\ILIAS\Cron\CronJob $job, \ilObjUser $actor): void; - public function activateJob(\ILIAS\Cron\CronJob $job, \ilObjUser $actor, bool $wasManuallyExecuted = false): void; + public function activateJob(\ILIAS\Cron\CronJob $job, \ilObjUser $actor, bool $was_manually_executed = false): void; - public function deactivateJob(\ILIAS\Cron\CronJob $job, \ilObjUser $actor, bool $wasManuallyExecuted = false): void; + public function deactivateJob(\ILIAS\Cron\CronJob $job, \ilObjUser $actor, bool $was_manually_executed = false): void; - public function isJobActive(string $jobId): bool; + public function isJobActive(string $id): bool; - public function isJobInactive(string $jobId): bool; + public function isJobInactive(string $id): bool; - public function ping(string $jobId): void; + public function ping(string $id): void; } diff --git a/components/ILIAS/Cron/src/Job/JobRepository.php b/components/ILIAS/Cron/src/Job/JobRepository.php index ed83f47e20d5..df30b9843d91 100644 --- a/components/ILIAS/Cron/src/Job/JobRepository.php +++ b/components/ILIAS/Cron/src/Job/JobRepository.php @@ -22,37 +22,49 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; +/** + * @phpstan-type CronJobRecord array{ + * job_id: string, + * component: string|null, + * schedule_type: int|null, + * schedule_value: int|null, + * job_status: int|null, + * job_status_user_id: int|null, + * job_status_type: int|null, + * job_status_ts: int|null, + * job_result_status: int|null, + * job_result_user_id: int|null, + * job_result_code: string|null, + * job_result_message: string|null, + * job_result_type: int|null, + * job_result_ts: int|null, + * class: string|null, + * running_ts: int|null, + * job_result_dur: int|null, + * alive_ts: int|null + * } + */ interface JobRepository { public function getJobInstanceById(string $id): ?\ILIAS\Cron\CronJob; public function getJobInstance( - string $a_id, - string $a_component, - string $a_class, - bool $isCreationContext = false + string $id, + string $component, + string $class, ): ?\ILIAS\Cron\CronJob; /** * Get cron job configuration/execution data - * @param list|string|null $id - * @return list> - */ - public function getCronJobData($id = null, bool $withInactiveJobsIncluded = true): array; - - public function registerJob(string $a_component, string $a_id, string $a_class, ?string $a_path): void; - - /** - * @param list $a_xml_job_ids + * @param null|list|string $id + * @return list */ - public function unregisterJob(string $a_component, array $a_xml_job_ids): void; - - public function createDefaultEntry(\ILIAS\Cron\CronJob $job, string $component, string $class, ?string $path): void; + public function getCronJobData(null|array|string $id = null, bool $with_inactive_jobs_included = true): array; /** - * @return array}> + * Ensures all jobs from the component registry exist in persistence, also removes obsolete jobs. */ - public function getPluginJobs(bool $withOnlyActive = false): array; + public function syncJobsFromRegistry(): void; public function resetJob(\ILIAS\Cron\CronJob $job): void; @@ -61,25 +73,29 @@ public function updateJobResult( \DateTimeImmutable $when, \ilObjUser $actor, JobResult $result, - bool $wasManualExecution = false + bool $was_manual_execution = false ): void; - public function updateRunInformation(string $jobId, int $runningTimestamp, int $aliveTimestamp): void; + public function updateRunInformation(string $id, int $running_timestamp, int $alive_timestamp): void; - public function updateJobSchedule(\ILIAS\Cron\CronJob $job, ?JobScheduleType $scheduleType, ?int $scheduleValue): void; + public function updateJobSchedule( + \ILIAS\Cron\CronJob $job, + ?JobScheduleType $schedule_type, + ?int $schedule_value + ): void; public function activateJob( \ILIAS\Cron\CronJob $job, \DateTimeImmutable $when, \ilObjUser $actor, - bool $wasManuallyExecuted = false + bool $was_manually_executed = false ): void; public function deactivateJob( \ILIAS\Cron\CronJob $job, \DateTimeImmutable $when, \ilObjUser $actor, - bool $wasManuallyExecuted = false + bool $was_manually_executed = false ): void; public function findAll(): JobCollection; diff --git a/components/ILIAS/Cron/src/Job/Manager/JobManagerImpl.php b/components/ILIAS/Cron/src/Job/Manager/JobManagerImpl.php index 1668de1a9218..4d344f36f8ff 100644 --- a/components/ILIAS/Cron/src/Job/Manager/JobManagerImpl.php +++ b/components/ILIAS/Cron/src/Job/Manager/JobManagerImpl.php @@ -23,6 +23,9 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobRepository; +/** + * @phpstan-import-type CronJobRecord from JobRepository + */ readonly class JobManagerImpl implements \ILIAS\Cron\Job\JobManager { public function __construct( @@ -69,7 +72,6 @@ public function runActiveJobs(\ilObjUser $actor): void \define('ILIAS_HTTP_PATH', \ilUtil::_getHttpPath()); } - // system foreach ($this->job_repository->getCronJobData(null, false) as $row) { $job = $this->job_repository->getJobInstanceById($row['job_id']); if ($job instanceof \ILIAS\Cron\CronJob) { @@ -78,67 +80,61 @@ public function runActiveJobs(\ilObjUser $actor): void } } - // plugins - foreach ($this->job_repository->getPluginJobs(true) as $item) { - // #18411 - we are NOT using the initial job data as it might be outdated at this point - $this->runJob($item[0], $actor); - } - $this->logger->info('CRON - batch end'); } - public function runJobManual(string $jobId, \ilObjUser $actor): bool + public function runJobManual(string $id, \ilObjUser $actor): bool { $result = false; - $this->logger->info('CRON - manual start (' . $jobId . ')'); + $this->logger->info('CRON - manual start (' . $id . ')'); - $job = $this->job_repository->getJobInstanceById($jobId); + $job = $this->job_repository->getJobInstanceById($id); if ($job instanceof \ILIAS\Cron\CronJob) { if ($job->isManuallyExecutable()) { $result = $this->runJob($job, $actor, null, true); } else { - $this->logger->info('CRON - job ' . $jobId . ' is not intended to be executed manually'); + $this->logger->info('CRON - job ' . $id . ' is not intended to be executed manually'); } } else { - $this->logger->info('CRON - job ' . $jobId . ' seems invalid or is inactive'); + $this->logger->info('CRON - job ' . $id . ' seems invalid or is inactive'); } - $this->logger->info('CRON - manual end (' . $jobId . ')'); + $this->logger->info('CRON - manual end (' . $id . ')'); return $result; } /** * Run single cron job (internal) - * @param null|array $jobData + * @param null|CronJobRecord $job_data * @internal */ private function runJob( \ILIAS\Cron\CronJob $job, \ilObjUser $actor, - ?array $jobData = null, - bool $isManualExecution = false + ?array $job_data = null, + bool $is_manually_executed = false ): bool { $did_run = false; - if ($jobData === null) { + if ($job_data === null) { // aquire "fresh" job (status) data $jobsData = $this->job_repository->getCronJobData($job->getId()); - $jobData = array_pop($jobsData); + $job_data = array_pop($jobsData); } $job->setDateTimeProvider(fn(): \DateTimeImmutable => $this->clock_factory->system()->now()); // already running? - if ($jobData['alive_ts']) { - $this->logger->info('CRON - job ' . $jobData['job_id'] . ' still running'); + if ($job_data['alive_ts']) { + $this->logger->info('CRON - job ' . $job_data['job_id'] . ' still running'); $cut = 60 * 60 * 3; // is running (and has not pinged) for 3 hours straight, we assume it crashed - if ($this->clock_factory->system()->now()->getTimestamp() - ((int) $jobData['alive_ts']) > $cut) { - $this->job_repository->updateRunInformation($jobData['job_id'], 0, 0); + if ($this->clock_factory->system()->now()->getTimestamp() - ((int) $job_data['alive_ts']) > $cut) { + $this->job_repository->updateRunInformation($job_data['job_id'], 0, 0); $this->deactivateJob($job, $actor); // #13082 $result = new \ILIAS\Cron\Job\JobResult(); @@ -151,32 +147,33 @@ private function runJob( $this->clock_factory->system()->now(), $actor, $result, - $isManualExecution + $is_manually_executed ); - $this->logger->info('CRON - job ' . $jobData['job_id'] . ' deactivated (assumed crash)'); + $this->logger->info('CRON - job ' . $job_data['job_id'] . ' deactivated (assumed crash)'); } } // initiate run? elseif ($job->isDue( - $jobData['job_result_ts'] ? (new \DateTimeImmutable( - '@' . $jobData['job_result_ts'] - ))->setTimezone($this->clock_factory->system()->now()->getTimezone()) : null, - is_numeric($jobData['schedule_type']) ? JobScheduleType::tryFrom( - (int) $jobData['schedule_type'] + $job_data['job_result_ts'] ? new \DateTimeImmutable( + '@' . $job_data['job_result_ts'] + )->setTimezone($this->clock_factory->system()->now()->getTimezone()) : null, + is_numeric($job_data['schedule_type']) ? JobScheduleType::tryFrom( + (int) $job_data['schedule_type'] ) : null, - $jobData['schedule_value'] ? (int) $jobData['schedule_value'] : null, - $isManualExecution + $job_data['schedule_value'] ? (int) $job_data['schedule_value'] : null, + $is_manually_executed )) { - $this->logger->info('CRON - job ' . $jobData['job_id'] . ' started'); + $this->logger->info('CRON - job ' . $job_data['job_id'] . ' started'); $this->job_repository->updateRunInformation( - $jobData['job_id'], + $job_data['job_id'], $this->clock_factory->system()->now()->getTimestamp(), $this->clock_factory->system()->now()->getTimestamp() ); $ts_in = $this->getMicrotime(); try { + $job->init(); $result = $job->run(); } catch (\Throwable $e) { $result = new \ILIAS\Cron\Job\JobResult(); @@ -193,7 +190,7 @@ private function runJob( if ($result->getStatus() === \ILIAS\Cron\Job\JobResult::STATUS_INVALID_CONFIGURATION) { $this->deactivateJob($job, $actor); - $this->logger->info('CRON - job ' . $jobData['job_id'] . ' invalid configuration'); + $this->logger->info('CRON - job ' . $job_data['job_id'] . ' invalid configuration'); } else { // success! $did_run = true; @@ -206,13 +203,13 @@ private function runJob( $this->clock_factory->system()->now(), $actor, $result, - $isManualExecution + $is_manually_executed ); - $this->job_repository->updateRunInformation($jobData['job_id'], 0, 0); + $this->job_repository->updateRunInformation($job_data['job_id'], 0, 0); - $this->logger->info('CRON - job ' . $jobData['job_id'] . ' finished'); + $this->logger->info('CRON - job ' . $job_data['job_id'] . ' finished'); } else { - $this->logger->info('CRON - job ' . $jobData['job_id'] . ' returned status inactive'); + $this->logger->info('CRON - job ' . $job_data['job_id'] . ' returned status inactive'); } return $did_run; @@ -237,38 +234,38 @@ public function resetJob(\ILIAS\Cron\CronJob $job, \ilObjUser $actor): void $this->activateJob($job, $actor, true); } - public function activateJob(\ILIAS\Cron\CronJob $job, \ilObjUser $actor, bool $wasManuallyExecuted = false): void + public function activateJob(\ILIAS\Cron\CronJob $job, \ilObjUser $actor, bool $was_manually_executed = false): void { - $this->job_repository->activateJob($job, $this->clock_factory->system()->now(), $actor, $wasManuallyExecuted); + $this->job_repository->activateJob($job, $this->clock_factory->system()->now(), $actor, $was_manually_executed); $job->activationWasToggled($this->db, $this->settings, true); } - public function deactivateJob(\ILIAS\Cron\CronJob $job, \ilObjUser $actor, bool $wasManuallyExecuted = false): void + public function deactivateJob(\ILIAS\Cron\CronJob $job, \ilObjUser $actor, bool $was_manually_executed = false): void { - $this->job_repository->deactivateJob($job, $this->clock_factory->system()->now(), $actor, $wasManuallyExecuted); + $this->job_repository->deactivateJob($job, $this->clock_factory->system()->now(), $actor, $was_manually_executed); $job->activationWasToggled($this->db, $this->settings, false); } - public function isJobActive(string $jobId): bool + public function isJobActive(string $id): bool { - $jobs_data = $this->job_repository->getCronJobData($jobId); + $jobs_data = $this->job_repository->getCronJobData($id); return $jobs_data !== [] && $jobs_data[0]['job_status']; } - public function isJobInactive(string $jobId): bool + public function isJobInactive(string $id): bool { - $jobs_data = $this->job_repository->getCronJobData($jobId); + $jobs_data = $this->job_repository->getCronJobData($id); return $jobs_data !== [] && !((bool) $jobs_data[0]['job_status']); } - public function ping(string $jobId): void + public function ping(string $id): void { $this->db->manipulateF( 'UPDATE cron_job SET alive_ts = %s WHERE job_id = %s', ['integer', 'text'], - [$this->clock_factory->system()->now()->getTimestamp(), $jobId] + [$this->clock_factory->system()->now()->getTimestamp(), $id] ); } } diff --git a/components/ILIAS/Cron/src/Job/Manager/StrictCliJobManager.php b/components/ILIAS/Cron/src/Job/Manager/StrictCliJobManager.php index e3a363edaa29..00ca31ba8b60 100644 --- a/components/ILIAS/Cron/src/Job/Manager/StrictCliJobManager.php +++ b/components/ILIAS/Cron/src/Job/Manager/StrictCliJobManager.php @@ -45,9 +45,9 @@ public function runActiveJobs(\ilObjUser $actor): void } } - public function runJobManual(string $jobId, \ilObjUser $actor): bool + public function runJobManual(string $id, \ilObjUser $actor): bool { - return $this->job_manager->runJobManual($jobId, $actor); + return $this->job_manager->runJobManual($id, $actor); } public function resetJob(\ILIAS\Cron\CronJob $job, \ilObjUser $actor): void @@ -55,28 +55,28 @@ public function resetJob(\ILIAS\Cron\CronJob $job, \ilObjUser $actor): void $this->job_manager->resetJob($job, $actor); } - public function activateJob(\ILIAS\Cron\CronJob $job, \ilObjUser $actor, bool $wasManuallyExecuted = false): void + public function activateJob(\ILIAS\Cron\CronJob $job, \ilObjUser $actor, bool $was_manually_executed = false): void { - $this->job_manager->activateJob($job, $actor, $wasManuallyExecuted); + $this->job_manager->activateJob($job, $actor, $was_manually_executed); } - public function deactivateJob(\ILIAS\Cron\CronJob $job, \ilObjUser $actor, bool $wasManuallyExecuted = false): void + public function deactivateJob(\ILIAS\Cron\CronJob $job, \ilObjUser $actor, bool $was_manually_executed = false): void { - $this->job_manager->deactivateJob($job, $actor, $wasManuallyExecuted); + $this->job_manager->deactivateJob($job, $actor, $was_manually_executed); } - public function isJobActive(string $jobId): bool + public function isJobActive(string $id): bool { - return $this->job_manager->isJobActive($jobId); + return $this->job_manager->isJobActive($id); } - public function isJobInactive(string $jobId): bool + public function isJobInactive(string $id): bool { - return $this->job_manager->isJobInactive($jobId); + return $this->job_manager->isJobInactive($id); } - public function ping(string $jobId): void + public function ping(string $id): void { - $this->job_manager->ping($jobId); + $this->job_manager->ping($id); } } diff --git a/components/ILIAS/Cron/src/Job/Manager/UI/JobTable.php b/components/ILIAS/Cron/src/Job/Manager/UI/JobTable.php index f084aa92b2af..1b1d5614545d 100644 --- a/components/ILIAS/Cron/src/Job/Manager/UI/JobTable.php +++ b/components/ILIAS/Cron/src/Job/Manager/UI/JobTable.php @@ -104,7 +104,7 @@ public function getRows( ); yield $row_builder - ->buildDataRow($item->getEffectiveJobId(), $record) + ->buildDataRow($item->getJobId(), $record) ->withDisabledAction('run', !$may_run) ->withDisabledAction('activate', !$may_activate) ->withDisabledAction('deactivate', !$may_deactivate) @@ -180,7 +180,7 @@ private function getRecords(\ILIAS\Data\Range $range, \ILIAS\Data\Order $order): private function formatTitle(JobEntity $entity): string { $title = implode('', [ - '', + '', $entity->getEffectiveTitle(), '' ]); @@ -222,12 +222,7 @@ private function formatSchedule(JobEntity $entity): string public function formatComponent(JobEntity $entity): string { - $component = $entity->getComponent(); - if ($entity->isPlugin()) { - $component = $this->lng->txt('cmps_plugin') . '/' . $component; - } - - return $component; + return $entity->getComponent(); } private function formatStatusInfo(JobEntity $entity): string diff --git a/components/ILIAS/Cron/src/Job/Manager/UI/JobTableFilterMediator.php b/components/ILIAS/Cron/src/Job/Manager/UI/JobTableFilterMediator.php index 095c326689a0..11b1831bd363 100644 --- a/components/ILIAS/Cron/src/Job/Manager/UI/JobTableFilterMediator.php +++ b/components/ILIAS/Cron/src/Job/Manager/UI/JobTableFilterMediator.php @@ -50,23 +50,25 @@ public function __construct( public function filter(string $action): Standard { - $componentOptions = array_unique( - array_map(function (JobEntity $entity): string { - if ($entity->isPlugin()) { - return $this->lng->txt('cmps_plugin') . '/' . $entity->getComponent(); - } - + $component_options = array_unique( + array_map(static function (JobEntity $entity): string { return $entity->getComponent(); }, $this->items->toArray()) ); - asort($componentOptions); + asort($component_options); $title_and_desc = $this->uiFactory->input()->field()->text( $this->lng->txt('title') . ' / ' . $this->lng->txt('description') ); $components = $this->uiFactory->input()->field()->select( $this->lng->txt('cron_component'), - array_combine($componentOptions, $componentOptions) + array_combine( + array_map( + fn(string $component): string => $this->encodeComponent($component), + $component_options + ), + $component_options + ) ); $schedule = $this->uiFactory->input()->field()->select( $this->lng->txt('cron_schedule'), @@ -156,12 +158,7 @@ public function filteredJobs(Standard $filter): \ILIAS\Cron\Job\JobCollection if (isset($filter_values[self::FILTER_PROPERTY_NAME_COMPONENT]) && \is_string($filter_values[self::FILTER_PROPERTY_NAME_COMPONENT]) && $filter_values[self::FILTER_PROPERTY_NAME_COMPONENT] !== '') { - $component = $entity->getComponent(); - if ($entity->isPlugin()) { - $component = $this->lng->txt('cmps_plugin') . '/' . $component; - } - - if ($filter_values[self::FILTER_PROPERTY_NAME_COMPONENT] !== $component) { + if ($filter_values[self::FILTER_PROPERTY_NAME_COMPONENT] !== $this->encodeComponent($entity->getComponent())) { return false; } } @@ -202,4 +199,9 @@ public function filteredJobs(Standard $filter): \ILIAS\Cron\Job\JobCollection return true; }); } + + private function encodeComponent(string $component): string + { + return base64_encode($component); + } } diff --git a/components/ILIAS/Cron/src/Job/Repository/JobRepositoryImpl.php b/components/ILIAS/Cron/src/Job/Repository/JobRepositoryImpl.php index cab2cdde2176..e3cf7ba345bd 100644 --- a/components/ILIAS/Cron/src/Job/Repository/JobRepositoryImpl.php +++ b/components/ILIAS/Cron/src/Job/Repository/JobRepositoryImpl.php @@ -20,65 +20,35 @@ namespace ILIAS\Cron\Job\Repository; +use ILIAS\Cron\CronJobRegistry; use ILIAS\Cron\Job\JobRepository; use ILIAS\Cron\Job\Schedule\JobScheduleType; +use ILIAS\Cron\Job\JobEntity; +use ILIAS\Cron\CronJob; readonly class JobRepositoryImpl implements JobRepository { - private const string TYPE_PLUGINS = 'Plugins'; - public function __construct( + private CronJobRegistry $registry, private \ilDBInterface $db, private \ilSetting $setting, private \ilLogger $logger, private \ilComponentRepository $component_repository, - private \ilComponentFactory $component_factory + private \ilComponentFactory $component_factory, + private \ILIAS\Language\Language $language, + private \ILIAS\Logging\LoggerFactory $logger_factory, ) { } - public function getJobInstanceById(string $id): ?\ILIAS\Cron\CronJob + public function getJobInstanceById(string $id): ?CronJob { - // plugin - if (str_starts_with($id, 'pl__')) { - $parts = explode('__', $id); - $pl_name = $parts[1]; - $job_id = $parts[2]; - - foreach ($this->component_repository->getPlugins() as $pl) { - if ($pl->getName() !== $pl_name || !$pl->isActive()) { - continue; - } - - $plugin = $this->component_factory->getPlugin($pl->getId()); - if (!$plugin instanceof \ILIAS\Cron\Job\JobProvider) { - continue; - } - - try { - $job = $plugin->getCronJobInstance($job_id); - - // should never happen but who knows... - $jobs_data = $this->getCronJobData($job_id); - if ($jobs_data === []) { - // as job is not 'imported' from xml - $this->createDefaultEntry($job, $pl_name, self::TYPE_PLUGINS, ''); - } - - return $job; - } catch (\OutOfBoundsException) { - // Maybe a job was removed from plugin, renamed etc. - } - break; - } - } else { - $jobs_data = $this->getCronJobData($id); - if ($jobs_data !== [] && $jobs_data[0]['job_id'] === $id) { - return $this->getJobInstance( - $jobs_data[0]['job_id'], - $jobs_data[0]['component'], - $jobs_data[0]['class'] - ); - } + $jobs_data = $this->getCronJobData($id); + if ($jobs_data !== [] && $jobs_data[0]['job_id'] === $id) { + return $this->getJobInstance( + $jobs_data[0]['job_id'], + $jobs_data[0]['component'], + $jobs_data[0]['class'], + ); } $this->logger->info('CRON - job ' . $id . ' seems invalid or is inactive'); @@ -87,20 +57,18 @@ public function getJobInstanceById(string $id): ?\ILIAS\Cron\CronJob } public function getJobInstance( - string $a_id, - string $a_component, - string $a_class, - bool $isCreationContext = false - ): ?\ILIAS\Cron\CronJob { - if (class_exists($a_class)) { - if ($isCreationContext) { - $refl = new \ReflectionClass($a_class); - $job = $refl->newInstanceWithoutConstructor(); - } else { - $job = new $a_class(); - } + string $id, + string $component, + string $class, + ): ?CronJob { + if (class_exists($class)) { + $job = new $class( + $component, + $this->language, + $this->logger_factory + ); - if ($job instanceof \ILIAS\Cron\CronJob && $job->getId() === $a_id) { + if ($job instanceof CronJob && $job->getId() === $id) { return $job; } } @@ -108,94 +76,82 @@ public function getJobInstance( return null; } - public function getCronJobData($id = null, bool $withInactiveJobsIncluded = true): array + public function getCronJobData(null|array|string $id = null, bool $with_inactive_jobs_included = true): array { - $jobData = []; - if ($id && !\is_array($id)) { $id = [$id]; } + if ($id && !array_is_list($id)) { + throw new \InvalidArgumentException('Job IDs must be provided as an array or a single string'); + } + $query = 'SELECT * FROM cron_job'; $where = []; if ($id) { $where[] = $this->db->in('job_id', $id, false, \ilDBConstants::T_TEXT); - } else { - $where[] = 'class != ' . $this->db->quote(self::TYPE_PLUGINS, \ilDBConstants::T_TEXT); } - if (!$withInactiveJobsIncluded) { + if (!$with_inactive_jobs_included) { $where[] = 'job_status = ' . $this->db->quote(1, \ilDBConstants::T_INTEGER); } if ($where !== []) { $query .= ' WHERE ' . implode(' AND ', $where); } - // :TODO: discuss job execution order + // TODO: discuss job execution order $query .= ' ORDER BY job_id'; $res = $this->db->query($query); + $job_data = []; while ($row = $this->db->fetchAssoc($res)) { - $jobData[] = $row; + $job_data[] = $row; } - return $jobData; + return $job_data; } - public function registerJob( - string $a_component, - string $a_id, - string $a_class, - ?string $a_path - ): void { + public function syncJobsFromRegistry(): void + { + $keep_ids = []; + foreach ($this->registry->getAllJobs() as $job) { + $this->registerJob($job); + $keep_ids[] = $job->getId(); + } + + $this->deleteJobsNotIn($keep_ids); + } + + private function registerJob(CronJob $job): void + { if (!$this->db->tableExists('cron_job')) { return; } - $job = $this->getJobInstance($a_id, $a_component, $a_class, true); - if ($job) { - $this->createDefaultEntry($job, $a_component, $a_class, $a_path); - } + $this->createDefaultEntry($job); } - public function unregisterJob(string $a_component, array $a_xml_job_ids): void + /** + * @param list $keep_job_ids + */ + private function deleteJobsNotIn(array $keep_job_ids): void { if (!$this->db->tableExists('cron_job')) { return; } - $jobs = []; - $query = 'SELECT job_id FROM cron_job WHERE component = ' . $this->db->quote($a_component, 'text'); - $res = $this->db->query($query); - while ($row = $this->db->fetchAssoc($res)) { - $jobs[] = $row['job_id']; + if ($keep_job_ids === []) { + $this->db->manipulate('DELETE FROM cron_job'); + return; } - if ($jobs !== []) { - if ($a_xml_job_ids !== []) { - foreach ($jobs as $job_id) { - if (!\in_array($job_id, $a_xml_job_ids, true)) { - $this->db->manipulate( - 'DELETE FROM cron_job' . - ' WHERE component = ' . $this->db->quote($a_component, 'text') . - ' AND job_id = ' . $this->db->quote($job_id, 'text') - ); - } - } - } else { - $this->db->manipulate( - 'DELETE FROM cron_job WHERE component = ' . $this->db->quote($a_component, 'text') - ); - } - } + $this->db->manipulate( + 'DELETE FROM cron_job WHERE ' . $this->db->in('job_id', $keep_job_ids, true, \ilDBConstants::T_TEXT) + ); } - public function createDefaultEntry( - \ILIAS\Cron\CronJob $job, - string $component, - string $class, - ?string $path - ): void { - $query = 'SELECT job_id, schedule_type, component, class, path FROM cron_job' . - ' WHERE job_id = ' . $this->db->quote($job->getId(), 'text'); + private function createDefaultEntry(CronJob $job): void + { + $query = 'SELECT job_id, schedule_type, component, class FROM cron_job' . + ' WHERE job_id = ' . $this->db->quote($job->getId(), \ilDBConstants::T_TEXT); $res = $this->db->query($query); $row = $this->db->fetchAssoc($res); $job_id = $row['job_id'] ?? null; @@ -204,28 +160,23 @@ public function createDefaultEntry( $schedule_type = is_numeric($schedule_type_value) ? JobScheduleType::tryFrom( (int) $schedule_type_value ) : null; + $component = $job->getComponent(); + $class = $job::class; - if ( - $job_exists && ( - $row['component'] !== $component || - $row['class'] !== $class || - $row['path'] !== $path - ) - ) { + if ($job_exists && ($row['component'] !== $component || $row['class'] !== $class)) { $this->db->manipulateF( - 'UPDATE cron_job SET component = %s, class = %s, path = %s WHERE job_id = %s', - ['text', 'text', 'text', 'text'], - [$component, $class, $path, $job->getId()] + 'UPDATE cron_job SET component = %s, class = %s WHERE job_id = %s', + [\ilDBConstants::T_TEXT, \ilDBConstants::T_TEXT, \ilDBConstants::T_TEXT], + [$component, $class, $job->getId()] ); } // new job if (!$job_exists) { - $query = 'INSERT INTO cron_job (job_id, component, class, path)' . - ' VALUES (' . $this->db->quote($job->getId(), 'text') . ', ' . - $this->db->quote($component, 'text') . ', ' . - $this->db->quote($class, 'text') . ', ' . - $this->db->quote($path, 'text') . ')'; + $query = 'INSERT INTO cron_job (job_id, component, class)' . + ' VALUES (' . $this->db->quote($job->getId(), \ilDBConstants::T_TEXT) . ', ' . + $this->db->quote($component, \ilDBConstants::T_TEXT) . ', ' . + $this->db->quote($class, \ilDBConstants::T_TEXT) . ')'; $this->db->manipulate($query); $this->logger->info('Cron XML - Job ' . $job->getId() . ' in class ' . $class . ' added.'); @@ -257,135 +208,100 @@ public function createDefaultEntry( } } - public function getPluginJobs(bool $withOnlyActive = false): array - { - $res = []; - foreach ($this->component_repository->getPlugins() as $pl) { - if (!$pl->isActive()) { - continue; - } - - $plugin = $this->component_factory->getPlugin($pl->getId()); - - if (!$plugin instanceof \ILIAS\Cron\Job\JobProvider) { - continue; - } - - foreach ($plugin->getCronJobInstances() as $job) { - $jobs_data = $this->getCronJobData($job->getId()); - $job_data = $jobs_data[0] ?? null; - if (!\is_array($job_data) || $job_data === []) { - // as job is not "imported" from xml - $this->createDefaultEntry($job, $plugin->getPluginName(), self::TYPE_PLUGINS, ''); - } - - $jobs_data = $this->getCronJobData($job->getId()); - $job_data = $jobs_data[0]; - - // #17941 - if (!$withOnlyActive || (int) $job_data['job_status'] === 1) { - $res[$job->getId()] = [$job, $job_data]; - } - } - } - - return $res; - } - - public function resetJob(\ILIAS\Cron\CronJob $job): void + public function resetJob(CronJob $job): void { $this->db->manipulate( 'UPDATE cron_job' . - ' SET running_ts = ' . $this->db->quote(0, 'integer') . - ' , alive_ts = ' . $this->db->quote(0, 'integer') . - ' , job_result_ts = ' . $this->db->quote(0, 'integer') . - ' WHERE job_id = ' . $this->db->quote($job->getId(), 'text') + ' SET running_ts = ' . $this->db->quote(0, \ilDBConstants::T_INTEGER) . + ' , alive_ts = ' . $this->db->quote(0, \ilDBConstants::T_INTEGER) . + ' , job_result_ts = ' . $this->db->quote(0, \ilDBConstants::T_INTEGER) . + ' WHERE job_id = ' . $this->db->quote($job->getId(), \ilDBConstants::T_TEXT) ); } public function updateJobResult( - \ILIAS\Cron\CronJob $job, + CronJob $job, \DateTimeImmutable $when, \ilObjUser $actor, \ILIAS\Cron\Job\JobResult $result, - bool $wasManualExecution = false + bool $was_manual_execution = false ): void { - $user_id = $wasManualExecution ? $actor->getId() : 0; + $user_id = $was_manual_execution ? $actor->getId() : 0; $query = 'UPDATE cron_job SET ' . - ' job_result_status = ' . $this->db->quote($result->getStatus(), 'integer') . - ' , job_result_user_id = ' . $this->db->quote($user_id, 'integer') . - ' , job_result_code = ' . $this->db->quote($result->getCode(), 'text') . - ' , job_result_message = ' . $this->db->quote($result->getMessage(), 'text') . - ' , job_result_type = ' . $this->db->quote((int) $wasManualExecution, 'integer') . - ' , job_result_ts = ' . $this->db->quote($when->getTimestamp(), 'integer') . - ' , job_result_dur = ' . $this->db->quote($result->getDuration() * 1000, 'integer') . - ' WHERE job_id = ' . $this->db->quote($job->getId(), 'text'); + ' job_result_status = ' . $this->db->quote($result->getStatus(), \ilDBConstants::T_INTEGER) . + ' , job_result_user_id = ' . $this->db->quote($user_id, \ilDBConstants::T_INTEGER) . + ' , job_result_code = ' . $this->db->quote($result->getCode(), \ilDBConstants::T_INTEGER) . + ' , job_result_message = ' . $this->db->quote($result->getMessage(), \ilDBConstants::T_INTEGER) . + ' , job_result_type = ' . $this->db->quote((int) $was_manual_execution, \ilDBConstants::T_INTEGER) . + ' , job_result_ts = ' . $this->db->quote($when->getTimestamp(), \ilDBConstants::T_INTEGER) . + ' , job_result_dur = ' . $this->db->quote($result->getDuration() * 1000, \ilDBConstants::T_INTEGER) . + ' WHERE job_id = ' . $this->db->quote($job->getId(), \ilDBConstants::T_TEXT); $this->db->manipulate($query); } - public function updateRunInformation(string $jobId, int $runningTimestamp, int $aliveTimestamp): void + public function updateRunInformation(string $id, int $running_timestamp, int $alive_timestamp): void { $this->db->manipulate( 'UPDATE cron_job SET' . - ' running_ts = ' . $this->db->quote($runningTimestamp, 'integer') . - ' , alive_ts = ' . $this->db->quote($aliveTimestamp, 'integer') . - ' WHERE job_id = ' . $this->db->quote($jobId, 'text') + ' running_ts = ' . $this->db->quote($running_timestamp, \ilDBConstants::T_INTEGER) . + ' , alive_ts = ' . $this->db->quote($alive_timestamp, \ilDBConstants::T_INTEGER) . + ' WHERE job_id = ' . $this->db->quote($id, \ilDBConstants::T_TEXT) ); } - public function updateJobSchedule(\ILIAS\Cron\CronJob $job, ?JobScheduleType $scheduleType, ?int $scheduleValue): void + public function updateJobSchedule(CronJob $job, ?JobScheduleType $schedule_type, ?int $schedule_value): void { if ( - $scheduleType === null || - ($job->hasFlexibleSchedule() && \in_array($scheduleType, $job->getValidScheduleTypes(), true)) + $schedule_type === null || + ($job->hasFlexibleSchedule() && \in_array($schedule_type, $job->getValidScheduleTypes(), true)) ) { $query = 'UPDATE cron_job SET ' . - ' schedule_type = ' . $this->db->quote($scheduleType?->value, 'integer') . - ' , schedule_value = ' . $this->db->quote($scheduleValue, 'integer') . - ' WHERE job_id = ' . $this->db->quote($job->getId(), 'text'); + ' schedule_type = ' . $this->db->quote($schedule_type?->value, \ilDBConstants::T_INTEGER) . + ' , schedule_value = ' . $this->db->quote($schedule_value, \ilDBConstants::T_INTEGER) . + ' WHERE job_id = ' . $this->db->quote($job->getId(), \ilDBConstants::T_TEXT); $this->db->manipulate($query); } } public function activateJob( - \ILIAS\Cron\CronJob $job, + CronJob $job, \DateTimeImmutable $when, ?\ilObjUser $actor = null, - bool $wasManuallyExecuted = false + bool $was_manually_executed = false ): void { $usrId = 0; - if ($wasManuallyExecuted && $actor instanceof \ilObjUser) { + if ($was_manually_executed && $actor instanceof \ilObjUser) { $usrId = $actor->getId(); } $query = 'UPDATE cron_job SET ' . - ' job_status = ' . $this->db->quote(1, 'integer') . - ' , job_status_user_id = ' . $this->db->quote($usrId, 'integer') . - ' , job_status_type = ' . $this->db->quote($wasManuallyExecuted, 'integer') . - ' , job_status_ts = ' . $this->db->quote($when->getTimestamp(), 'integer') . - ' WHERE job_id = ' . $this->db->quote($job->getId(), 'text'); + ' job_status = ' . $this->db->quote(1, \ilDBConstants::T_INTEGER) . + ' , job_status_user_id = ' . $this->db->quote($usrId, \ilDBConstants::T_INTEGER) . + ' , job_status_type = ' . $this->db->quote($was_manually_executed, \ilDBConstants::T_INTEGER) . + ' , job_status_ts = ' . $this->db->quote($when->getTimestamp(), \ilDBConstants::T_INTEGER) . + ' WHERE job_id = ' . $this->db->quote($job->getId(), \ilDBConstants::T_TEXT); $this->db->manipulate($query); } public function deactivateJob( - \ILIAS\Cron\CronJob $job, + CronJob $job, \DateTimeImmutable $when, \ilObjUser $actor, - bool $wasManuallyExecuted = false + bool $was_manually_executed = false ): void { - $usrId = $wasManuallyExecuted ? $actor->getId() : 0; + $usrId = $was_manually_executed ? $actor->getId() : 0; $query = 'UPDATE cron_job SET ' . - ' job_status = ' . $this->db->quote(0, 'integer') . - ' , job_result_status = ' . $this->db->quote(null, 'text') . - ' , job_result_message = ' . $this->db->quote(null, 'text') . - ' , job_result_type = ' . $this->db->quote(null, 'text') . - ' , job_result_code = ' . $this->db->quote(null, 'text') . - ' , job_status_user_id = ' . $this->db->quote($usrId, 'integer') . - ' , job_status_type = ' . $this->db->quote($wasManuallyExecuted, 'integer') . - ' , job_status_ts = ' . $this->db->quote($when->getTimestamp(), 'integer') . - ' WHERE job_id = ' . $this->db->quote($job->getId(), 'text'); + ' job_status = ' . $this->db->quote(0, \ilDBConstants::T_INTEGER) . + ' , job_result_status = ' . $this->db->quote(null, \ilDBConstants::T_TEXT) . + ' , job_result_message = ' . $this->db->quote(null, \ilDBConstants::T_TEXT) . + ' , job_result_type = ' . $this->db->quote(null, \ilDBConstants::T_TEXT) . + ' , job_result_code = ' . $this->db->quote(null, \ilDBConstants::T_TEXT) . + ' , job_status_user_id = ' . $this->db->quote($usrId, \ilDBConstants::T_INTEGER) . + ' , job_status_type = ' . $this->db->quote($was_manually_executed, \ilDBConstants::T_INTEGER) . + ' , job_status_ts = ' . $this->db->quote($when->getTimestamp(), \ilDBConstants::T_INTEGER) . + ' WHERE job_id = ' . $this->db->quote($job->getId(), \ilDBConstants::T_TEXT); $this->db->manipulate($query); } @@ -393,30 +309,21 @@ public function findAll(): \ILIAS\Cron\Job\JobCollection { $collection = new \ILIAS\Cron\Job\Collection\JobEntities(); - foreach ($this->getCronJobData() as $item) { - $job = $this->getJobInstance( - $item['job_id'], - $item['component'], - $item['class'] - ); - if ($job) { - $collection->add(new \ILIAS\Cron\Job\JobEntity($job, $item)); - } - } - - foreach ($this->getPluginJobs() as $item) { - $collection->add(new \ILIAS\Cron\Job\JobEntity($item[0], $item[1], true)); + foreach ($this->registry->getAllJobs() as $job) { + $job_data = $this->getCronJobData($job->getId()); + $entity = new JobEntity($job, array_shift($job_data)); + $collection->add($entity); } return $collection; } - public function getEntityById(string $id): ?\ILIAS\Cron\Job\JobEntity + public function getEntityById(string $id): ?JobEntity { $jobs = $this->findAll(); return $jobs->filter( - static fn(\ILIAS\Cron\Job\JobEntity $entity): bool => $entity->getEffectiveJobId() === $id + static fn(JobEntity $entity): bool => $entity->getJobId() === $id )->toArray()[0] ?? null; } } diff --git a/components/ILIAS/Cron/src/Setup/Agent.php b/components/ILIAS/Cron/src/Setup/Agent.php deleted file mode 100644 index f93672cd0565..000000000000 --- a/components/ILIAS/Cron/src/Setup/Agent.php +++ /dev/null @@ -1,77 +0,0 @@ -refinery->identity(); - } - - public function getInstallObjective(?Config $config = null): Objective - { - return new NullObjective(); - } - - public function getUpdateObjective(?Config $config = null): Objective - { - return new ilTreeAdminNodeAddedObjective('cron', 'Cron'); - } - - public function getBuildObjective(): Objective - { - return new NullObjective(); - } - - public function getStatusObjective(Storage $storage): Objective - { - return new NullObjective(); - } - - public function getMigrations(): array - { - return []; - } - - public function getNamedObjectives(?Config $config = null): array - { - return []; - } -} diff --git a/components/ILIAS/Cron/src/Setup/CronDBUpdateSteps12.php b/components/ILIAS/Cron/src/Setup/CronDBUpdateSteps12.php new file mode 100644 index 000000000000..90b1ce66152c --- /dev/null +++ b/components/ILIAS/Cron/src/Setup/CronDBUpdateSteps12.php @@ -0,0 +1,41 @@ +db = $db; + } + + public function step_1(): void + { + if ($this->db->tableExists('cron_job') && $this->db->tableColumnExists('cron_job', 'path')) { + $this->db->dropTableColumn('cron_job', 'path'); + } + } +} diff --git a/components/ILIAS/Cron/src/Setup/CronJobSetupAgent.php b/components/ILIAS/Cron/src/Setup/CronJobSetupAgent.php new file mode 100644 index 000000000000..02edcfedde99 --- /dev/null +++ b/components/ILIAS/Cron/src/Setup/CronJobSetupAgent.php @@ -0,0 +1,102 @@ + $jobs + */ + public function __construct(private readonly array $jobs) + { + } + + public function hasConfig(): bool + { + return false; + } + + public function getArrayToConfigTransformation(): Transformation + { + throw new \LogicException('Agent has no config.'); + } + + public function getInstallObjective(?Config $config = null): Objective + { + return new ObjectiveCollection( + 'Cron component installation', + false, + new \ilDatabaseUpdateStepsExecutedObjective(new CronDBUpdateSteps12()), + new StoreCronJobsInDatabaseObjective($this->jobs), + new \ilTreeAdminNodeAddedObjective('cron', 'Cron'), + ); + } + + public function getUpdateObjective(?Config $config = null): Objective + { + return new ObjectiveCollection( + 'Cron component update', + false, + new \ilDatabaseUpdateStepsExecutedObjective(new CronDBUpdateSteps12()), + new StoreCronJobsInDatabaseObjective($this->jobs), + new \ilTreeAdminNodeAddedObjective('cron', 'Cron'), + ); + } + + public function getBuildObjective(): Objective + { + return new NullObjective(); + } + + public function getStatusObjective(Storage $storage): Objective + { + return new ObjectiveCollection( + 'Database is updated for component/ILIAS/Cron', + true, + new \ilDatabaseUpdateStepsMetricsCollectedObjective($storage, new CronDBUpdateSteps12()), + ); + } + + public function getMigrations(): array + { + return []; + } + + public function getNamedObjectives(?Config $config = null): array + { + return [ + 'cron.registerCronJobs' => + new ObjectiveConstructor( + 'Gathers and registers cron jobs', + fn(): Objective => new StoreCronJobsInDatabaseObjective($this->jobs) + ) + ]; + } +} diff --git a/components/ILIAS/Cron/src/Setup/DefinitionProcessor.php b/components/ILIAS/Cron/src/Setup/DefinitionProcessor.php deleted file mode 100644 index 78aae10a2fb3..000000000000 --- a/components/ILIAS/Cron/src/Setup/DefinitionProcessor.php +++ /dev/null @@ -1,95 +0,0 @@ -has_cron = []; - - $this->job_repository = new JobRepositoryImpl( - $this->db, - $setting, - new \ILIAS\components\Logging\NullLogger(), - $component_repository, - $component_factory - ); - } - - public function purge(): void - { - } - - public function beginComponent(string $component, string $type): void - { - $this->component = $type . '/' . $component; - $this->has_cron = []; - } - - public function endComponent(string $component, string $type): void - { - $this->component = null; - $this->has_cron = []; - } - - public function beginTag(string $name, array $attributes): void - { - if ($name !== 'cron') { - return; - } - - $component = $attributes['component'] ?? null; - if (!$component) { - $component = $this->component; - } - - $this->job_repository->registerJob( - $component, - $attributes['id'], - $attributes['class'], - ($attributes['path'] ?? null) - ); - - $this->has_cron[] = $attributes['id']; - } - - public function endTag(string $name): void - { - if ($name !== 'module' && $name !== 'service') { - return; - } - - $this->job_repository->unregisterJob($this->component, $this->has_cron); - } -} diff --git a/components/ILIAS/Cron/src/Setup/StoreCronJobsInDatabaseObjective.php b/components/ILIAS/Cron/src/Setup/StoreCronJobsInDatabaseObjective.php new file mode 100644 index 000000000000..99a3eab0c059 --- /dev/null +++ b/components/ILIAS/Cron/src/Setup/StoreCronJobsInDatabaseObjective.php @@ -0,0 +1,104 @@ + $jobs + */ + public function __construct(private readonly array $jobs) + { + } + + public function getHash(): string + { + return hash('sha256', self::class); + } + + public function getLabel(): string + { + return 'Cron jobs from component contributions are stored in the database.'; + } + + public function isNotable(): bool + { + return true; + } + + public function getPreconditions(Environment $environment): array + { + return [ + new \ilDatabaseUpdatedObjective(), + new \ilSettingsFactoryExistsObjective(), + new \ilComponentRepositoryExistsObjective(), + new \ilComponentFactoryExistsObjective(), + ]; + } + + public function achieve(Environment $environment): Environment + { + $db = $environment->getResource(Environment::RESOURCE_DATABASE); + /** @var \ilSettingsFactory $settings_factory */ + $settings_factory = $environment->getResource(Environment::RESOURCE_SETTINGS_FACTORY); + /** @var \ilComponentRepository $component_repository */ + $component_repository = $environment->getResource(Environment::RESOURCE_COMPONENT_REPOSITORY); + /** @var \ilComponentFactory $component_factory */ + $component_factory = $environment->getResource(Environment::RESOURCE_COMPONENT_FACTORY); + + $registry = new \ILIAS\Cron\InMemoryCronJobRegistry($this->jobs); + + $language = new \ilSetupLanguage('en'); + $logger_factory = new class () implements \ILIAS\Logging\LoggerFactory { + public function getComponentLogger($a_component_id): \ilLogger + { + } + }; + + $job_repository = new JobRepositoryImpl( + $registry, + $db, + $settings_factory->settingsFor(), + new \ILIAS\components\Logging\NullLogger(), + $component_repository, + $component_factory, + $language, + $logger_factory + ); + + $job_repository->syncJobsFromRegistry(); + + return $environment; + } + + public function isApplicable(Environment $environment): bool + { + return true; + } +} diff --git a/components/ILIAS/Cron/src/class.ilObjCronGUI.php b/components/ILIAS/Cron/src/class.ilObjCronGUI.php index 900a88e27e04..40c45de73075 100644 --- a/components/ILIAS/Cron/src/class.ilObjCronGUI.php +++ b/components/ILIAS/Cron/src/class.ilObjCronGUI.php @@ -112,7 +112,7 @@ private function retrieveTableActionJobIds(): array ) ); $ids = array_map( - static fn(JobEntity $entity): string => $entity->getEffectiveJobId(), + static fn(JobEntity $entity): string => $entity->getJobId(), $tableFilterMediator->filteredJobs( $filter )->toArray() @@ -147,7 +147,7 @@ private function addProblematicItemsInfo( function (JobEntity $entity): \ILIAS\UI\Component\Link\Standard { return $this->ui_factory->link()->standard( $entity->getEffectiveTitle(), - '#job-' . $entity->getEffectiveJobId() + '#job-' . $entity->getJobId() ); }, (new OrderedJobEntities( @@ -344,7 +344,7 @@ public function edit(?ILIAS\UI\Component\Input\Container\Form\Form $form = null) } if ($entity->getJob()->usesLegacyForms()) { - $this->ctrl->setParameter($this, $this->getJobIdParameterName(), $entity->getEffectiveJobId()); + $this->ctrl->setParameter($this, $this->getJobIdParameterName(), $entity->getJobId()); $this->ctrl->redirect($this, 'editLegacy'); } @@ -420,7 +420,7 @@ protected function buildForm(JobEntity $entity): ILIAS\UI\Component\Input\Contai { $job = $entity->getJob(); - $this->ctrl->setParameter($this, $this->getJobIdParameterName(), $entity->getEffectiveJobId()); + $this->ctrl->setParameter($this, $this->getJobIdParameterName(), $entity->getJobId()); $section_inputs = []; if ($job->hasFlexibleSchedule()) { @@ -521,7 +521,7 @@ protected function initLegacyEditForm(JobEntity $entity): ilPropertyFormGUI { $job = $entity->getJob(); - $this->ctrl->setParameter($this, $this->getJobIdParameterName(), $entity->getEffectiveJobId()); + $this->ctrl->setParameter($this, $this->getJobIdParameterName(), $entity->getJobId()); $form = new ilPropertyFormGUI(); $form->setFormAction($this->ctrl->getFormAction($this, 'updateLegacy')); @@ -803,6 +803,7 @@ protected function getMultiActionData(): array foreach ($job_ids as $job_id) { $job = $this->cron_repository->getJobInstanceById($job_id); if ($job instanceof CronJob) { + $job->init(); $res[$job_id] = $job; } } @@ -882,6 +883,7 @@ public function addToExternalSettingsForm(int $a_form_id): array $item['class'] ); if ($job !== null) { + $job->init(); $job->addToExternalSettingsForm($a_form_id, $fields, (bool) $item['job_status']); } } diff --git a/components/ILIAS/Cron/tests/CronJobEntityTest.php b/components/ILIAS/Cron/tests/CronJobEntityTest.php index 3fcad259440f..055366f21c55 100755 --- a/components/ILIAS/Cron/tests/CronJobEntityTest.php +++ b/components/ILIAS/Cron/tests/CronJobEntityTest.php @@ -30,10 +30,12 @@ class CronJobEntityTest extends TestCase private function getEntity( ?CronJob $job_instance = null, ?int $schedule_type = null, - int $schedule_value = 5, - bool $is_plugin = false + int $schedule_value = 5 ): JobEntity { - $job_instance ??= $this->createMock(CronJob::class); + if ($job_instance === null) { + $job_instance = $this->createMock(CronJob::class); + $job_instance->method('getId')->willReturn('phpunit'); + } if ($schedule_type === null) { $schedule_type = JobScheduleType::IN_MINUTES->value; @@ -59,7 +61,7 @@ private function getEntity( 'running_ts' => time(), 'job_result_dur' => time(), 'alive_ts' => time(), - ], $is_plugin); + ]); } public function testEntityCollectionCanBeCreatedWithItems(): \ILIAS\Cron\Job\Collection\JobEntities @@ -95,6 +97,7 @@ public function testCollectionCanBeFilteredAndSliced(\ILIAS\Cron\Job\Collection\ public function testEffectiveScheduleCanBeDetermined(): void { $job_instance = $this->createMock(CronJob::class); + $job_instance->method('getId')->willReturn('phpunit'); $job_instance->method('hasFlexibleSchedule')->willReturn(true); $entity = $this->getEntity($job_instance); @@ -102,6 +105,7 @@ public function testEffectiveScheduleCanBeDetermined(): void $this->assertSame(5, $entity->getEffectiveScheduleValue()); $another_job_instance = $this->createMock(CronJob::class); + $another_job_instance->method('getId')->willReturn('phpunit'); $another_job_instance->method('hasFlexibleSchedule')->willReturn(false); $another_job_instance->method('getDefaultScheduleType')->willReturn( JobScheduleType::IN_HOURS @@ -113,6 +117,7 @@ public function testEffectiveScheduleCanBeDetermined(): void $this->assertSame(5, $another_entity->getEffectiveScheduleValue()); $yet_another_job_instance = $this->createMock(CronJob::class); + $yet_another_job_instance->method('getId')->willReturn('phpunit'); $yet_another_job_instance->method('hasFlexibleSchedule')->willReturn(true); $yet_another_job_instance->method('getDefaultScheduleType')->willReturn( JobScheduleType::IN_HOURS diff --git a/components/ILIAS/Cron/tests/CronJobScheduleTest.php b/components/ILIAS/Cron/tests/CronJobScheduleTest.php index 18d4ce6b3f22..748aa51dc74e 100755 --- a/components/ILIAS/Cron/tests/CronJobScheduleTest.php +++ b/components/ILIAS/Cron/tests/CronJobScheduleTest.php @@ -21,6 +21,7 @@ use PHPUnit\Framework\TestCase; use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; +use ILIAS\Cron\AbstractCronJob; use ILIAS\Cron\CronJob; use PHPUnit\Framework\Attributes\DataProvider; @@ -29,28 +30,40 @@ class CronJobScheduleTest extends TestCase private static DateTimeImmutable $now; private static DateTimeImmutable $this_quarter_start; - private static function getJob( + /** + * Builds the anonymous {@see CronJob} used by schedule tests (requires test-case mocks). + */ + private function getJob( bool $has_flexible_schedule, JobScheduleType $default_schedule_type, ?int $default_schedule_value, JobScheduleType $schedule_type, ?int $schedule_value ): CronJob { + $language = $this->createMock(\ILIAS\Language\Language::class); + $logger_factory = $this->getMockBuilder(\ILIAS\Logging\LoggerFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $job_instance = new class ( $has_flexible_schedule, $default_schedule_type, $default_schedule_value, $schedule_type, - $schedule_value - ) extends - CronJob { + $schedule_value, + $language, + $logger_factory + ) extends AbstractCronJob { public function __construct( private readonly bool $has_flexible_schedule, private readonly JobScheduleType $default_schedule_type, private readonly ?int $default_schedule_value, JobScheduleType $schedule_type, - ?int $schedule_value + ?int $schedule_value, + \ILIAS\Language\Language $language, + \ILIAS\Logging\LoggerFactory $logger_factory, ) { + parent::__construct(\ILIAS\Cron\Cron::class, $language, $logger_factory); $this->schedule_type = $schedule_type; $this->schedule_value = $schedule_value; } @@ -102,13 +115,23 @@ public function run(): JobResult } /** - * @return array + * Each case defers {@see self::getJob()} via a closure so static providers can run without + * {@see TestCase} mock helpers + * + * @return array */ public static function jobProvider(): array { return [ 'Manual Run is Always Due' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::DAILY, null, @@ -122,7 +145,7 @@ public static function jobProvider(): array true ], 'Job Without Any Run is Always Due' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::DAILY, null, @@ -136,7 +159,7 @@ public static function jobProvider(): array true ], 'Daily Schedule / Did not run Today' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::DAILY, null, @@ -154,7 +177,7 @@ function (): DateTimeImmutable { true ], 'Daily Schedule / Did run Today' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::DAILY, null, @@ -172,7 +195,7 @@ function (): DateTimeImmutable { false ], 'Weekly Schedule / Did not run this Week' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::WEEKLY, null, @@ -190,7 +213,7 @@ function (): DateTimeImmutable { true ], 'Weekly Schedule / Did run this Week' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::WEEKLY, null, @@ -208,7 +231,7 @@ function (): DateTimeImmutable { false ], 'Monthly Schedule / Did not run this Month' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::MONTHLY, null, @@ -226,7 +249,7 @@ function (): DateTimeImmutable { true ], 'Monthly Schedule / Did run this Month' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::MONTHLY, null, @@ -244,7 +267,7 @@ function (): DateTimeImmutable { false ], 'Yearly Schedule / Did not run this Year' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::YEARLY, null, @@ -262,7 +285,7 @@ function (): DateTimeImmutable { true ], 'Yearly Schedule / Did run this Year' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::YEARLY, null, @@ -280,7 +303,7 @@ function (): DateTimeImmutable { false ], 'Quarterly Schedule / Did not run this Quarter' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::QUARTERLY, null, @@ -301,7 +324,7 @@ function (): DateTimeImmutable { true ], 'Quarterly Schedule / Did run this Quarter' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::QUARTERLY, null, @@ -322,7 +345,7 @@ function (): DateTimeImmutable { false ], 'Minutely Schedule / Did not run this Minute' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::IN_MINUTES, 1, @@ -340,7 +363,7 @@ function (): DateTimeImmutable { true ], 'Minutely Schedule / Did run this Minute' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::IN_MINUTES, 1, @@ -358,7 +381,7 @@ function (): DateTimeImmutable { false ], 'Hourly Schedule / Did not run this Hour' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::IN_HOURS, 7, @@ -376,7 +399,7 @@ function (): DateTimeImmutable { true ], 'Hourly Schedule / Did run this Hour' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::IN_HOURS, 7, @@ -394,7 +417,7 @@ function (): DateTimeImmutable { false ], 'Every 5 Days Schedule / Did not run for 5 Days' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::IN_DAYS, 5, @@ -412,7 +435,7 @@ function (): DateTimeImmutable { true ], 'Every 5 Days Schedule / Did run withing the last 5 Days' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::IN_DAYS, 5, @@ -433,17 +456,19 @@ function (): DateTimeImmutable { } /** - * @param null|callable(): DateTimeImmutable $last_run_datetime_callable + * @param Closure(CronJobScheduleTest): CronJob $job_factory + * @param null|callable(): DateTimeImmutable $last_run_datetime_callable */ #[DataProvider('jobProvider')] public function testSchedule( - CronJob $job_instance, + Closure $job_factory, bool $is_manual_run, ?callable $last_run_datetime_callable, JobScheduleType $schedule_type, ?int $schedule_value, bool $should_be_due ): void { + $job_instance = $job_factory($this); $last_run_datetime = $last_run_datetime_callable ? $last_run_datetime_callable() : null; self::assertEquals( $should_be_due, @@ -452,10 +477,17 @@ public function testSchedule( ); } + /** + * @return Generator + */ public static function weeklyScheduleProvider(): Generator { yield 'Different Week' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::WEEKLY, null, @@ -473,7 +505,7 @@ function (): DateTimeImmutable { ]; yield 'Same Week and Year, but different Month: December (now) and January (Last run)' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::WEEKLY, null, @@ -493,7 +525,7 @@ function (): DateTimeImmutable { ]; yield 'Same Week and Year and same Month: January' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::WEEKLY, null, @@ -513,7 +545,7 @@ function (): DateTimeImmutable { ]; yield 'Same Week (52nd), but Year Difference > 1' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::WEEKLY, null, @@ -533,7 +565,7 @@ function (): DateTimeImmutable { ]; yield 'Same Week (52nd) in different Years, but Turn of the Year' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::WEEKLY, null, @@ -553,7 +585,7 @@ function (): DateTimeImmutable { ]; yield 'Same Week (52nd) in different Years, but not Turn of the Year' => [ - self::getJob( + fn(CronJobScheduleTest $case): CronJob => $case->getJob( true, JobScheduleType::WEEKLY, null, @@ -574,14 +606,16 @@ function (): DateTimeImmutable { } /** - * @param callable(): DateTimeImmutable $last_run_datetime_provider + * @param Closure(CronJobScheduleTest): CronJob $job_factory + * @param callable(): DateTimeImmutable $last_run_datetime_provider */ #[DataProvider('weeklyScheduleProvider')] public function testWeeklySchedules( - CronJob $job_instance, + Closure $job_factory, callable $last_run_datetime_provider, bool $should_be_due ): void { + $job_instance = $job_factory($this); $last_run_datetime = $last_run_datetime_provider(); self::assertSame( diff --git a/components/ILIAS/Cron/tests/InMemoryCronJobRegistryTest.php b/components/ILIAS/Cron/tests/InMemoryCronJobRegistryTest.php new file mode 100644 index 000000000000..023fefbd6bcb --- /dev/null +++ b/components/ILIAS/Cron/tests/InMemoryCronJobRegistryTest.php @@ -0,0 +1,64 @@ +createStub(CronJob::class); + $a->method('getId')->willReturn('a'); + + $b = $this->createStub(CronJob::class); + $b->method('getId')->willReturn('b'); + + $registry = new InMemoryCronJobRegistry([$a, $b]); + + self::assertSame([$a, $b], $registry->getAllJobs()); + } + + public function testRejectsDuplicateJobIds(): void + { + $a = $this->createStub(CronJob::class); + $a->method('getId')->willReturn('dup'); + + $b = $this->createStub(CronJob::class); + $b->method('getId')->willReturn('dup'); + + $this->expectException(LogicException::class); + $this->expectExceptionMessage('Duplicate cron job id contributed: dup'); + + new InMemoryCronJobRegistry([$a, $b]); + } + + public function testRejectsEmptyJobId(): void + { + $a = $this->createStub(CronJob::class); + $a->method('getId')->willReturn(''); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Cron job id must not be empty.'); + + new InMemoryCronJobRegistry([$a]); + } +} diff --git a/components/ILIAS/Exercise/Exercise.php b/components/ILIAS/Exercise/Exercise.php index 1328bafa06e7..0419503af337 100644 --- a/components/ILIAS/Exercise/Exercise.php +++ b/components/ILIAS/Exercise/Exercise.php @@ -44,5 +44,18 @@ public function init( new Component\Resource\ComponentJS($this, "ilExcPeerReview.js"); $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\ComponentJS($this, "exc-text-more.js"); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilExcCronFeedbackNotification( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilExcCronReminders( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/Exercise/classes/class.ilExcCronFeedbackNotification.php b/components/ILIAS/Exercise/classes/class.ilExcCronFeedbackNotification.php index 8300b0b9b722..f1ddba3f0747 100755 --- a/components/ILIAS/Exercise/classes/class.ilExcCronFeedbackNotification.php +++ b/components/ILIAS/Exercise/classes/class.ilExcCronFeedbackNotification.php @@ -18,7 +18,7 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Cron for exercise feedback notification @@ -26,37 +26,26 @@ * @author Jörg Lützenkirchen * @author Alexander Killing */ -class ilExcCronFeedbackNotification extends CronJob +class ilExcCronFeedbackNotification extends AbstractCronJob { - protected ilLanguage $lng; - - - public function __construct() + public function getId(): string { - global $DIC; - - $this->lng = $DIC->language(); + return "exc_feedback_notification"; } - public function getId(): string + public function init(): void { - return "exc_feedback_notification"; + $this->language->loadLanguageModule("exc"); } public function getTitle(): string { - $lng = $this->lng; - - $lng->loadLanguageModule("exc"); - return $lng->txt("exc_global_feedback_file_cron"); + return $this->language->txt("exc_global_feedback_file_cron"); } public function getDescription(): string { - $lng = $this->lng; - - $lng->loadLanguageModule("exc"); - return $lng->txt("exc_global_feedback_file_cron_info"); + return $this->language->txt("exc_global_feedback_file_cron_info"); } public function getDefaultScheduleType(): JobScheduleType diff --git a/components/ILIAS/Exercise/classes/class.ilExcCronReminders.php b/components/ILIAS/Exercise/classes/class.ilExcCronReminders.php index 229c3da3e495..e8dcf8f99d42 100755 --- a/components/ILIAS/Exercise/classes/class.ilExcCronReminders.php +++ b/components/ILIAS/Exercise/classes/class.ilExcCronReminders.php @@ -18,7 +18,7 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Cron for exercise reminders @@ -26,38 +26,26 @@ * @author Jesús López * @author Alexander Killing */ -class ilExcCronReminders extends CronJob +class ilExcCronReminders extends AbstractCronJob { - protected ilLanguage $lng; - - public function __construct() + public function getId(): string { - global $DIC; - - $this->lng = $DIC->language(); + return "exc_reminders"; } - public function getId(): string + public function init(): void { - return "exc_reminders"; + $this->language->loadLanguageModule("exc"); } public function getTitle(): string { - $lng = $this->lng; - - $lng->loadLanguageModule("exc"); - - return $lng->txt("exc_reminders_cron"); + return $this->language->txt("exc_reminders_cron"); } public function getDescription(): string { - $lng = $this->lng; - - $lng->loadLanguageModule("exc"); - - return $lng->txt("exc_reminders_cron_info"); + return $this->language->txt("exc_reminders_cron_info"); } public function getDefaultScheduleType(): JobScheduleType diff --git a/components/ILIAS/Exercise/module.xml b/components/ILIAS/Exercise/module.xml index 773bfebe1233..432eb6ed1ac3 100755 --- a/components/ILIAS/Exercise/module.xml +++ b/components/ILIAS/Exercise/module.xml @@ -25,10 +25,6 @@ wfld - - - - diff --git a/components/ILIAS/Filesystem/Filesystem.php b/components/ILIAS/Filesystem/Filesystem.php index 421dc2883e95..4a9528c07715 100644 --- a/components/ILIAS/Filesystem/Filesystem.php +++ b/components/ILIAS/Filesystem/Filesystem.php @@ -40,5 +40,12 @@ public function init( new \ilFileSystemSetupAgent( $pull[Factory::class] ); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilFileSystemCleanTempDirCron( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/Filesystem/classes/class.ilFileSystemCleanTempDirCron.php b/components/ILIAS/Filesystem/classes/class.ilFileSystemCleanTempDirCron.php index 0b10cad78fa9..21f1e0acba7a 100755 --- a/components/ILIAS/Filesystem/classes/class.ilFileSystemCleanTempDirCron.php +++ b/components/ILIAS/Filesystem/classes/class.ilFileSystemCleanTempDirCron.php @@ -18,48 +18,30 @@ use ILIAS\Filesystem\Filesystem; use ILIAS\Filesystem\DTO\Metadata; -use ILIAS\DI\Container; use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Class ilFileSystemCleanTempDirCron * * @author Lukas Zehnder */ -class ilFileSystemCleanTempDirCron extends CronJob +class ilFileSystemCleanTempDirCron extends AbstractCronJob { protected Filesystem $filesystem; - protected ilLanguage $language; - protected ilLogger $logger; - /** - * @inheritDoc - */ - public function __construct() + public function init(): void { - /** - * @var $DIC Container - */ global $DIC; - if ($DIC->offsetExists('lng')) { - $this->language = $DIC['lng']; - } - if ($DIC->offsetExists('filesystem')) { - $this->filesystem = $DIC->filesystem()->temp(); - } - if ($DIC->offsetExists('ilLoggerFactory')) { - $this->logger = $DIC->logger()->root(); - } - } - private function initDependencies(): void - { + $this->filesystem = $DIC->filesystem()->temp(); + $this->logger = $DIC->logger()->root(); } + public function getId(): string { return "file_system_clean_temp_dir"; diff --git a/components/ILIAS/Filesystem/service.xml b/components/ILIAS/Filesystem/service.xml index dc131c3873cf..c14d8bee117a 100755 --- a/components/ILIAS/Filesystem/service.xml +++ b/components/ILIAS/Filesystem/service.xml @@ -3,7 +3,4 @@ id="filesys"> - - - diff --git a/components/ILIAS/Forum/Forum.php b/components/ILIAS/Forum/Forum.php index 0d79bcdc6cc0..7490a25038bb 100644 --- a/components/ILIAS/Forum/Forum.php +++ b/components/ILIAS/Forum/Forum.php @@ -33,12 +33,17 @@ public function init( array | \ArrayAccess &$internal, ): void { $contribute[\ILIAS\Setup\Agent::class] = static fn() => - new \ilForumSetupAgent( - $pull[\ILIAS\Refinery\Factory::class] - ); + new \ilForumSetupAgent(); $contribute[Component\Resource\PublicAsset::class] = fn() => - new Component\Resource\ComponentJS($this, "autosave_forum.js"); + new Component\Resource\ComponentJS($this, 'autosave_forum.js'); $contribute[Component\Resource\PublicAsset::class] = fn() => - new Component\Resource\ComponentCSS($this, "forum_table.css"); + new Component\Resource\ComponentCSS($this, 'forum_table.css'); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilForumCronNotification( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/Forum/classes/class.ilForumCronNotification.php b/components/ILIAS/Forum/classes/class.ilForumCronNotification.php index ab1786241622..c4762b46b01e 100755 --- a/components/ILIAS/Forum/classes/class.ilForumCronNotification.php +++ b/components/ILIAS/Forum/classes/class.ilForumCronNotification.php @@ -21,14 +21,14 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobManager; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Forum notifications * @author Michael Jansen * @author Nadia Matuschek */ -class ilForumCronNotification extends CronJob +class ilForumCronNotification extends AbstractCronJob { private const int KEEP_ALIVE_CHUNK_SIZE = 25; private const int DEFAULT_MAX_NOTIFICATION_AGE_IN_DAYS = 30; @@ -44,7 +44,6 @@ class ilForumCronNotification extends CronJob /** @var array */ private static array $container_by_frm_ref_id = []; - private readonly ilLanguage $lng; private readonly ilSetting $settings; private ilLogger $logger; private ilTree $tree; @@ -54,22 +53,17 @@ class ilForumCronNotification extends CronJob private readonly \ILIAS\Refinery\Factory $refinery; private readonly JobManager $cronManager; - public function __construct( - ?ilDBInterface $database = null, - ?ilForumNotificationCache $notificationCache = null, - ?ilLanguage $lng = null, - ?ilSetting $settings = null, - ?\ILIAS\Refinery\Factory $refinery = null, - ?JobManager $cronManager = null - ) { + public function init(): void + { global $DIC; - $this->settings = $settings ?? new ilSetting('frma'); - $this->lng = $lng ?? $DIC->language(); - $this->ilDB = $database ?? $DIC->database(); - $this->notificationCache = $notificationCache ?? new ilForumNotificationCache(); - $this->refinery = $refinery ?? $DIC->refinery(); - $this->cronManager = $cronManager ?? $DIC->cron()->manager(); + $this->language->loadLanguageModule('forum'); + + $this->settings = new ilSetting('frma'); + $this->ilDB = $DIC->database(); + $this->notificationCache = new ilForumNotificationCache(); + $this->refinery = $DIC->refinery(); + $this->cronManager = $DIC->cron()->manager(); } public function getId(): string @@ -79,12 +73,12 @@ public function getId(): string public function getTitle(): string { - return $this->lng->txt('cron_forum_notification'); + return $this->language->txt('cron_forum_notification'); } public function getDescription(): string { - return $this->lng->txt('cron_forum_notification_crob_desc'); + return $this->language->txt('cron_forum_notification_crob_desc'); } public function getDefaultScheduleType(): JobScheduleType @@ -128,8 +122,6 @@ public function run(): JobResult $status = JobResult::STATUS_NO_ACTION; - $this->lng->loadLanguageModule('forum'); - $this->logger->info('Started forum notification job ...'); if (!($last_run_datetime = $this->settings->get('cron_forum_notification_last_date'))) { @@ -370,8 +362,8 @@ public function addToExternalSettingsForm(int $a_form_id, array &$a_fields, bool { if ($a_form_id === ilAdministrationSettingsFormHandler::FORM_FORUM) { $a_fields['cron_forum_notification'] = $a_is_active ? - $this->lng->txt('enabled') : - $this->lng->txt('disabled'); + $this->language->txt('enabled') : + $this->language->txt('disabled'); } } @@ -388,18 +380,16 @@ public function activationWasToggled(ilDBInterface $db, ilSetting $setting, bool public function addCustomSettingsToForm(ilPropertyFormGUI $a_form): void { - $this->lng->loadLanguageModule('forum'); - $max_notification_age = new ilNumberInputGUI( - $this->lng->txt('frm_max_notification_age'), + $this->language->txt('frm_max_notification_age'), 'max_notification_age' ); $max_notification_age->setSize(5); - $max_notification_age->setSuffix($this->lng->txt('frm_max_notification_age_unit')); + $max_notification_age->setSuffix($this->language->txt('frm_max_notification_age_unit')); $max_notification_age->setRequired(true); $max_notification_age->allowDecimals(false); $max_notification_age->setMinValue(1); - $max_notification_age->setInfo($this->lng->txt('frm_max_notification_age_info')); + $max_notification_age->setInfo($this->language->txt('frm_max_notification_age_info')); $max_notification_age->setValue( $this->settings->get( 'max_notification_age', diff --git a/components/ILIAS/Forum/module.xml b/components/ILIAS/Forum/module.xml index ad0e3726f968..ed9b7f1fe1a6 100755 --- a/components/ILIAS/Forum/module.xml +++ b/components/ILIAS/Forum/module.xml @@ -32,9 +32,6 @@ - - - diff --git a/components/ILIAS/Init/Init.php b/components/ILIAS/Init/Init.php index b183dda06ef8..b2539ace9548 100644 --- a/components/ILIAS/Init/Init.php +++ b/components/ILIAS/Init/Init.php @@ -123,6 +123,7 @@ public function init( $pull[\ILIAS\UI\Implementation\Component\Input\UploadLimitResolver::class], $use[\ILIAS\Setup\AgentFinder::class], $pull[\ILIAS\UI\Implementation\Component\Navigation\Factory::class], + $pull[\ILIAS\Cron\CronJobRegistry::class], ); } } diff --git a/components/ILIAS/Init/classes/class.ilInitialisation.php b/components/ILIAS/Init/classes/class.ilInitialisation.php index 33810d466bb9..b17542a5ac23 100755 --- a/components/ILIAS/Init/classes/class.ilInitialisation.php +++ b/components/ILIAS/Init/classes/class.ilInitialisation.php @@ -214,17 +214,17 @@ public static function bootstrapFilesystems(): void { global $DIC; - $DIC['filesystem.security.sanitizing.filename'] = function (Container $c) { + $DIC['filesystem.security.sanitizing.filename'] = static function (Container $c) { return new ilFileServicesFilenameSanitizer( $c->fileServiceSettings() ); }; - $DIC['filesystem.factory'] = function ($c) { + $DIC['filesystem.factory'] = static function ($c) { return new \ILIAS\Filesystem\Provider\DelegatingFilesystemFactory($c['filesystem.security.sanitizing.filename']); }; - $DIC['filesystem.web'] = function ($c) { + $DIC['filesystem.web'] = static function ($c) { //web /** @@ -235,7 +235,7 @@ public static function bootstrapFilesystems(): void return $delegatingFactory->getLocal($webConfiguration); }; - $DIC['filesystem.storage'] = function ($c) { + $DIC['filesystem.storage'] = static function ($c) { //storage /** @@ -246,7 +246,7 @@ public static function bootstrapFilesystems(): void return $delegatingFactory->getLocal($storageConfiguration); }; - $DIC['filesystem.temp'] = function ($c) { + $DIC['filesystem.temp'] = static function ($c) { //temp /** @@ -257,7 +257,7 @@ public static function bootstrapFilesystems(): void return $delegatingFactory->getLocal($tempConfiguration); }; - $DIC['filesystem.customizing'] = function ($c) { + $DIC['filesystem.customizing'] = static function ($c) { //customizing /** @@ -268,7 +268,7 @@ public static function bootstrapFilesystems(): void return $delegatingFactory->getLocal($customizingConfiguration); }; - $DIC['filesystem.libs'] = function ($c) { + $DIC['filesystem.libs'] = static function ($c) { //customizing /** @@ -279,7 +279,7 @@ public static function bootstrapFilesystems(): void return $delegatingFactory->getLocal($customizingConfiguration, true); }; - $DIC['filesystem.node_modules'] = function ($c) { + $DIC['filesystem.node_modules'] = static function ($c) { //customizing /** @@ -290,7 +290,7 @@ public static function bootstrapFilesystems(): void return $delegatingFactory->getLocal($customizingConfiguration, true); }; - $DIC['filesystem'] = function ($c) { + $DIC['filesystem'] = static function ($c) { return new \ILIAS\Filesystem\FilesystemsImpl( $c['filesystem.storage'], $c['filesystem.web'], @@ -305,16 +305,16 @@ public static function bootstrapFilesystems(): void /** * Initializes the file upload service. * This service requires the http and filesystem service. - * @param \ILIAS\DI\Container $dic The dependency container which should be used to load the file upload service. + * @param Container $dic The dependency container which should be used to load the file upload service. * @return void */ - public static function initFileUploadService(\ILIAS\DI\Container $dic): void + public static function initFileUploadService(Container $dic): void { - $dic['upload.processor-manager'] = function ($c) { + $dic['upload.processor-manager'] = static function ($c) { return new PreProcessorManagerImpl(); }; - $dic['upload'] = function (\ILIAS\DI\Container $c) { + $dic['upload'] = static function (Container $c) { $fileUploadImpl = new \ILIAS\FileUpload\FileUploadImpl( $c['upload.processor-manager'], $c['filesystem'], @@ -344,7 +344,7 @@ public static function initFileUploadService(\ILIAS\DI\Container $dic): void }; } - protected static function initUploadPolicies(\ILIAS\DI\Container $dic): void + protected static function initUploadPolicies(Container $dic): void { $dic['upload_policy_repository'] = static function ($dic) { return new UploadPolicyDBRepository($dic->database()); @@ -716,19 +716,22 @@ protected static function setSessionCookieParams(): void } } - protected static function initCron(\ILIAS\DI\Container $c): void + protected static function initCron(Container $c): void { - $c['cron.repository'] = static function (\ILIAS\DI\Container $c): ILIAS\Cron\Job\JobRepository { + $c['cron.repository'] = static function (Container $c): ILIAS\Cron\Job\JobRepository { return new ILIAS\Cron\Job\Repository\JobRepositoryImpl( + $c[\ILIAS\Cron\CronJobRegistry::class], $c->database(), $c->settings(), $c->logger()->cron(), $c['component.repository'], - $c['component.factory'] + $c['component.factory'], + $c['lng'], + $c['ilLoggerFactory'] ); }; - $c['cron.manager'] = static function (\ILIAS\DI\Container $c): ILIAS\Cron\Job\JobManager { + $c['cron.manager'] = static function (Container $c): ILIAS\Cron\Job\JobManager { return new ILIAS\Cron\Job\Manager\JobManagerImpl( $c['cron.repository'], $c->database(), @@ -740,11 +743,11 @@ protected static function initCron(\ILIAS\DI\Container $c): void } /** - * @param \ILIAS\DI\Container $c + * @param Container $c */ - protected static function initCustomObjectIcons(\ILIAS\DI\Container $c): void + protected static function initCustomObjectIcons(Container $c): void { - $c["object.customicons.factory"] = function ($c) { + $c["object.customicons.factory"] = static function ($c) { return new CustomIconFactory( $c->filesystem()->web(), $c->upload(), @@ -753,9 +756,9 @@ protected static function initCustomObjectIcons(\ILIAS\DI\Container $c): void }; } - protected static function initAvatar(\ILIAS\DI\Container $c): void + protected static function initAvatar(Container $c): void { - $c["user.avatar.factory"] = function ($c) { + $c["user.avatar.factory"] = static function ($c) { return new \ilUserAvatarFactory($c); }; } @@ -770,13 +773,13 @@ protected static function initMail(Container $c): void MailService::init($c); } - protected static function initAccessibilityControlConcept(\ILIAS\DI\Container $c): void + protected static function initAccessibilityControlConcept(Container $c): void { - $c['acc.criteria.type.factory'] = function (\ILIAS\DI\Container $c) { + $c['acc.criteria.type.factory'] = static function (Container $c) { return new ilAccessibilityCriterionTypeFactory($c->rbac()->review(), $c['ilObjDataCache']); }; - $c['acc.document.evaluator'] = function (\ILIAS\DI\Container $c) { + $c['acc.document.evaluator'] = static function (Container $c) { return new ilAccessibilitySequentialDocumentEvaluation( new ilAccessibilityLogicalAndDocumentCriteriaEvaluation( $c['acc.criteria.type.factory'], @@ -1154,7 +1157,7 @@ public static function initILIAS(): void return; } - $GLOBALS["DIC"]["ilLoggerFactory"] = function ($c) { + $GLOBALS["DIC"]["ilLoggerFactory"] = static function ($c) { return ilLoggerFactory::getInstance(); }; @@ -1479,9 +1482,9 @@ protected static function handleAuthenticationFail(): void } /** - * @param \ILIAS\DI\Container $container + * @param Container $container */ - protected static function initHTTPServices(\ILIAS\DI\Container $container): void + protected static function initHTTPServices(Container $container): void { $init_http = new InitHttpServices(); $init_http->init($container); @@ -1490,11 +1493,11 @@ protected static function initHTTPServices(\ILIAS\DI\Container $container): void } /** - * @param \ILIAS\DI\Container $c + * @param Container $c */ - private static function initGlobalScreen(\ILIAS\DI\Container $c): void + private static function initGlobalScreen(Container $c): void { - $c['global_screen'] = function () use ($c) { + $c['global_screen'] = static function () use ($c) { return new Services( new ilGSProviderFactory($c), $c->ui(), @@ -1509,7 +1512,7 @@ private static function initGlobalScreen(\ILIAS\DI\Container $c): void * @deprecated this mechanism will be removed as part of the component revision and * the refactoring to the new bootstrap mechanism. */ - public static function applyPluginManipulationsToUiFramework(\ILIAS\DI\Container $c): void + public static function applyPluginManipulationsToUiFramework(Container $c): void { $component_repository = $c["component.repository"]; $component_factory = $c["component.factory"]; @@ -1533,7 +1536,7 @@ public static function applyPluginManipulationsToUiFramework(\ILIAS\DI\Container /** * @param Container $container */ - protected static function replaceSuperGlobals(\ILIAS\DI\Container $container): void + protected static function replaceSuperGlobals(Container $container): void { /** @var ilIniFile $client_ini */ $client_ini = $container['ilClientIniFile']; @@ -1553,7 +1556,7 @@ protected static function replaceSuperGlobals(\ILIAS\DI\Container $container): v } } - protected static function initComponentService(\ILIAS\DI\Container $container): void + protected static function initComponentService(Container $container): void { $init = new InitComponentService(); $init->init($container); @@ -1893,7 +1896,7 @@ public static function redirectToStartingPage(string $target = ''): void } } - private static function initBackgroundTasks(\ILIAS\DI\Container $c): void + private static function initBackgroundTasks(Container $c): void { global $ilIliasIniFile; @@ -1903,19 +1906,19 @@ private static function initBackgroundTasks(\ILIAS\DI\Container $c): void $n_of_tasks = $n_of_tasks ?: 5; $sync = $sync ?: 'sync'; // The default value is sync. - $c["bt.task_factory"] = function ($c) { + $c["bt.task_factory"] = static function ($c) { return new \ILIAS\BackgroundTasks\Implementation\Tasks\BasicTaskFactory($c["di.injector"]); }; - $c["bt.persistence"] = function ($c) { + $c["bt.persistence"] = static function ($c) { return \ILIAS\BackgroundTasks\Implementation\Persistence\BasicPersistence::instance($c->database()); }; - $c["bt.injector"] = function ($c) { + $c["bt.injector"] = static function ($c) { return new \ILIAS\BackgroundTasks\Dependencies\Injector($c, new BaseDependencyMap()); }; - $c["bt.task_manager"] = function ($c) use ($sync) { + $c["bt.task_manager"] = static function ($c) use ($sync) { if ($sync == 'sync') { return new \ILIAS\BackgroundTasks\Implementation\TaskManager\SyncTaskManager($c["bt.persistence"]); } elseif ($sync == 'async') { @@ -1926,20 +1929,20 @@ private static function initBackgroundTasks(\ILIAS\DI\Container $c): void }; } - private static function initInjector(\ILIAS\DI\Container $c): void + private static function initInjector(Container $c): void { - $c["di.dependency_map"] = function ($c) { + $c["di.dependency_map"] = static function ($c) { return new \ILIAS\BackgroundTasks\Dependencies\DependencyMap\BaseDependencyMap(); }; - $c["di.injector"] = function ($c) { + $c["di.injector"] = static function ($c) { return new \ILIAS\BackgroundTasks\Dependencies\Injector($c, $c["di.dependency_map"]); }; } - private static function initKioskMode(\ILIAS\DI\Container $c): void + private static function initKioskMode(Container $c): void { - $c["service.kiosk_mode"] = function ($c) { + $c["service.kiosk_mode"] = static function ($c) { return new ilKioskModeService( $c['ilCtrl'], $c['lng'], @@ -1949,9 +1952,9 @@ private static function initKioskMode(\ILIAS\DI\Container $c): void }; } - private static function initLearningObjectMetadata(\ILIAS\DI\Container $c): void + private static function initLearningObjectMetadata(Container $c): void { - $c['learning_object_metadata'] = function ($c) { + $c['learning_object_metadata'] = static function ($c) { return new \ILIAS\MetaData\Services\Services($c); }; } diff --git a/components/ILIAS/Init/src/AllModernComponents.php b/components/ILIAS/Init/src/AllModernComponents.php index cd3393e9e783..b8c3b63ad18d 100644 --- a/components/ILIAS/Init/src/AllModernComponents.php +++ b/components/ILIAS/Init/src/AllModernComponents.php @@ -95,6 +95,7 @@ public function __construct( protected \ILIAS\UI\Implementation\Component\Input\UploadLimitResolver $ui_upload_limit_resolver, protected \ILIAS\Setup\AgentFinder $setup_agent_finder, protected \ILIAS\UI\Implementation\Component\Navigation\Factory $ui_factory_navigation, + protected \ILIAS\Cron\CronJobRegistry $cron_job_registry, ) { } @@ -172,6 +173,7 @@ protected function populateComponentsInLegacyEnvironment(\Pimple\Container $DIC) $DIC['ui.renderer'] = fn() => $this->ui_renderer; $DIC['setup.agentfinder'] = fn() => $this->setup_agent_finder; $DIC['ui.factory.navigation'] = fn() => $this->ui_factory_input_field; + $DIC[\ILIAS\Cron\CronJobRegistry::class] = fn() => $this->cron_job_registry; } public function getName(): string diff --git a/components/ILIAS/LDAP/LDAP.php b/components/ILIAS/LDAP/LDAP.php index 2488615ea94c..41a14623324a 100644 --- a/components/ILIAS/LDAP/LDAP.php +++ b/components/ILIAS/LDAP/LDAP.php @@ -33,6 +33,13 @@ public function init( array | \ArrayAccess &$internal, ): void { $contribute[\ILIAS\Setup\Agent::class] = static fn() => - new \ILIAS\LDAP\Setup\Agent(); + new \ILIAS\LDAP\Setup\Agent(); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilLDAPCronSynchronization( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/LDAP/classes/class.ilLDAPCronSynchronization.php b/components/ILIAS/LDAP/classes/class.ilLDAPCronSynchronization.php index 0df6facc2439..5067dbd8b7e3 100755 --- a/components/ILIAS/LDAP/classes/class.ilLDAPCronSynchronization.php +++ b/components/ILIAS/LDAP/classes/class.ilLDAPCronSynchronization.php @@ -21,43 +21,42 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobManager; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * * @author Stefan Meyer */ -class ilLDAPCronSynchronization extends CronJob +class ilLDAPCronSynchronization extends AbstractCronJob { - private ilLanguage $lng; private ilLogger $logger; private JobManager $cronManager; private int $counter = 0; - public function __construct() + public function init(): void { global $DIC; + $this->language->loadLanguageModule('ldap'); + $this->logger = $DIC->logger()->auth(); $this->cronManager = $DIC->cron()->manager(); - $this->lng = $DIC->language(); - $this->lng->loadLanguageModule('ldap'); } public function getId(): string { - return "ldap_sync"; + return 'ldap_sync'; } public function getTitle(): string { - return $this->lng->txt('ldap_user_sync_cron'); + return $this->language->txt('ldap_user_sync_cron'); } public function getDescription(): string { - return $this->lng->txt("ldap_user_sync_cron_info"); + return $this->language->txt('ldap_user_sync_cron_info'); } public function getDefaultScheduleType(): JobScheduleType @@ -84,12 +83,12 @@ public function run(): JobResult { $status = JobResult::STATUS_NO_ACTION; - $messages = array(); + $messages = []; foreach (ilLDAPServer::_getCronServerIds() as $server_id) { try { $current_server = new ilLDAPServer($server_id); $current_server->doConnectionCheck(); - $this->logger->info("LDAP: starting user synchronization for " . $current_server->getName()); + $this->logger->info('LDAP: starting user synchronization for ' . $current_server->getName()); $ldap_query = new ilLDAPQuery($current_server); $ldap_query->bind(); @@ -105,13 +104,13 @@ public function run(): JobResult $offset = 0; $limit = 500; while ($user_sliced = array_slice($users, $offset, $limit, true)) { - $this->logger->info("LDAP: Starting update/creation of users ..."); - $this->logger->info("LDAP: Offset: " . $offset); + $this->logger->info('LDAP: Starting update/creation of users ...'); + $this->logger->info('LDAP: Offset: ' . $offset); $ldap_to_ilias = new ilLDAPAttributeToUser($current_server); $ldap_to_ilias->setNewUserAuthMode($current_server->getAuthenticationMappingKey()); $ldap_to_ilias->setUserData($user_sliced); $ldap_to_ilias->refresh(); - $this->logger->info("LDAP: Finished update/creation"); + $this->logger->info('LDAP: Finished update/creation'); $offset += $limit; @@ -119,7 +118,7 @@ public function run(): JobResult } $this->counter++; } else { - $this->logger->info("LDAP: No users for update/create. Aborting."); + $this->logger->info('LDAP: No users for update/create. Aborting.'); } } catch (ilLDAPQueryException $exc) { $mess = $exc->getMessage(); @@ -165,10 +164,10 @@ private function deactivateUsers(ilLDAPServer $server, array $a_ldap_users): voi public function addToExternalSettingsForm(int $a_form_id, array &$a_fields, bool $a_is_active): void { if ($a_form_id === ilAdministrationSettingsFormHandler::FORM_LDAP) { - $a_fields["ldap_user_sync_cron"] = [$a_is_active ? - $this->lng->txt("enabled") : - $this->lng->txt("disabled"), - ilAdministrationSettingsFormHandler::VALUE_BOOL]; + $a_fields['ldap_user_sync_cron'] = [$a_is_active ? + $this->language->txt('enabled') : + $this->language->txt('disabled'), + ilAdministrationSettingsFormHandler::VALUE_BOOL]; } } } diff --git a/components/ILIAS/LDAP/service.xml b/components/ILIAS/LDAP/service.xml index b80fb92c506e..7b0dde5bd2a0 100755 --- a/components/ILIAS/LDAP/service.xml +++ b/components/ILIAS/LDAP/service.xml @@ -6,7 +6,4 @@ - - - diff --git a/components/ILIAS/LTIProvider/LTIProvider.php b/components/ILIAS/LTIProvider/LTIProvider.php index fd0843291de0..959c41db8328 100644 --- a/components/ILIAS/LTIProvider/LTIProvider.php +++ b/components/ILIAS/LTIProvider/LTIProvider.php @@ -39,5 +39,12 @@ public function init( $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\Endpoint($this, "lti.php"); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilLTICronOutcomeService( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/LTIProvider/classes/class.ilLTICronOutcomeService.php b/components/ILIAS/LTIProvider/classes/class.ilLTICronOutcomeService.php index 0a67f37772b2..cf37e82a517c 100644 --- a/components/ILIAS/LTIProvider/classes/class.ilLTICronOutcomeService.php +++ b/components/ILIAS/LTIProvider/classes/class.ilLTICronOutcomeService.php @@ -21,7 +21,7 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobRepository; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Description of class class @@ -29,19 +29,20 @@ * @author Stefan Meyer * */ -class ilLTICronOutcomeService extends CronJob +class ilLTICronOutcomeService extends AbstractCronJob { - private ilLanguage $lng; private JobRepository $cronRepo; - public function __construct() + public function init(): void { global $DIC; - $this->lng = $DIC->language(); - $this->lng->loadLanguageModule("lti"); + + $this->language->loadLanguageModule("lti"); + $this->cronRepo = $DIC->cron()->repository(); } + public function getDefaultScheduleType(): JobScheduleType { return JobScheduleType::DAILY; @@ -69,17 +70,17 @@ public function hasFlexibleSchedule(): bool public function getTitle(): string { - return $this->lng->txt('lti_cron_title'); + return $this->language->txt('lti_cron_title'); } public function getDescription(): string { - return $this->lng->txt('lti_cron_title_desc'); + return $this->language->txt('lti_cron_title_desc'); } public function run(): JobResult { - $status = \ILIAS\Cron\Job\JobResult::STATUS_NO_ACTION; + $status = JobResult::STATUS_NO_ACTION; $info = $this->cronRepo->getCronJobData($this->getId()); $last_ts = $info['job_status_ts'] ?? false; @@ -89,7 +90,7 @@ public function run(): JobResult $since = new ilDateTime($last_ts, IL_CAL_UNIX); - $result = new \ILIAS\Cron\Job\JobResult(); + $result = new JobResult(); $result->setStatus($status); ilLTIAppEventListener::handleCronUpdate($since); $result->setStatus(JobResult::STATUS_OK); diff --git a/components/ILIAS/LTIProvider/service.xml b/components/ILIAS/LTIProvider/service.xml index 0d2564f42fa7..b35e0640222e 100644 --- a/components/ILIAS/LTIProvider/service.xml +++ b/components/ILIAS/LTIProvider/service.xml @@ -13,8 +13,5 @@ - - - diff --git a/components/ILIAS/Logging/Logging.php b/components/ILIAS/Logging/Logging.php index ea5202974232..e8e2438894b7 100644 --- a/components/ILIAS/Logging/Logging.php +++ b/components/ILIAS/Logging/Logging.php @@ -32,9 +32,65 @@ public function init( array | \ArrayAccess &$pull, array | \ArrayAccess &$internal, ): void { + $define[] = \ILIAS\Logging\LoggerFactory::class; + + $implement[\ILIAS\Logging\LoggerFactory::class] = static fn() => + $internal[\ilLoggerFactory::class]; + + $contribute[\ILIAS\Setup\Agent::class] = static fn() => new \ilLoggingSetupAgent( $pull[\ILIAS\Refinery\Factory::class] ); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilLoggerCronCleanErrorFiles( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); + + $internal[\ilLoggerFactory::class] = static fn() => + \ilLoggerFactory::getInstance( + $internal[\ilLoggingSettings::class] + ); + + $internal[\ilLoggingSettings::class] = static fn() => + new class () implements \ilLoggingSettings { + public function isEnabled(): bool + { + return false; + } + public function getLogDir(): string + { + } + public function getLogFile(): string + { + } + public function getLevel(): int + { + } + public function getLevelByComponent(string $a_component_id): int + { + } + public function getCacheLevel(): int + { + } + public function isCacheEnabled(): bool + { + } + public function isMemoryUsageEnabled(): bool + { + } + public function isBrowserLogEnabled(): bool + { + } + public function isBrowserLogEnabledForUser(string $a_login): bool + { + } + public function getBrowserLogUsers(): array + { + } + }; } } diff --git a/components/ILIAS/Logging/classes/error/class.ilLoggerCronCleanErrorFiles.php b/components/ILIAS/Logging/classes/error/class.ilLoggerCronCleanErrorFiles.php index 748470e98756..3da738e80dbb 100755 --- a/components/ILIAS/Logging/classes/error/class.ilLoggerCronCleanErrorFiles.php +++ b/components/ILIAS/Logging/classes/error/class.ilLoggerCronCleanErrorFiles.php @@ -4,7 +4,7 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * This file is part of ILIAS, a powerful learning management system @@ -22,20 +22,17 @@ * *********************************************************************/ -class ilLoggerCronCleanErrorFiles extends CronJob +class ilLoggerCronCleanErrorFiles extends AbstractCronJob { protected const DEFAULT_VALUE_OLDER_THAN = 31; - protected ilLanguage $lng; protected ilSetting $settings; protected ilLoggingErrorSettings $error_settings; - public function __construct() + public function init(): void { - global $DIC; + $this->language->loadLanguageModule("logging"); - $this->lng = $DIC->language(); - $this->lng->loadLanguageModule("logging"); $this->settings = new ilSetting('log'); $this->error_settings = ilLoggingErrorSettings::getInstance(); } @@ -47,12 +44,12 @@ public function getId(): string public function getTitle(): string { - return $this->lng->txt("log_error_file_cleanup_title"); + return $this->language->txt("log_error_file_cleanup_title"); } public function getDescription(): string { - return $this->lng->txt("log_error_file_cleanup_info"); + return $this->language->txt("log_error_file_cleanup_info"); } public function getDefaultScheduleType(): JobScheduleType @@ -86,7 +83,7 @@ public function run(): JobResult $folder = $this->error_settings->folder(); if (!is_dir($folder)) { $result->setStatus(JobResult::STATUS_OK); - $result->setMessage($this->lng->txt("log_error_path_not_configured_or_wrong")); + $result->setMessage($this->language->txt("log_error_path_not_configured_or_wrong")); return $result; } @@ -140,11 +137,11 @@ public function addCustomSettingsToForm(ilPropertyFormGUI $a_form): void $offset = (string) self::DEFAULT_VALUE_OLDER_THAN; } - $clear_older_then = new ilNumberInputGUI($this->lng->txt('frm_clear_older_then'), 'clear_older_then'); + $clear_older_then = new ilNumberInputGUI($this->language->txt('frm_clear_older_then'), 'clear_older_then'); $clear_older_then->allowDecimals(false); $clear_older_then->setMinValue(1, true); $clear_older_then->setValue($offset); - $clear_older_then->setInfo($this->lng->txt('frm_clear_older_then_info')); + $clear_older_then->setInfo($this->language->txt('frm_clear_older_then_info')); $a_form->addItem($clear_older_then); } diff --git a/components/ILIAS/Logging/classes/public/class.ilLoggerFactory.php b/components/ILIAS/Logging/classes/public/class.ilLoggerFactory.php index e865f2b34aca..c8be1e189e09 100755 --- a/components/ILIAS/Logging/classes/public/class.ilLoggerFactory.php +++ b/components/ILIAS/Logging/classes/public/class.ilLoggerFactory.php @@ -34,7 +34,7 @@ * @author Stefan Meyer * */ -class ilLoggerFactory +class ilLoggerFactory implements \ILIAS\Logging\LoggerFactory { protected const DEFAULT_FORMAT = "[%extra.suid%] [%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"; @@ -44,8 +44,7 @@ class ilLoggerFactory private static ?ilLoggerFactory $instance = null; - private ilLoggingSettings $settings; - protected Container $dic; + protected ?Container $dic; private bool $enabled = false; //ToDo PHP8 Review: This is a private var never read only written and should probably be removed. @@ -54,21 +53,25 @@ class ilLoggerFactory */ private array $loggers = array(); - protected function __construct(ilLoggingSettings $settings) + protected function __construct(private ilLoggingSettings $settings) { global $DIC; $this->dic = $DIC; - $this->settings = $settings; $this->enabled = $this->getSettings()->isEnabled(); } - public static function getInstance(): ilLoggerFactory + public static function getInstance(?\ilLoggingSettings $settings = null): ilLoggerFactory { - if (!static::$instance instanceof ilLoggerFactory) { + if ($settings === null) { $settings = ilLoggingDBSettings::getInstance(); + static::$instance = null; + } + + if (!static::$instance instanceof self) { static::$instance = new ilLoggerFactory($settings); } + return static::$instance; } diff --git a/components/ILIAS/Logging/service.xml b/components/ILIAS/Logging/service.xml index 13cdbbe73f12..31e109a29e12 100755 --- a/components/ILIAS/Logging/service.xml +++ b/components/ILIAS/Logging/service.xml @@ -9,8 +9,5 @@ adm - - - diff --git a/components/ILIAS/Cron/src/Job/JobProvider.php b/components/ILIAS/Logging/src/LoggerFactory.php similarity index 62% rename from components/ILIAS/Cron/src/Job/JobProvider.php rename to components/ILIAS/Logging/src/LoggerFactory.php index f776c0e9aa33..1e2419cf0a6c 100644 --- a/components/ILIAS/Cron/src/Job/JobProvider.php +++ b/components/ILIAS/Logging/src/LoggerFactory.php @@ -18,17 +18,12 @@ declare(strict_types=1); -namespace ILIAS\Cron\Job; +namespace ILIAS\Logging; -interface JobProvider +/** + * Abstraction for {@see \ilLoggerFactory} so component dependency names follow `Vendor\Package\Type`. + */ +interface LoggerFactory { - /** - * @return list<\ILIAS\Cron\CronJob> - */ - public function getCronJobInstances(): array; - - /** - * @throws \OutOfBoundsException if the passed argument does not match any cron job - */ - public function getCronJobInstance(string $jobId): \ILIAS\Cron\CronJob; + public function getComponentLogger(string $a_component_id): \ilLogger; } diff --git a/components/ILIAS/Mail/Mail.php b/components/ILIAS/Mail/Mail.php index b6b188826140..626ec5d573a6 100644 --- a/components/ILIAS/Mail/Mail.php +++ b/components/ILIAS/Mail/Mail.php @@ -35,16 +35,33 @@ public function init( array | \ArrayAccess &$internal, ): void { $contribute[\ILIAS\Setup\Agent::class] = static fn() => - new \ilMailSetupAgent( - $pull[\ILIAS\Refinery\Factory::class] - ); + new \ilMailSetupAgent(); $contribute[Component\Resource\PublicAsset::class] = fn() => - new Component\Resource\ComponentJS($this, "ilMailComposeFunctions.js"); + new Component\Resource\ComponentJS($this, 'ilMailComposeFunctions.js'); $contribute[Component\Resource\PublicAsset::class] = fn() => new ComponentCSS($this, '/../../../../templates/default/mail.css'); - $contribute[User\Settings\UserSettings::class] = fn() => + $contribute[User\Settings\UserSettings::class] = static fn() => new Mail\UserSettings\Settings(); - $contribute[User\Profile\ChangeListeners\UserFieldAttributesChangeListener::class] = fn() => + $contribute[User\Profile\ChangeListeners\UserFieldAttributesChangeListener::class] = static fn() => new Mail\ilMailUserFieldChangeListener(); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilMailCronNotification( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilMailCronOrphanedMails( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ILIAS\Mail\Cron\ScheduledMailsCron( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/Mail/classes/class.ilMailCronNotification.php b/components/ILIAS/Mail/classes/class.ilMailCronNotification.php index dff50f39d2d7..9839100fec4d 100755 --- a/components/ILIAS/Mail/classes/class.ilMailCronNotification.php +++ b/components/ILIAS/Mail/classes/class.ilMailCronNotification.php @@ -18,29 +18,21 @@ declare(strict_types=1); -use ILIAS\HTTP\GlobalHttpState; use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; -class ilMailCronNotification extends CronJob +class ilMailCronNotification extends AbstractCronJob { - private GlobalHttpState $http; - protected ilLanguage $lng; - protected ilSetting $settings; - protected bool $init_done = false; + private ilSetting $settings; - protected function init(): void + public function init(): void { global $DIC; - if (!$this->init_done) { - $this->settings = $DIC->settings(); - $this->lng = $DIC->language(); - $this->http = $DIC->http(); + $this->language->loadLanguageModule('mail'); - $this->init_done = true; - } + $this->settings = $DIC->settings(); } public function getId(): string @@ -50,20 +42,14 @@ public function getId(): string public function getTitle(): string { - $this->init(); - - return $this->lng->txt('cron_mail_notification'); + return $this->language->txt('cron_mail_notification'); } public function getDescription(): string { - $this->init(); - - $this->lng->loadLanguageModule('mail'); - return sprintf( - $this->lng->txt('cron_mail_notification_desc'), - $this->lng->txt('mail_allow_external') + $this->language->txt('cron_mail_notification_desc'), + $this->language->txt('mail_allow_external') ); } @@ -105,8 +91,8 @@ public function getCustomConfigurationInput( $status = $ui_factory ->input() ->field() - ->checkbox($this->lng->txt('cron_mail_notification_message')) - ->withByline($this->lng->txt('cron_mail_notification_message_info')) + ->checkbox($this->language->txt('cron_mail_notification_message')) + ->withByline($this->language->txt('cron_mail_notification_message_info')) ->withValue((bool) $this->settings->get('mail_notification_message', '0')) ->withDedicatedName('mail_notification_message'); @@ -115,7 +101,6 @@ public function getCustomConfigurationInput( public function saveCustomConfiguration(mixed $form_data): void { - $this->init(); $this->settings->set( 'mail_notification_message', (string) ((int) $form_data) diff --git a/components/ILIAS/Mail/classes/class.ilMailCronOrphanedMails.php b/components/ILIAS/Mail/classes/class.ilMailCronOrphanedMails.php index c5c23a0e1887..f024175e0dab 100755 --- a/components/ILIAS/Mail/classes/class.ilMailCronOrphanedMails.php +++ b/components/ILIAS/Mail/classes/class.ilMailCronOrphanedMails.php @@ -18,7 +18,6 @@ declare(strict_types=1); -use ILIAS\HTTP\GlobalHttpState; use ILIAS\Refinery\Factory as Refinery; use ILIAS\Refinery\Transformation; use ILIAS\Mail\Cron\ExpiredOrOrphanedMails\ExpiredOrOrphanedMailsCollector; @@ -28,35 +27,29 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobManager; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; -class ilMailCronOrphanedMails extends CronJob +class ilMailCronOrphanedMails extends AbstractCronJob { - private GlobalHttpState $http; + private \ILIAS\HTTP\GlobalHttpState $http; private Refinery $refinery; - private ilLanguage $lng; private ilSetting $settings; private ilDBInterface $db; private ilObjUser $user; - private bool $init_done = false; private JobManager $cron_manager; - private function init(): void + public function init(): void { global $DIC; - if (!$this->init_done) { - $this->settings = $DIC->settings(); - $this->lng = $DIC->language(); - $this->db = $DIC->database(); - $this->user = $DIC->user(); - $this->http = $DIC->http(); - $this->refinery = $DIC->refinery(); - $this->cron_manager = $DIC->cron()->manager(); - - $this->lng->loadLanguageModule('mail'); - $this->init_done = true; - } + $this->language->loadLanguageModule('mail'); + + $this->settings = $DIC->settings(); + $this->db = $DIC->database(); + $this->user = $DIC->user(); + $this->http = $DIC->http(); + $this->refinery = $DIC->refinery(); + $this->cron_manager = $DIC->cron()->manager(); } private function emptyStringOrFloatOrIntToEmptyOrIntegerString(): Transformation @@ -89,14 +82,12 @@ public function getId(): string public function getTitle(): string { - $this->init(); - return $this->lng->txt('mail_orphaned_mails'); + return $this->language->txt('mail_orphaned_mails'); } public function getDescription(): string { - $this->init(); - return $this->lng->txt('mail_orphaned_mails_desc'); + return $this->language->txt('mail_orphaned_mails_desc'); } public function hasAutoActivation(): bool @@ -138,14 +129,12 @@ public function hasCustomSettings(): bool public function addCustomSettingsToForm(ilPropertyFormGUI $a_form): void { - $this->init(); - parent::addCustomSettingsToForm($a_form); - $threshold = new ilNumberInputGUI($this->lng->txt('mail_threshold'), 'mail_threshold'); - $threshold->setInfo($this->lng->txt('mail_threshold_info')); + $threshold = new ilNumberInputGUI($this->language->txt('mail_threshold'), 'mail_threshold'); + $threshold->setInfo($this->language->txt('mail_threshold_info')); $threshold->allowDecimals(false); - $threshold->setSuffix($this->lng->txt('days')); + $threshold->setSuffix($this->language->txt('days')); $threshold->setMinValue(1); $threshold->setSize(4); $threshold->setValue($this->settings->get('mail_threshold', '')); @@ -153,22 +142,22 @@ public function addCustomSettingsToForm(ilPropertyFormGUI $a_form): void $a_form->addItem($threshold); $mail_folder = new ilCheckboxInputGUI( - $this->lng->txt('only_inbox_trash'), + $this->language->txt('only_inbox_trash'), 'mail_only_inbox_trash' ); $mail_folder->setValue('1'); - $mail_folder->setInfo($this->lng->txt('only_inbox_trash_info')); + $mail_folder->setInfo($this->language->txt('only_inbox_trash_info')); $mail_folder->setChecked((bool) $this->settings->get('mail_only_inbox_trash', '0')); $a_form->addItem($mail_folder); $notification = new ilNumberInputGUI( - $this->lng->txt('mail_notify_orphaned'), + $this->language->txt('mail_notify_orphaned'), 'mail_notify_orphaned' ); - $notification->setInfo($this->lng->txt('mail_notify_orphaned_info')); + $notification->setInfo($this->language->txt('mail_notify_orphaned_info')); $notification->allowDecimals(false); $notification->setSize(4); - $notification->setSuffix($this->lng->txt('days')); + $notification->setSuffix($this->language->txt('days')); $notification->setMinValue(0); if ($this->http->wrapper()->post()->has('mail_threshold')) { @@ -187,8 +176,6 @@ public function addCustomSettingsToForm(ilPropertyFormGUI $a_form): void public function saveCustomSettings(ilPropertyFormGUI $a_form): bool { - $this->init(); - $this->settings->set('mail_only_inbox_trash', (string) ((int) $a_form->getInput('mail_only_inbox_trash'))); $this->settings->set( 'mail_threshold', @@ -221,8 +208,6 @@ public function ping(): void public function run(): JobResult { - $this->init(); - $mail_expiration_days = (int) $this->settings->get('mail_threshold', '0'); ilLoggerFactory::getLogger('mail')->info(sprintf( @@ -252,8 +237,6 @@ public function run(): JobResult private function processNotification(): void { - $this->init(); - $notifier = new Notifier( $this, new NotificationsCollector($this), @@ -265,8 +248,6 @@ private function processNotification(): void private function processDeletion(): void { - $this->init(); - $processor = new MailDeletionHandler($this, new ExpiredOrOrphanedMailsCollector($this)); $processor->delete(); } diff --git a/components/ILIAS/Mail/service.xml b/components/ILIAS/Mail/service.xml index 11b9fefc636d..80122b01f2fa 100755 --- a/components/ILIAS/Mail/service.xml +++ b/components/ILIAS/Mail/service.xml @@ -10,11 +10,6 @@ adm - - - - - diff --git a/components/ILIAS/Mail/src/Cron/ScheduledMailsCron.php b/components/ILIAS/Mail/src/Cron/ScheduledMailsCron.php index e503c99d2ad0..68f8ebe5a566 100644 --- a/components/ILIAS/Mail/src/Cron/ScheduledMailsCron.php +++ b/components/ILIAS/Mail/src/Cron/ScheduledMailsCron.php @@ -21,55 +21,40 @@ namespace ILIAS\Mail\Cron; use ilMail; -use Generator; use ilContext; use ilObjUser; use Throwable; -use ilLanguage; -use DateTimeZone; use ilFormatMail; -use ilDBConstants; -use ilDBInterface; -use ilLoggerFactory; -use DateTimeImmutable; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; use ILIAS\Cron\Job\JobResult; -use ILIAS\Data\Clock\ClockFactory; -use ILIAS\Mail\Folder\MailFolderType; use ILIAS\Data\Factory as DataFactory; use ILIAS\Cron\Job\Schedule\JobScheduleType; use MailDeliveryData; use ILIAS\Mail\Folder\OutboxDatabaseRepository; use ILIAS\Mail\Folder\OutboxRepository; -use ILIAS\Mail\Folder\MailScheduleData; -class ScheduledMailsCron extends CronJob +class ScheduledMailsCron extends AbstractCronJob { - private readonly ilLanguage $lng; - private readonly ilObjUser $user; - private bool $init_done = false; - private readonly ilMail $mail; - private readonly ilFormatMail $umail; + private ilObjUser $user; + private ilMail $mail; + private ilFormatMail $umail; private OutboxRepository $outbox_repository; - private function init(): void + public function init(): void { global $DIC; - if (!$this->init_done) { - $this->lng = $DIC->language(); - $this->user = $DIC->user(); - $this->mail = new ilMail($this->user->getId()); - $this->umail = new ilFormatMail($this->user->getId()); - - $this->lng->loadLanguageModule('mail'); - $this->init_done = true; - $this->outbox_repository = new OutboxDatabaseRepository( - $DIC->database(), - (new DataFactory())->clock(), - $this->mail - ); - } + $this->language->loadLanguageModule('mail'); + + $this->user = $DIC->user(); + $this->mail = new ilMail($this->user->getId()); + $this->umail = new ilFormatMail($this->user->getId()); + + $this->outbox_repository = new OutboxDatabaseRepository( + $DIC->database(), + new DataFactory()->clock(), + $this->mail + ); } public function getId(): string @@ -79,16 +64,12 @@ public function getId(): string public function getTitle(): string { - $this->init(); - - return $this->lng->txt('mail_cron_scheduled_mails'); + return $this->language->txt('mail_cron_scheduled_mails'); } public function getDescription(): string { - $this->init(); - - return $this->lng->txt('mail_cron_scheduled_mails_desc'); + return $this->language->txt('mail_cron_scheduled_mails_desc'); } public function hasAutoActivation(): bool @@ -113,12 +94,10 @@ public function getDefaultScheduleValue(): ?int public function run(): JobResult { - $this->init(); - $job_result = new JobResult(); $job_result->setStatus(JobResult::STATUS_OK); - ilLoggerFactory::getLogger('mail')->info('Start sending scheduled mails from all users.'); + \ilLoggerFactory::getLogger('mail')->info('Start sending scheduled mails from all users.'); $mails = $this->outbox_repository->getOutboxMails(); $sent_mail_ids = []; @@ -146,7 +125,7 @@ public function run(): JobResult } } catch (Throwable $e) { $job_result->setStatus(JobResult::STATUS_FAIL); - ilLoggerFactory::getLogger('mail')->error( + \ilLoggerFactory::getLogger('mail')->error( 'Error sending scheduled mail with id ' . ((string) ($mail->getInternalMailId() ?? 'unknown')) . ': ' . $e->getMessage() . '\n' . $e->getTraceAsString() ); @@ -158,10 +137,10 @@ public function run(): JobResult $this->mail->deleteMails($sent_mail_ids); } } - ilLoggerFactory::getLogger('mail')->info( - 'Sent ' . count($sent_mail_ids) . ' scheduled mails and removed them from outbox.' + \ilLoggerFactory::getLogger('mail')->info( + 'Sent ' . \count($sent_mail_ids) . ' scheduled mails and removed them from outbox.' ); - $job_result->setMessage('Processed ' . count($sent_mail_ids) . ' mails.'); + $job_result->setMessage('Processed ' . \count($sent_mail_ids) . ' mails.'); return $job_result; } diff --git a/components/ILIAS/Membership/Membership.php b/components/ILIAS/Membership/Membership.php index b43c82b90d66..52ca68e6e662 100644 --- a/components/ILIAS/Membership/Membership.php +++ b/components/ILIAS/Membership/Membership.php @@ -32,6 +32,17 @@ public function init( array | \ArrayAccess &$pull, array | \ArrayAccess &$internal, ): void { - // ... + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilMembershipCronNotifications( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilMembershipCronMinMembers( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/Membership/classes/Cron/class.ilMembershipCronMinMembers.php b/components/ILIAS/Membership/classes/Cron/class.ilMembershipCronMinMembers.php index b35b70407284..3ddef8d74320 100755 --- a/components/ILIAS/Membership/classes/Cron/class.ilMembershipCronMinMembers.php +++ b/components/ILIAS/Membership/classes/Cron/class.ilMembershipCronMinMembers.php @@ -20,24 +20,15 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Cron for course/group minimum members * @author Jörg Lützenkirchen * @ingroup ServicesMembership */ -class ilMembershipCronMinMembers extends CronJob +class ilMembershipCronMinMembers extends AbstractCronJob { - protected ilLanguage $lng; - - public function __construct() - { - global $DIC; - - $this->lng = $DIC->language(); - } - public function getId(): string { return "mem_min_members"; @@ -45,12 +36,12 @@ public function getId(): string public function getTitle(): string { - return $this->lng->txt("mem_cron_min_members"); + return $this->language->txt("mem_cron_min_members"); } public function getDescription(): string { - return $this->lng->txt("mem_cron_min_members_info"); + return $this->language->txt("mem_cron_min_members_info"); } public function getDefaultScheduleType(): JobScheduleType diff --git a/components/ILIAS/Membership/classes/Cron/class.ilMembershipCronNotifications.php b/components/ILIAS/Membership/classes/Cron/class.ilMembershipCronNotifications.php index c0fea84531eb..1a70caf8b307 100755 --- a/components/ILIAS/Membership/classes/Cron/class.ilMembershipCronNotifications.php +++ b/components/ILIAS/Membership/classes/Cron/class.ilMembershipCronNotifications.php @@ -20,24 +20,22 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Course/group notifications * @author Jörg Lützenkirchen */ -class ilMembershipCronNotifications extends CronJob +class ilMembershipCronNotifications extends AbstractCronJob { - protected ilLanguage $lng; protected ilDBInterface $db; protected ilLogger $logger; protected ilTree $tree; - public function __construct() + public function init(): void { global $DIC; - $this->lng = $DIC->language(); $this->db = $DIC->database(); $this->logger = $DIC->logger()->mmbr(); $this->tree = $DIC->repositoryTree(); @@ -55,12 +53,12 @@ public function getId(): string public function getTitle(): string { - return $this->lng->txt("enable_course_group_notifications"); + return $this->language->txt("enable_course_group_notifications"); } public function getDescription(): string { - return $this->lng->txt("enable_course_group_notifications_desc"); + return $this->language->txt("enable_course_group_notifications_desc"); } public function getDefaultScheduleType(): JobScheduleType @@ -485,8 +483,8 @@ public function addToExternalSettingsForm(int $a_form_id, array &$a_fields, bool case ilAdministrationSettingsFormHandler::FORM_COURSE: case ilAdministrationSettingsFormHandler::FORM_GROUP: $a_fields["enable_course_group_notifications"] = $a_is_active ? - $this->lng->txt("enabled") : - $this->lng->txt("disabled"); + $this->language->txt("enabled") : + $this->language->txt("disabled"); break; } } diff --git a/components/ILIAS/Membership/service.xml b/components/ILIAS/Membership/service.xml index d3cd9895e2e3..42c0459b8456 100755 --- a/components/ILIAS/Membership/service.xml +++ b/components/ILIAS/Membership/service.xml @@ -3,9 +3,5 @@ - - - - diff --git a/components/ILIAS/MetaData/MetaData.php b/components/ILIAS/MetaData/MetaData.php index 7fc312612276..c45d63e04bd3 100644 --- a/components/ILIAS/MetaData/MetaData.php +++ b/components/ILIAS/MetaData/MetaData.php @@ -42,5 +42,12 @@ public function init( $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\Endpoint($this, "oai.php"); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilCronOerHarvester( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/MetaData/classes/class.ilCronOerHarvester.php b/components/ILIAS/MetaData/classes/class.ilCronOerHarvester.php index 01f6e1dd7ba8..4d7f8086d76d 100755 --- a/components/ILIAS/MetaData/classes/class.ilCronOerHarvester.php +++ b/components/ILIAS/MetaData/classes/class.ilCronOerHarvester.php @@ -22,7 +22,7 @@ use ILIAS\MetaData\OERHarvester\Services\Services as PublishingServices; use ILIAS\MetaData\OERHarvester\CronJob\Results\Wrapper as ResultWrapper; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; use ILIAS\MetaData\Services\InternalServices; use ILIAS\MetaData\Presentation\UtilitiesInterface as PresentationUtilities; @@ -30,7 +30,7 @@ * Cron job for definition for oer harvesting * @author Stefan Meyer */ -class ilCronOerHarvester extends CronJob +class ilCronOerHarvester extends AbstractCronJob { public const string CRON_JOB_IDENTIFIER = 'meta_oer_harvester'; protected const int DEFAULT_SCHEDULE_VALUE = 1; @@ -39,7 +39,7 @@ class ilCronOerHarvester extends CronJob private PresentationUtilities $presentation_utilities; private PublishingServices $publishing_services; - public function __construct() + public function init(): void { global $DIC; diff --git a/components/ILIAS/MetaData/service.xml b/components/ILIAS/MetaData/service.xml index 47cd91d29cc2..76c5a1d3c82c 100755 --- a/components/ILIAS/MetaData/service.xml +++ b/components/ILIAS/MetaData/service.xml @@ -9,8 +9,5 @@ adm - - - diff --git a/components/ILIAS/OrgUnit/OrgUnit.php b/components/ILIAS/OrgUnit/OrgUnit.php index b65df02e25d1..3ad2eee35550 100644 --- a/components/ILIAS/OrgUnit/OrgUnit.php +++ b/components/ILIAS/OrgUnit/OrgUnit.php @@ -38,5 +38,12 @@ public function init( ); $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\ComponentJS($this, "authority.js"); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilCronUpdateOrgUnitPaths( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/OrgUnit/classes/class.ilCronUpdateOrgUnitPaths.php b/components/ILIAS/OrgUnit/classes/class.ilCronUpdateOrgUnitPaths.php index 11d3265d9943..61414091860c 100755 --- a/components/ILIAS/OrgUnit/classes/class.ilCronUpdateOrgUnitPaths.php +++ b/components/ILIAS/OrgUnit/classes/class.ilCronUpdateOrgUnitPaths.php @@ -18,28 +18,16 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Class ilCronUpdateOrgUnitPaths * @author Theodor Truffer * @author Fabian Schmid */ -class ilCronUpdateOrgUnitPaths extends CronJob +class ilCronUpdateOrgUnitPaths extends AbstractCronJob { public const ID = "orgunit_paths"; - protected ilDBInterface $db; - protected ilLogger $log; - protected ilTree $tree; - - private ilLanguage $lng; - - public function __construct() - { - global $DIC; - - $this->lng = $DIC->language(); - } public function getId(): string { @@ -48,12 +36,12 @@ public function getId(): string public function getTitle(): string { - return $this->lng->txt("update_orgunits"); + return $this->language->txt("update_orgunits"); } public function getDescription(): string { - return $this->lng->txt("update_orgunits_desc"); + return $this->language->txt("update_orgunits_desc"); } public function hasAutoActivation(): bool diff --git a/components/ILIAS/OrgUnit/module.xml b/components/ILIAS/OrgUnit/module.xml index d0ddab88bad9..4c681ae6b817 100755 --- a/components/ILIAS/OrgUnit/module.xml +++ b/components/ILIAS/OrgUnit/module.xml @@ -23,7 +23,4 @@ - - - diff --git a/components/ILIAS/Search/Search.php b/components/ILIAS/Search/Search.php index 117d81a1b60a..05f0e088c5a0 100644 --- a/components/ILIAS/Search/Search.php +++ b/components/ILIAS/Search/Search.php @@ -41,5 +41,12 @@ public function init( $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\ComponentJS($this, "Search.js"); $contribute[SetupAgent::class] = fn() => new SearchSetupAgent($pull[RefineryFactory::class]); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilLuceneIndexer( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/Search/classes/Lucene/class.ilLuceneIndexer.php b/components/ILIAS/Search/classes/Lucene/class.ilLuceneIndexer.php index 02f0529f526f..6db52410f995 100755 --- a/components/ILIAS/Search/classes/Lucene/class.ilLuceneIndexer.php +++ b/components/ILIAS/Search/classes/Lucene/class.ilLuceneIndexer.php @@ -5,7 +5,7 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Class for indexing hmtl ,pdf, txt files and htlm Learning modules. @@ -15,21 +15,20 @@ * * @package ServicesSearch */ -class ilLuceneIndexer extends CronJob +class ilLuceneIndexer extends AbstractCronJob { protected int $timeout = 60; - protected ilLanguage $lng; protected ilSetting $setting; - public function __construct() + public function init(): void { global $DIC; - $this->lng = $DIC->language(); $this->setting = $DIC->settings(); } + public function getId(): string { return "src_lucene_indexer"; @@ -37,12 +36,12 @@ public function getId(): string public function getTitle(): string { - return $this->lng->txt("cron_lucene_index"); + return $this->language->txt("cron_lucene_index"); } public function getDescription(): string { - return $this->lng->txt("cron_lucene_index_info"); + return $this->language->txt("cron_lucene_index_info"); } public function getDefaultScheduleType(): JobScheduleType diff --git a/components/ILIAS/Search/service.xml b/components/ILIAS/Search/service.xml index 33b83feb08f6..9a538a189144 100755 --- a/components/ILIAS/Search/service.xml +++ b/components/ILIAS/Search/service.xml @@ -14,8 +14,5 @@ - - - diff --git a/components/ILIAS/Skill/Skill.php b/components/ILIAS/Skill/Skill.php index 14809de6b706..b76d446c447a 100644 --- a/components/ILIAS/Skill/Skill.php +++ b/components/ILIAS/Skill/Skill.php @@ -38,5 +38,12 @@ public function init( ); $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\ComponentJS($this, "SkillEntries.js"); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilSkillNotifications( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/Skill/classes/class.ilSkillNotifications.php b/components/ILIAS/Skill/classes/class.ilSkillNotifications.php index 37faa43c7cf2..59b27a4f077b 100755 --- a/components/ILIAS/Skill/classes/class.ilSkillNotifications.php +++ b/components/ILIAS/Skill/classes/class.ilSkillNotifications.php @@ -21,38 +21,33 @@ use ILIAS\Skill\Service\SkillTreeService; use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Course/group skill notification * * @author Alex Killing */ -class ilSkillNotifications extends CronJob +class ilSkillNotifications extends AbstractCronJob { - protected ilLanguage $lng; protected ilObjUser $user; protected ilIniFile $client_ini; protected ilTree $tree; protected SkillTreeService $tree_service; - public function __construct() + public function init(): void { global $DIC; - $this->lng = $DIC->language(); - if (isset($DIC["ilUser"])) { - $this->user = $DIC->user(); - } - if (isset($DIC["ilClientIniFile"])) { - $this->client_ini = $DIC["ilClientIniFile"]; - } - if (isset($DIC["tree"])) { - $this->tree = $DIC->repositoryTree(); - } + $this->language->loadLanguageModule("skll"); + + $this->user = $DIC->user(); + $this->client_ini = $DIC["ilClientIniFile"]; + $this->tree = $DIC->repositoryTree(); $this->tree_service = $DIC->skills()->tree(); } + public function getId(): string { return "skll_notification"; @@ -60,16 +55,12 @@ public function getId(): string public function getTitle(): string { - $lng = $this->lng; - $lng->loadLanguageModule("skll"); - return $lng->txt("skll_skill_notification"); + return $this->language->txt("skll_skill_notification"); } public function getDescription(): string { - $lng = $this->lng; - $lng->loadLanguageModule("skll"); - return $lng->txt("skll_skill_notification_desc"); + return $this->language->txt("skll_skill_notification_desc"); } public function getDefaultScheduleType(): JobScheduleType diff --git a/components/ILIAS/Skill/service.xml b/components/ILIAS/Skill/service.xml index 8379fd2e1879..c9097fddbd02 100755 --- a/components/ILIAS/Skill/service.xml +++ b/components/ILIAS/Skill/service.xml @@ -19,7 +19,4 @@ - - - diff --git a/components/ILIAS/StudyProgramme/StudyProgramme.php b/components/ILIAS/StudyProgramme/StudyProgramme.php index 29e04a00d8ea..56879a5eea47 100644 --- a/components/ILIAS/StudyProgramme/StudyProgramme.php +++ b/components/ILIAS/StudyProgramme/StudyProgramme.php @@ -38,5 +38,36 @@ public function init( ); $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\ComponentCSS($this, "css/ilStudyProgramme.css"); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilPrgInvalidateExpiredProgressesCronJob( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilPrgRestartAssignmentsCronJob( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilPrgUserNotRestartedCronJob( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilPrgUserRiskyToFailCronJob( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilPrgUpdateProgressCronJob( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/StudyProgramme/classes/class.ilPrgInvalidateExpiredProgressesCronJob.php b/components/ILIAS/StudyProgramme/classes/class.ilPrgInvalidateExpiredProgressesCronJob.php index fa861c40df12..bd1770a7951c 100755 --- a/components/ILIAS/StudyProgramme/classes/class.ilPrgInvalidateExpiredProgressesCronJob.php +++ b/components/ILIAS/StudyProgramme/classes/class.ilPrgInvalidateExpiredProgressesCronJob.php @@ -20,7 +20,7 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /* * This invalidates a successful progress if validityOfQualification is reached. @@ -29,21 +29,21 @@ * It is perfectly feasible to raise some event for this, though, * but invalidation is reached by a date rather than a flag set by a cron job. */ -class ilPrgInvalidateExpiredProgressesCronJob extends CronJob +class ilPrgInvalidateExpiredProgressesCronJob extends AbstractCronJob { private const ID = 'prg_invalidate_expired_progresses'; - protected ilComponentLogger $log; - protected ilLanguage $lng; + protected ilLogger $log; protected ilPRGAssignmentDBRepository $assignment_repo; protected ilStudyProgrammeSettingsDBRepository $settings_repo; - public function __construct() + public function init(): void { global $DIC; - $this->log = $DIC['ilLog']; - $this->lng = $DIC['lng']; - $this->lng->loadLanguageModule('prg'); + + $this->language->loadLanguageModule('prg'); + + $this->log = $DIC->logger()->root(); $dic = ilStudyProgrammeDIC::dic(); $this->assignment_repo = $dic['repo.assignment']; @@ -52,12 +52,12 @@ public function __construct() public function getTitle(): string { - return $this->lng->txt('prg_invalidate_expired_progresses_title'); + return $this->language->txt('prg_invalidate_expired_progresses_title'); } public function getDescription(): string { - return $this->lng->txt('prg_invalidate_expired_progresses_desc'); + return $this->language->txt('prg_invalidate_expired_progresses_desc'); } public function getId(): string diff --git a/components/ILIAS/StudyProgramme/classes/class.ilPrgRestartAssignmentsCronJob.php b/components/ILIAS/StudyProgramme/classes/class.ilPrgRestartAssignmentsCronJob.php index f7221d21c311..125b4c259ba3 100755 --- a/components/ILIAS/StudyProgramme/classes/class.ilPrgRestartAssignmentsCronJob.php +++ b/components/ILIAS/StudyProgramme/classes/class.ilPrgRestartAssignmentsCronJob.php @@ -20,30 +20,30 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Re-assign users (according to restart-date). * This will result in a new/additional assignment */ -class ilPrgRestartAssignmentsCronJob extends CronJob +class ilPrgRestartAssignmentsCronJob extends AbstractCronJob { private const ID = 'prg_restart_assignments_temporal_progress'; private const ACTING_USR_ID = ilPRGAssignment::AUTO_ASSIGNED_BY_RESTART; - protected ilComponentLogger $log; - protected ilLanguage $lng; + protected ilLogger $log; protected ilPRGAssignmentDBRepository $assignment_repo; protected ilPrgCronJobAdapter $adapter; protected array $prgs = []; - public function __construct() + public function init(): void { global $DIC; - $this->log = $DIC['ilLog']; - $this->lng = $DIC['lng']; - $this->lng->loadLanguageModule('prg'); + + $this->language->loadLanguageModule('prg'); + + $this->log = $DIC->logger()->root(); $dic = ilStudyProgrammeDIC::dic(); $this->assignment_repo = $dic['repo.assignment']; @@ -52,12 +52,12 @@ public function __construct() public function getTitle(): string { - return $this->lng->txt('prg_restart_assignments_temporal_progress_title'); + return $this->language->txt('prg_restart_assignments_temporal_progress_title'); } public function getDescription(): string { - return $this->lng->txt('prg_restart_assignments_temporal_progress_desc'); + return $this->language->txt('prg_restart_assignments_temporal_progress_desc'); } public function getId(): string diff --git a/components/ILIAS/StudyProgramme/classes/class.ilPrgUpdateProgressCronJob.php b/components/ILIAS/StudyProgramme/classes/class.ilPrgUpdateProgressCronJob.php index 149cf61aa5c2..3c393de01099 100755 --- a/components/ILIAS/StudyProgramme/classes/class.ilPrgUpdateProgressCronJob.php +++ b/components/ILIAS/StudyProgramme/classes/class.ilPrgUpdateProgressCronJob.php @@ -20,27 +20,24 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * This will set progresses to FAILED, * if they are past the deadline (and not successful, yet) */ -class ilPrgUpdateProgressCronJob extends CronJob +class ilPrgUpdateProgressCronJob extends AbstractCronJob { private const ID = 'prg_update_progress'; protected Pimple\Container $dic; - protected ilLanguage $lng; protected ilStudyProgrammeSettingsDBRepository $settings_repo; protected ilPRGAssignmentDBRepository $assignment_repo; protected int $acting_user_id; - public function __construct() + public function init(): void { - global $DIC; - $this->lng = $DIC['lng']; - $this->lng->loadLanguageModule('prg'); + $this->language->loadLanguageModule('prg'); $dic = ilStudyProgrammeDIC::dic(); $this->settings_repo = $dic['model.Settings.ilStudyProgrammeSettingsRepository']; @@ -50,12 +47,12 @@ public function __construct() public function getTitle(): string { - return $this->lng->txt('prg_update_progress_title'); + return $this->language->txt('prg_update_progress_title'); } public function getDescription(): string { - return $this->lng->txt('prg_update_progress_description'); + return $this->language->txt('prg_update_progress_description'); } public function getId(): string diff --git a/components/ILIAS/StudyProgramme/classes/class.ilPrgUserNotRestartedCronJob.php b/components/ILIAS/StudyProgramme/classes/class.ilPrgUserNotRestartedCronJob.php index 1cada71de4d9..8ec49e3304fa 100755 --- a/components/ILIAS/StudyProgramme/classes/class.ilPrgUserNotRestartedCronJob.php +++ b/components/ILIAS/StudyProgramme/classes/class.ilPrgUserNotRestartedCronJob.php @@ -20,40 +20,41 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Inform a user, that her qualification is about to expire */ -class ilPrgUserNotRestartedCronJob extends CronJob +class ilPrgUserNotRestartedCronJob extends AbstractCronJob { private const ID = 'prg_user_not_restarted'; - protected ilComponentLogger $log; - protected ilLanguage $lng; + protected ilLogger $log; protected ilPRGAssignmentDBRepository $assignment_repo; protected ilPrgCronJobAdapter $adapter; - public function __construct() + public function init(): void { global $DIC; - $this->log = $DIC['ilLog']; - $this->lng = $DIC['lng']; - $this->lng->loadLanguageModule('prg'); + + $this->language->loadLanguageModule('prg'); + + $this->log = $DIC->logger()->root(); $dic = ilStudyProgrammeDIC::dic(); $this->assignment_repo = $dic['repo.assignment']; $this->adapter = $dic['cron.notRestarted']; } + public function getTitle(): string { - return $this->lng->txt('prg_user_not_restarted_title'); + return $this->language->txt('prg_user_not_restarted_title'); } public function getDescription(): string { - return $this->lng->txt('prg_user_not_restarted_desc'); + return $this->language->txt('prg_user_not_restarted_desc'); } public function getId(): string diff --git a/components/ILIAS/StudyProgramme/classes/class.ilPrgUserRiskyToFailCronJob.php b/components/ILIAS/StudyProgramme/classes/class.ilPrgUserRiskyToFailCronJob.php index 58bb9e9c3392..1553793f3b08 100755 --- a/components/ILIAS/StudyProgramme/classes/class.ilPrgUserRiskyToFailCronJob.php +++ b/components/ILIAS/StudyProgramme/classes/class.ilPrgUserRiskyToFailCronJob.php @@ -4,7 +4,7 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * This file is part of ILIAS, a powerful learning management system @@ -22,21 +22,21 @@ * *********************************************************************/ -class ilPrgUserRiskyToFailCronJob extends CronJob +class ilPrgUserRiskyToFailCronJob extends AbstractCronJob { private const ID = 'prg_user_risky_to_fail'; - protected ilComponentLogger $log; - protected ilLanguage $lng; + protected ilLogger $log; protected ilPRGAssignmentDBRepository $assignment_repo; protected ilPrgCronJobAdapter $adapter; - public function __construct() + public function init(): void { global $DIC; - $this->log = $DIC['ilLog']; - $this->lng = $DIC['lng']; - $this->lng->loadLanguageModule('prg'); + + $this->language->loadLanguageModule('prg'); + + $this->log = $DIC->logger()->root(); $dic = ilStudyProgrammeDIC::dic(); $this->assignment_repo = $dic['repo.assignment']; @@ -45,12 +45,12 @@ public function __construct() public function getTitle(): string { - return $this->lng->txt('prg_user_risky_to_fail_title'); + return $this->language->txt('prg_user_risky_to_fail_title'); } public function getDescription(): string { - return $this->lng->txt('prg_user_risky_to_fail_desc'); + return $this->language->txt('prg_user_risky_to_fail_desc'); } public function getId(): string diff --git a/components/ILIAS/StudyProgramme/module.xml b/components/ILIAS/StudyProgramme/module.xml index 273481e38b01..56cae23a5f83 100755 --- a/components/ILIAS/StudyProgramme/module.xml +++ b/components/ILIAS/StudyProgramme/module.xml @@ -43,13 +43,6 @@ - - - - - - - diff --git a/components/ILIAS/StudyProgramme/tests/cron/ilPrgRestartAssignmentsCronJobTest.php b/components/ILIAS/StudyProgramme/tests/cron/ilPrgRestartAssignmentsCronJobTest.php index 0636948e1dbd..1efe361ded55 100755 --- a/components/ILIAS/StudyProgramme/tests/cron/ilPrgRestartAssignmentsCronJobTest.php +++ b/components/ILIAS/StudyProgramme/tests/cron/ilPrgRestartAssignmentsCronJobTest.php @@ -29,8 +29,11 @@ class ilPrgRestartAssignmentsCronJobMock extends ilPrgRestartAssignmentsCronJob public function __construct( ilPRGAssignmentDBRepository $repo, ilPrgCronJobAdapter $adapter, - ilObjStudyProgramme $prg + ilObjStudyProgramme $prg, + \ILIAS\Language\Language $language, + \ILIAS\Logging\LoggerFactory $logger_factory, ) { + parent::__construct(\ILIAS\StudyProgramme::class, $language, $logger_factory); $this->assignment_repo = $repo; $this->adapter = $adapter; $this->prg = $prg; @@ -85,7 +88,13 @@ protected function setUp(): void ->onlyMethods(['getApplicableMembershipSourceForUser', 'getSettings', 'assignUser', 'getRefIdFor']) ->getMock(); - $this->job = new ilPrgRestartAssignmentsCronJobMock($this->assignment_repo, $this->adapter, $this->prg); + $this->job = new ilPrgRestartAssignmentsCronJobMock( + $this->assignment_repo, + $this->adapter, + $this->prg, + $this->createMock(\ILIAS\Language\Language::class), + $this->getMockBuilder(\ILIAS\Logging\LoggerFactory::class)->disableOriginalConstructor()->getMock() + ); } public function testRestartAssignmentsForNoRelevantProgrammes(): void @@ -196,7 +205,13 @@ public function testRestartAssignmentsEvents(): void ->method('assignUser') ->will($this->onConsecutiveCalls($ass1, $ass2)); - $job = new ilPrgRestartAssignmentsCronJobMock($this->assignment_repo, $this->real_adapter, $this->prg); + $job = new ilPrgRestartAssignmentsCronJobMock( + $this->assignment_repo, + $this->real_adapter, + $this->prg, + $this->createMock(\ILIAS\Language\Language::class), + $this->getMockBuilder(\ILIAS\Logging\LoggerFactory::class)->disableOriginalConstructor()->getMock() + ); $job->run(); $this->assertEquals(2, count($job->logs)); diff --git a/components/ILIAS/StudyProgramme/tests/cron/ilStudyProgrammeCronAboutToExpireTest.php b/components/ILIAS/StudyProgramme/tests/cron/ilStudyProgrammeCronAboutToExpireTest.php index 13f79c2869bc..b03908c7797e 100755 --- a/components/ILIAS/StudyProgramme/tests/cron/ilStudyProgrammeCronAboutToExpireTest.php +++ b/components/ILIAS/StudyProgramme/tests/cron/ilStudyProgrammeCronAboutToExpireTest.php @@ -27,8 +27,11 @@ class ilPrgUserNotRestartedCronJobMock extends ilPrgUserNotRestartedCronJob public function __construct( ilPRGAssignmentDBRepository $repo, - ilPrgCronJobAdapter $adapter + ilPrgCronJobAdapter $adapter, + \ILIAS\Language\Language $language, + \ILIAS\Logging\LoggerFactory $logger_factory, ) { + parent::__construct(\ILIAS\StudyProgramme::class, $language, $logger_factory); $this->assignment_repo = $repo; $this->adapter = $adapter; } @@ -71,7 +74,12 @@ protected function setUp(): void ->onlyMethods(['getAboutToExpire', 'storeExpiryInfoSentFor']) ->getMock(); - $this->job = new ilPrgUserNotRestartedCronJobMock($this->assignment_repo, $this->adapter); + $this->job = new ilPrgUserNotRestartedCronJobMock( + $this->assignment_repo, + $this->adapter, + $this->getMockBuilder(\ILIAS\Language\Language::class)->disableOriginalConstructor()->getMock(), + $this->createMock(\ILIAS\Logging\LoggerFactory::class) + ); } public function testAboutToExpireForNoRelevantProgrammes(): void @@ -141,7 +149,15 @@ public function testAboutToExpireEvents(): void ->method('getAboutToExpire') ->willReturn([$ass1, $ass2]); - $job = new ilPrgUserNotRestartedCronJobMock($this->assignment_repo, $this->real_adapter); + $language = $this->getMockBuilder(ilLanguage::class)->disableOriginalConstructor()->getMock(); + $logger_factory = $this->createMock(\ILIAS\Logging\LoggerFactory::class); + + $job = new ilPrgUserNotRestartedCronJobMock( + $this->assignment_repo, + $this->real_adapter, + $language, + $logger_factory + ); $job->run(); $this->assertEquals(2, count($job->logs)); diff --git a/components/ILIAS/StudyProgramme/tests/cron/ilStudyProgrammeCronRiskyToFailTest.php b/components/ILIAS/StudyProgramme/tests/cron/ilStudyProgrammeCronRiskyToFailTest.php index b2b880c34a92..9c495068dd4e 100755 --- a/components/ILIAS/StudyProgramme/tests/cron/ilStudyProgrammeCronRiskyToFailTest.php +++ b/components/ILIAS/StudyProgramme/tests/cron/ilStudyProgrammeCronRiskyToFailTest.php @@ -27,8 +27,11 @@ class ilPrgUserRiskyToFailCronJobMock extends ilPrgUserRiskyToFailCronJob public function __construct( ilPRGAssignmentDBRepository $repo, - ilPrgCronJobAdapter $adapter + ilPrgCronJobAdapter $adapter, + \ILIAS\Language\Language $language, + \ILIAS\Logging\LoggerFactory $logger_factory, ) { + parent::__construct(\ILIAS\StudyProgramme::class, $language, $logger_factory); $this->assignment_repo = $repo; $this->adapter = $adapter; } @@ -71,7 +74,12 @@ protected function setUp(): void ->onlyMethods(['getRiskyToFail', 'storeRiskyToFailSentFor']) ->getMock(); - $this->job = new ilPrgUserRiskyToFailCronJobMock($this->assignment_repo, $this->adapter); + $this->job = new ilPrgUserRiskyToFailCronJobMock( + $this->assignment_repo, + $this->adapter, + $this->createMock(\ILIAS\Language\Language::class), + $this->getMockBuilder(\ILIAS\Logging\LoggerFactory::class)->disableOriginalConstructor()->getMock() + ); } public function testRiskyToFailForNoRelevantProgrammes(): void @@ -141,7 +149,15 @@ public function testRiskyToFailEvents(): void ->method('getRiskyToFail') ->willReturn([$ass1, $ass2]); - $job = new ilPrgUserRiskyToFailCronJobMock($this->assignment_repo, $this->real_adapter); + $language = $this->getMockBuilder(ilLanguage::class)->disableOriginalConstructor()->getMock(); + $logger_factory = $this->createMock(\ILIAS\Logging\LoggerFactory::class); + + $job = new ilPrgUserRiskyToFailCronJobMock( + $this->assignment_repo, + $this->real_adapter, + $language, + $logger_factory + ); $job->run(); $this->assertEquals(2, count($job->logs)); diff --git a/components/ILIAS/Survey/Survey.php b/components/ILIAS/Survey/Survey.php index ad72be6ccc39..37e6e60f05ae 100644 --- a/components/ILIAS/Survey/Survey.php +++ b/components/ILIAS/Survey/Survey.php @@ -34,5 +34,12 @@ public function init( ): void { $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\ComponentCSS($this, "survey.css"); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilSurveyCronNotification( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/Survey/classes/class.ilSurveyCronNotification.php b/components/ILIAS/Survey/classes/class.ilSurveyCronNotification.php index 6674f69beadb..51c843fa30e9 100755 --- a/components/ILIAS/Survey/classes/class.ilSurveyCronNotification.php +++ b/components/ILIAS/Survey/classes/class.ilSurveyCronNotification.php @@ -18,7 +18,7 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Cron for survey notifications @@ -26,21 +26,19 @@ * * @author Jörg Lützenkirchen */ -class ilSurveyCronNotification extends CronJob +class ilSurveyCronNotification extends AbstractCronJob { protected const MAX_MESSAGE_LENGTH = 397; - protected ilLanguage $lng; protected ilTree $tree; - public function __construct() + public function init(): void { global $DIC; - $this->lng = $DIC->language(); - if (isset($DIC["tree"])) { - $this->tree = $DIC->repositoryTree(); - } + $this->language->loadLanguageModule("survey"); + + $this->tree = $DIC->repositoryTree(); } public function getId(): string @@ -50,18 +48,12 @@ public function getId(): string public function getTitle(): string { - $lng = $this->lng; - - $lng->loadLanguageModule("survey"); - return $lng->txt("survey_reminder_cron"); + return $this->language->txt("survey_reminder_cron"); } public function getDescription(): string { - $lng = $this->lng; - - $lng->loadLanguageModule("survey"); - return $lng->txt("survey_reminder_cron_info"); + return $this->language->txt("survey_reminder_cron_info"); } public function getDefaultScheduleType(): JobScheduleType diff --git a/components/ILIAS/Survey/module.xml b/components/ILIAS/Survey/module.xml index ef12edb39b7d..302a1754b883 100755 --- a/components/ILIAS/Survey/module.xml +++ b/components/ILIAS/Survey/module.xml @@ -21,9 +21,6 @@ adm - - - diff --git a/components/ILIAS/SystemCheck/SystemCheck.php b/components/ILIAS/SystemCheck/SystemCheck.php index fd0ea0f20f4c..99d4c2513017 100644 --- a/components/ILIAS/SystemCheck/SystemCheck.php +++ b/components/ILIAS/SystemCheck/SystemCheck.php @@ -32,6 +32,11 @@ public function init( array | \ArrayAccess &$pull, array | \ArrayAccess &$internal, ): void { - // ... + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilSCCronTrash( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/SystemCheck/classes/class.ilSCCronTrash.php b/components/ILIAS/SystemCheck/classes/class.ilSCCronTrash.php index 0922bb1ad8aa..bbda6f6c7ec3 100755 --- a/components/ILIAS/SystemCheck/classes/class.ilSCCronTrash.php +++ b/components/ILIAS/SystemCheck/classes/class.ilSCCronTrash.php @@ -20,26 +20,25 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Purge trash by cron * @author Stefan Meyer */ -class ilSCCronTrash extends CronJob +class ilSCCronTrash extends AbstractCronJob { - protected ilLanguage $lng; protected ilTree $tree; protected ilObjectDefinition $objDefinition; - public function __construct() + public function init(): void { global $DIC; - $this->lng = $DIC->language(); + $this->language->loadLanguageModule('sysc'); + $this->tree = $DIC->repositoryTree(); $this->objDefinition = $DIC['objDefinition']; - $this->lng->loadLanguageModule('sysc'); } public function getId(): string @@ -49,12 +48,12 @@ public function getId(): string public function getTitle(): string { - return $this->lng->txt('sysc_cron_empty_trash'); + return $this->language->txt('sysc_cron_empty_trash'); } public function getDescription(): string { - return $this->lng->txt('sysc_cron_empty_trash_desc'); + return $this->language->txt('sysc_cron_empty_trash_desc'); } public function getDefaultScheduleType(): JobScheduleType @@ -95,14 +94,14 @@ public function hasCustomSettings(): bool public function addCustomSettingsToForm(ilPropertyFormGUI $a_form): void { - $this->lng->loadLanguageModule('sysc'); + $this->language->loadLanguageModule('sysc'); $settings = new ilSetting('sysc'); // limit number - $num = new ilNumberInputGUI($this->lng->txt('sysc_trash_limit_num'), 'number'); + $num = new ilNumberInputGUI($this->language->txt('sysc_trash_limit_num'), 'number'); $num->allowDecimals(false); - $num->setInfo($this->lng->txt('purge_count_limit_desc')); + $num->setInfo($this->language->txt('purge_count_limit_desc')); $num->setSize(10); $num->setMinValue(1); $num->setValue($settings->get('num', '')); @@ -110,7 +109,7 @@ public function addCustomSettingsToForm(ilPropertyFormGUI $a_form): void $age = new ilNumberInputGUI($this->lng->txt('sysc_trash_limit_age'), 'age'); $age->allowDecimals(false); - $age->setInfo($this->lng->txt('purge_age_limit_desc')); + $age->setInfo($this->language->txt('purge_age_limit_desc')); $age->setSize(4); $age->setMinValue(1); $age->setMaxLength(4); @@ -131,7 +130,7 @@ public function addCustomSettingsToForm(ilPropertyFormGUI $a_form): void if (!$this->objDefinition->isRBACObject($obj_type) || !$this->objDefinition->isAllowedInRepository($obj_type)) { continue; } - $options[$obj_type] = $this->lng->txt('obj_' . $obj_type); + $options[$obj_type] = $this->language->txt('obj_' . $obj_type); } asort($options); $types->setOptions($options); diff --git a/components/ILIAS/SystemCheck/service.xml b/components/ILIAS/SystemCheck/service.xml index 4bac44be71ff..7ea5cd687aac 100755 --- a/components/ILIAS/SystemCheck/service.xml +++ b/components/ILIAS/SystemCheck/service.xml @@ -7,8 +7,5 @@ adm - - - diff --git a/components/ILIAS/Test/Test.php b/components/ILIAS/Test/Test.php index 866a38de18b7..3a54f7e64f93 100644 --- a/components/ILIAS/Test/Test.php +++ b/components/ILIAS/Test/Test.php @@ -48,5 +48,12 @@ public function init( new Component\Resource\ComponentCSS($this, "test_print.css"); $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\ComponentCSS($this, "test_print_hide_content.css"); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilCronFinishUnfinishedTestPasses( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/Test/classes/class.ilCronFinishUnfinishedTestPasses.php b/components/ILIAS/Test/classes/class.ilCronFinishUnfinishedTestPasses.php index bf32c7cb0077..f0b63c2b4b76 100755 --- a/components/ILIAS/Test/classes/class.ilCronFinishUnfinishedTestPasses.php +++ b/components/ILIAS/Test/classes/class.ilCronFinishUnfinishedTestPasses.php @@ -24,17 +24,16 @@ use ILIAS\Test\TestDIC; use ILIAS\Test\Logging\TestLogger; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Class ilCronFinishUnfinishedTestPasses * @author Guido Vollbach */ -class ilCronFinishUnfinishedTestPasses extends CronJob +class ilCronFinishUnfinishedTestPasses extends AbstractCronJob { protected readonly TestLogger $logger; - protected readonly ilLanguage $lng; protected readonly ilDBInterface $db; protected readonly ilObjUser $user; protected readonly ilObjectDataCache $obj_data_cache; @@ -45,15 +44,14 @@ class ilCronFinishUnfinishedTestPasses extends CronJob protected ilTestProcessLockerFactory $processLockerFactory; protected TestResultRepository $test_result_repository; - public function __construct() + public function init(): void { - /** @var ILIAS\DI\Container $DIC */ global $DIC; + $this->language->loadLanguageModule('assessment'); + $this->logger = TestDIC::dic()['logging.logger']; - $this->lng = $DIC['lng']; $this->user = $DIC['ilUser']; - $this->lng->loadLanguageModule('assessment'); $this->db = $DIC->database(); $this->obj_data_cache = $DIC['ilObjDataCache']; $this->now = time(); @@ -77,12 +75,12 @@ public function getId(): string public function getTitle(): string { - return $this->lng->txt('finish_unfinished_passes'); + return $this->language->txt('finish_unfinished_passes'); } public function getDescription(): string { - return $this->lng->txt('finish_unfinished_passes_desc'); + return $this->language->txt('finish_unfinished_passes_desc'); } public function getDefaultScheduleType(): JobScheduleType diff --git a/components/ILIAS/Test/module.xml b/components/ILIAS/Test/module.xml index b08137b7ad80..cb4e48da3cba 100755 --- a/components/ILIAS/Test/module.xml +++ b/components/ILIAS/Test/module.xml @@ -30,9 +30,6 @@ wfld - - - diff --git a/components/ILIAS/Test/tests/ilCronFinishUnfinishedTestPassesTest.php b/components/ILIAS/Test/tests/ilCronFinishUnfinishedTestPassesTest.php index 83a1066ec99c..e6ea07681ef4 100755 --- a/components/ILIAS/Test/tests/ilCronFinishUnfinishedTestPassesTest.php +++ b/components/ILIAS/Test/tests/ilCronFinishUnfinishedTestPassesTest.php @@ -41,7 +41,11 @@ protected function setUp(): void define("ILIAS_LOG_ENABLED", false); } - $this->test_obj = new ilCronFinishUnfinishedTestPasses(); + $this->test_obj = new ilCronFinishUnfinishedTestPasses( + \ILIAS\Test::class, + $this->getMockBuilder(ilLanguage::class)->disableOriginalConstructor()->getMock(), + $this->createMock(\ILIAS\Logging\LoggerFactory::class) + ); } public function test_instantiateObject_shouldReturnInstance(): void @@ -65,7 +69,11 @@ public function testGetTitle(): void ; $this->setGlobalVariable('lng', $lng_mock); - $test_obj = new ilCronFinishUnfinishedTestPasses(); + $test_obj = new ilCronFinishUnfinishedTestPasses( + \ILIAS\Test::class, + $lng_mock, + $this->createMock(\ILIAS\Logging\LoggerFactory::class) + ); $this->assertEquals('testString', $test_obj->getTitle()); } @@ -81,7 +89,11 @@ public function testGetDescription(): void ; $this->setGlobalVariable('lng', $lng_mock); - $test_obj = new ilCronFinishUnfinishedTestPasses(); + $test_obj = new ilCronFinishUnfinishedTestPasses( + \ILIAS\Test::class, + $lng_mock, + $this->createMock(\ILIAS\Logging\LoggerFactory::class) + ); $this->assertEquals('testString', $test_obj->getDescription()); } diff --git a/components/ILIAS/Tracking/Tracking.php b/components/ILIAS/Tracking/Tracking.php index 16dcad512166..1a538a75b0c8 100644 --- a/components/ILIAS/Tracking/Tracking.php +++ b/components/ILIAS/Tracking/Tracking.php @@ -37,5 +37,12 @@ public function init( array | \ArrayAccess &$internal, ): void { $contribute[SetupAgentInterface::class] = fn() => new SetupAgent($pull[Refinery::class]); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilLPCronObjectStatistics( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/Tracking/classes/class.ilLPCronObjectStatistics.php b/components/ILIAS/Tracking/classes/class.ilLPCronObjectStatistics.php index 1d0bd29135a4..10fe23d4dbbd 100755 --- a/components/ILIAS/Tracking/classes/class.ilLPCronObjectStatistics.php +++ b/components/ILIAS/Tracking/classes/class.ilLPCronObjectStatistics.php @@ -21,35 +21,35 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobManager; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * Cron for lp object statistics * @author Jörg Lützenkirchen * @ingroup ServicesTracking */ -class ilLPCronObjectStatistics extends CronJob +class ilLPCronObjectStatistics extends AbstractCronJob { protected int $date = 0; - protected ilLanguage $lng; protected ilDBInterface $db; protected ilTree $tree; protected ilLogger $logger; protected JobManager $cron_manager; - public function __construct() + public function init(): void { global $DIC; + $this->language->loadLanguageModule("trac"); + $this->logger = $DIC->logger()->trac(); - $this->lng = $DIC->language(); - $this->lng->loadLanguageModule("trac"); $this->db = $DIC->database(); $this->tree = $DIC->repositoryTree(); $this->cron_manager = $DIC->cron()->manager(); } + public function getId(): string { return "lp_object_statistics"; @@ -57,12 +57,12 @@ public function getId(): string public function getTitle(): string { - return $this->lng->txt("trac_object_statistics"); + return $this->language->txt("trac_object_statistics"); } public function getDescription(): string { - return $this->lng->txt("trac_object_statistics_info"); + return $this->language->txt("trac_object_statistics_info"); } public function getDefaultScheduleType(): JobScheduleType diff --git a/components/ILIAS/Tracking/service.xml b/components/ILIAS/Tracking/service.xml index af13202ac075..51156bcdf9bb 100755 --- a/components/ILIAS/Tracking/service.xml +++ b/components/ILIAS/Tracking/service.xml @@ -17,8 +17,5 @@ - - - diff --git a/components/ILIAS/User/User.php b/components/ILIAS/User/User.php index 8d7940d25dac..164066fbb9d1 100644 --- a/components/ILIAS/User/User.php +++ b/components/ILIAS/User/User.php @@ -56,5 +56,30 @@ public function init( new CustomTypeTextArea(); $contribute[CustomProfileFieldType::class] = fn() => new CustomTypeSelect(); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilCronDeleteInactiveUserAccounts( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilCronDeleteInactivatedUserAccounts( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilUserCronCheckAccounts( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilCronDeleteNeverLoggedInUserAccounts( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/User/classes/Cron/class.ilCronDeleteInactivatedUserAccounts.php b/components/ILIAS/User/classes/Cron/class.ilCronDeleteInactivatedUserAccounts.php index f5a214f3d5b5..a1b8add5764f 100755 --- a/components/ILIAS/User/classes/Cron/class.ilCronDeleteInactivatedUserAccounts.php +++ b/components/ILIAS/User/classes/Cron/class.ilCronDeleteInactivatedUserAccounts.php @@ -18,74 +18,48 @@ declare(strict_types=1); -use ILIAS\Language\Language; use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * This cron deletes user accounts by INACTIVATION period - * @author Bjoern Heyser - * @package components/ILIAS/User */ -class ilCronDeleteInactivatedUserAccounts extends CronJob +class ilCronDeleteInactivatedUserAccounts extends AbstractCronJob { - private const DEFAULT_INACTIVITY_PERIOD = 365; + private const int DEFAULT_INACTIVITY_PERIOD = 365; private int $period; /** @var int[] */ private array $include_roles; private ilSetting $settings; - private Language $lng; private ilRbacReview $rbac_review; private ilObjectDataCache $objectDataCache; private \ILIAS\HTTP\GlobalHttpState $http; private \ILIAS\Refinery\Factory $refinery; - public function __construct() + public function init(): void { - /** @var ILIAS\DI\Container $DIC */ global $DIC; - if (isset($DIC['http'])) { - $this->http = $DIC['http']; - } - - if (isset($DIC['lng'])) { - $this->lng = $DIC['lng']; - } - - if (isset($DIC['refinery'])) { - $this->refinery = $DIC['refinery']; - } - - if (isset($DIC['ilObjDataCache'])) { - $this->objectDataCache = $DIC['ilObjDataCache']; - } - - if (isset($DIC['rbacreview'])) { - $this->rbac_review = $DIC['rbacreview']; - } + $this->language->loadLanguageModule('usr'); - if (isset($DIC['ilSetting'])) { - $this->settings = $DIC['ilSetting']; - - $include_roles = $this->settings->get( - 'cron_inactivated_user_delete_include_roles', - null - ); - if ($include_roles === null) { - $this->include_roles = []; - } else { - $this->include_roles = array_filter(array_map('intval', explode(',', $include_roles))); - } + $this->http = $DIC->http(); + $this->refinery = $DIC->refinery(); + $this->objectDataCache = $DIC['ilObjDataCache']; + $this->rbac_review = $DIC->rbac()->review(); + $this->settings = $DIC->settings(); - $this->period = (int) $this->settings->get( - 'cron_inactivated_user_delete_period', - (string) self::DEFAULT_INACTIVITY_PERIOD - ); - } + $include_roles = $this->settings->get('cron_inactivated_user_delete_include_roles', null); + $this->include_roles = $include_roles === null + ? [] + : array_filter(array_map('intval', explode(',', $include_roles))); + $this->period = (int) $this->settings->get( + 'cron_inactivated_user_delete_period', + (string) self::DEFAULT_INACTIVITY_PERIOD + ); } + public function getId(): string { return "user_inactivated"; @@ -93,13 +67,13 @@ public function getId(): string public function getTitle(): string { - return $this->lng->txt("delete_inactivated_user_accounts"); + return $this->language->txt("delete_inactivated_user_accounts"); } public function getDescription(): string { return sprintf( - $this->lng->txt("delete_inactivated_user_accounts_desc"), + $this->language->txt("delete_inactivated_user_accounts_desc"), $this->period ); } @@ -164,10 +138,10 @@ public function run(): JobResult public function addCustomSettingsToForm(ilPropertyFormGUI $a_form): void { $sub_mlist = new ilMultiSelectInputGUI( - $this->lng->txt('delete_inactivated_user_accounts_include_roles'), + $this->language->txt('delete_inactivated_user_accounts_include_roles'), 'cron_inactivated_user_delete_include_roles' ); - $sub_mlist->setInfo($this->lng->txt('delete_inactivated_user_accounts_include_roles_desc')); + $sub_mlist->setInfo($this->language->txt('delete_inactivated_user_accounts_include_roles_desc')); $roles = []; foreach ($this->rbac_review->getGlobalRoles() as $role_id) { if ($role_id !== ANONYMOUS_ROLE_ID) { @@ -186,11 +160,11 @@ public function addCustomSettingsToForm(ilPropertyFormGUI $a_form): void $a_form->addItem($sub_mlist); $sub_text = new ilNumberInputGUI( - $this->lng->txt('delete_inactivated_user_accounts_period'), + $this->language->txt('delete_inactivated_user_accounts_period'), 'cron_inactivated_user_delete_period' ); $sub_text->allowDecimals(false); - $sub_text->setInfo($this->lng->txt('delete_inactivated_user_accounts_period_desc')); + $sub_text->setInfo($this->language->txt('delete_inactivated_user_accounts_period_desc')); $sub_text->setValue( $this->settings->get( 'cron_inactivated_user_delete_period', diff --git a/components/ILIAS/User/classes/Cron/class.ilCronDeleteInactiveUserAccounts.php b/components/ILIAS/User/classes/Cron/class.ilCronDeleteInactiveUserAccounts.php index c8404f18719f..ba5e3fc16270 100755 --- a/components/ILIAS/User/classes/Cron/class.ilCronDeleteInactiveUserAccounts.php +++ b/components/ILIAS/User/classes/Cron/class.ilCronDeleteInactiveUserAccounts.php @@ -18,26 +18,22 @@ declare(strict_types=1); -use ILIAS\Language\Language; use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobRepository; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * This cron deletes user accounts by INACTIVITY period - * @author Bjoern Heyser - * @author Guido Vollbach - * @package ilias */ -class ilCronDeleteInactiveUserAccounts extends CronJob +class ilCronDeleteInactiveUserAccounts extends AbstractCronJob { - private const DEFAULT_INACTIVITY_PERIOD = 365; - private const DEFAULT_REMINDER_PERIOD = 0; + private const int DEFAULT_INACTIVITY_PERIOD = 365; + private const int DEFAULT_REMINDER_PERIOD = 0; - private const ACTION_USER_NONE = 0; - private const ACTION_USER_REMINDER_MAIL_SENT = 1; - private const ACTION_USER_DELETED = 2; + private const int ACTION_USER_NONE = 0; + private const int ACTION_USER_REMINDER_MAIL_SENT = 1; + private const int ACTION_USER_DELETED = 2; private int $delete_period; private int $reminder_period; @@ -45,59 +41,31 @@ class ilCronDeleteInactiveUserAccounts extends CronJob private array $include_roles; private ilCronDeleteInactiveUserReminderMail $cron_delete_reminder_mail; private ilSetting $settings; - private Language $lng; private ilComponentLogger $log; private ilRbacReview $rbac_review; private ilObjectDataCache $objectDataCache; private \ILIAS\HTTP\GlobalHttpState $http; private \ILIAS\Refinery\Factory $refinery; private JobRepository $cronRepository; - private \ilGlobalTemplateInterface $main_tpl; + private ilGlobalTemplateInterface $main_tpl; - public function __construct() + public function init(): void { - /** @var ILIAS\DI\Container $DIC */ global $DIC; - if (isset($DIC['ilDB'])) { - $this->cron_delete_reminder_mail = new ilCronDeleteInactiveUserReminderMail($DIC['ilDB']); - } - - if (isset($DIC['tpl'])) { - $this->main_tpl = $DIC['tpl']; - } - if (isset($DIC['http'])) { - $this->http = $DIC['http']; - } - - if (isset($DIC['lng'])) { - $this->lng = $DIC['lng']; - } - - if (isset($DIC['ilLog'])) { - $this->log = $DIC['ilLog']; - } + $this->language->loadLanguageModule('usr'); - if (isset($DIC['refinery'])) { - $this->refinery = $DIC['refinery']; - } - - if (isset($DIC['ilObjDataCache'])) { - $this->objectDataCache = $DIC['ilObjDataCache']; - } - - if (isset($DIC['rbacreview'])) { - $this->rbac_review = $DIC['rbacreview']; - } - - if (isset($DIC['cron.repository'])) { - $this->cronRepository = $DIC['cron.repository']; - } + $this->main_tpl = $DIC->ui()->mainTemplate(); + $this->http = $DIC->http(); + $this->log = $this->logger_factory->getRootLogger(); + $this->refinery = $DIC->refinery(); + $this->objectDataCache = $DIC['ilObjDataCache']; + $this->rbac_review = $DIC->rbac()->review(); + $this->cronRepository = $DIC['cron.repository']; + $this->settings = $DIC->settings(); + $this->cron_delete_reminder_mail = new ilCronDeleteInactiveUserReminderMail($DIC->database()); - if (isset($DIC['ilSetting'])) { - $this->settings = $DIC['ilSetting']; - $this->loadSettings(); - } + $this->loadSettings(); } private function loadSettings(): void @@ -173,12 +141,12 @@ public function getId(): string public function getTitle(): string { - return $this->lng->txt("delete_inactive_user_accounts"); + return $this->language->txt("delete_inactive_user_accounts"); } public function getDescription(): string { - return $this->lng->txt("delete_inactive_user_accounts_desc"); + return $this->language->txt("delete_inactive_user_accounts_desc"); } public function getDefaultScheduleType(): JobScheduleType @@ -300,17 +268,17 @@ protected function calculateDeletionData(int $date_for_deletion): int public function addCustomSettingsToForm(ilPropertyFormGUI $a_form): void { - $this->lng->loadLanguageModule("user"); + $this->language->loadLanguageModule("user"); $schedule = $a_form->getItemByPostVar('type'); - $schedule->setTitle($this->lng->txt('delete_inactive_user_accounts_frequency')); - $schedule->setInfo($this->lng->txt('delete_inactive_user_accounts_frequency_desc')); + $schedule->setTitle($this->language->txt('delete_inactive_user_accounts_frequency')); + $schedule->setInfo($this->language->txt('delete_inactive_user_accounts_frequency_desc')); $sub_mlist = new ilMultiSelectInputGUI( - $this->lng->txt('delete_inactive_user_accounts_include_roles'), + $this->language->txt('delete_inactive_user_accounts_include_roles'), 'cron_inactive_user_delete_include_roles' ); - $sub_mlist->setInfo($this->lng->txt('delete_inactive_user_accounts_include_roles_desc')); + $sub_mlist->setInfo($this->language->txt('delete_inactive_user_accounts_include_roles_desc')); $roles = []; foreach ($this->rbac_review->getGlobalRoles() as $role_id) { if ($role_id !== ANONYMOUS_ROLE_ID) { @@ -331,11 +299,11 @@ public function addCustomSettingsToForm(ilPropertyFormGUI $a_form): void $default_setting = (string) self::DEFAULT_INACTIVITY_PERIOD; $sub_text = new ilNumberInputGUI( - $this->lng->txt('delete_inactive_user_accounts_period'), + $this->language->txt('delete_inactive_user_accounts_period'), 'cron_inactive_user_delete_period' ); $sub_text->allowDecimals(false); - $sub_text->setInfo($this->lng->txt('delete_inactive_user_accounts_period_desc')); + $sub_text->setInfo($this->language->txt('delete_inactive_user_accounts_period_desc')); $sub_text->setValue($this->settings->get("cron_inactive_user_delete_period", $default_setting)); $sub_text->setSize(4); $sub_text->setMaxLength(4); @@ -343,13 +311,13 @@ public function addCustomSettingsToForm(ilPropertyFormGUI $a_form): void $a_form->addItem($sub_text); $sub_period = new ilNumberInputGUI( - $this->lng->txt('send_mail_to_inactive_users'), + $this->language->txt('send_mail_to_inactive_users'), 'cron_inactive_user_reminder_period' ); $sub_period->allowDecimals(false); - $sub_period->setInfo($this->lng->txt("send_mail_to_inactive_users_desc")); + $sub_period->setInfo($this->language->txt("send_mail_to_inactive_users_desc")); $sub_period->setValue($this->settings->get("cron_inactive_user_reminder_period", $default_setting)); - $sub_period->setSuffix($this->lng->txt("send_mail_to_inactive_users_suffix")); + $sub_period->setSuffix($this->language->txt("send_mail_to_inactive_users_suffix")); $sub_period->setSize(4); $sub_period->setMaxLength(4); $sub_period->setRequired(false); @@ -359,7 +327,7 @@ public function addCustomSettingsToForm(ilPropertyFormGUI $a_form): void public function saveCustomSettings(ilPropertyFormGUI $a_form): bool { - $this->lng->loadLanguageModule("user"); + $this->language->loadLanguageModule("user"); $valid = true; @@ -422,21 +390,21 @@ public function saveCustomSettings(ilPropertyFormGUI $a_form): bool if ($this->isDecimal($delete_period)) { $valid = false; $a_form->getItemByPostVar('cron_inactive_user_delete_period')->setAlert( - $this->lng->txt('send_mail_to_inactive_users_numbers_only') + $this->language->txt('send_mail_to_inactive_users_numbers_only') ); } if ($this->isDecimal($reminder_period)) { $valid = false; $a_form->getItemByPostVar('cron_inactive_user_reminder_period')->setAlert( - $this->lng->txt('send_mail_to_inactive_users_numbers_only') + $this->language->txt('send_mail_to_inactive_users_numbers_only') ); } if ($reminder_period >= $delete_period) { $valid = false; $a_form->getItemByPostVar('cron_inactive_user_reminder_period')->setAlert( - $this->lng->txt('send_mail_to_inactive_users_must_be_smaller_than') + $this->language->txt('send_mail_to_inactive_users_must_be_smaller_than') ); } @@ -469,7 +437,7 @@ public function saveCustomSettings(ilPropertyFormGUI $a_form): bool if (!$logic) { $valid = false; $a_form->getItemByPostVar('cron_inactive_user_reminder_period')->setAlert( - $this->lng->txt('send_mail_reminder_window_too_small') + $this->language->txt('send_mail_reminder_window_too_small') ); } } @@ -494,7 +462,7 @@ public function saveCustomSettings(ilPropertyFormGUI $a_form): bool $this->settings->set('cron_inactive_user_reminder_period', (string) $reminder_period); if (!$valid) { - $this->main_tpl->setOnScreenMessage('failure', $this->lng->txt("form_input_not_valid")); + $this->main_tpl->setOnScreenMessage('failure', $this->language->txt("form_input_not_valid")); return false; } diff --git a/components/ILIAS/User/classes/Cron/class.ilCronDeleteNeverLoggedInUserAccounts.php b/components/ILIAS/User/classes/Cron/class.ilCronDeleteNeverLoggedInUserAccounts.php index a88c8eda6e96..d0cd6ec9c517 100755 --- a/components/ILIAS/User/classes/Cron/class.ilCronDeleteNeverLoggedInUserAccounts.php +++ b/components/ILIAS/User/classes/Cron/class.ilCronDeleteNeverLoggedInUserAccounts.php @@ -18,66 +18,45 @@ declare(strict_types=1); -use ILIAS\Language\Language; use ILIAS\Refinery\ConstraintViolationException; use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; +use ILIAS\Cron\AbstractCronJob; -class ilCronDeleteNeverLoggedInUserAccounts extends \ILIAS\Cron\CronJob +class ilCronDeleteNeverLoggedInUserAccounts extends AbstractCronJob { - private const DEFAULT_CREATION_THRESHOLD = 365; + private const int DEFAULT_CREATION_THRESHOLD = 365; private string $roleIdWhiteliste = ''; private int $thresholdInDays = self::DEFAULT_CREATION_THRESHOLD; - private Language $lng; private ilSetting $settings; private ilRbacReview $rbacreview; private ilObjectDataCache $objectDataCache; private \ILIAS\HTTP\GlobalHttpState $http; private \ILIAS\Refinery\Factory $refinery; - private \ilGlobalTemplateInterface $main_tpl; + private ilGlobalTemplateInterface $main_tpl; - public function __construct() + public function init(): void { global $DIC; - $this->main_tpl = $DIC->ui()->mainTemplate(); - - if ($DIC) { - if (isset($DIC['ilSetting'])) { - $this->settings = $DIC->settings(); - - $this->roleIdWhiteliste = (string) $this->settings->get( - 'cron_users_without_login_delete_incl_roles', - '' - ); - $this->thresholdInDays = (int) $this->settings->get( - 'cron_users_without_login_delete_threshold', - (string) self::DEFAULT_CREATION_THRESHOLD - ); - } - - if (isset($DIC['lng'])) { - $this->lng = $DIC->language(); - $this->lng->loadLanguageModule('usr'); - } + $this->language->loadLanguageModule('usr'); - if (isset($DIC['rbacreview'])) { - $this->rbacreview = $DIC->rbac()->review(); - } - - if (isset($DIC['ilObjDataCache'])) { - $this->objectDataCache = $DIC['ilObjDataCache']; - } - - if (isset($DIC['http'])) { - $this->http = $DIC->http(); - } - - if (isset($DIC['refinery'])) { - $this->refinery = $DIC->refinery(); - } - } + $this->main_tpl = $DIC->ui()->mainTemplate(); + $this->settings = $DIC->settings(); + $this->rbacreview = $DIC->rbac()->review(); + $this->objectDataCache = $DIC['ilObjDataCache']; + $this->http = $DIC->http(); + $this->refinery = $DIC->refinery(); + + $this->roleIdWhiteliste = (string) $this->settings->get( + 'cron_users_without_login_delete_incl_roles', + '' + ); + $this->thresholdInDays = (int) $this->settings->get( + 'cron_users_without_login_delete_threshold', + (string) self::DEFAULT_CREATION_THRESHOLD + ); } public function getId(): string @@ -87,16 +66,12 @@ public function getId(): string public function getTitle(): string { - global $DIC; - - return $DIC->language()->txt('user_never_logged_in'); + return $this->language->txt('user_never_logged_in'); } public function getDescription(): string { - global $DIC; - - return $DIC->language()->txt('user_never_logged_in_info'); + return $this->language->txt('user_never_logged_in_info'); } public function getDefaultScheduleType(): JobScheduleType diff --git a/components/ILIAS/User/classes/Cron/class.ilUserCronCheckAccounts.php b/components/ILIAS/User/classes/Cron/class.ilUserCronCheckAccounts.php index 975a3ab240fc..f9e667a38396 100755 --- a/components/ILIAS/User/classes/Cron/class.ilUserCronCheckAccounts.php +++ b/components/ILIAS/User/classes/Cron/class.ilUserCronCheckAccounts.php @@ -20,36 +20,26 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * This cron send notifications about expiring user accounts - * @author Stefan Meyer */ -class ilUserCronCheckAccounts extends CronJob +class ilUserCronCheckAccounts extends AbstractCronJob { protected int $counter = 0; private ilDBInterface $db; - private ilLanguage $lng; private ilComponentLogger $log; - public function __construct() + public function init(): void { - /** @var ILIAS\DI\Container $DIC */ global $DIC; - if (isset($DIC['ilDB'])) { - $this->db = $DIC['ilDB']; - } - - if (isset($DIC['lng'])) { - $this->lng = $DIC['lng']; - } + $this->language->loadLanguageModule('usr'); - if (isset($DIC['ilDB'])) { - $this->log = $DIC['ilLog']; - } + $this->log = $this->logger_factory->getRootLogger(); + $this->db = $DIC->database(); } public function getId(): string @@ -59,12 +49,12 @@ public function getId(): string public function getTitle(): string { - return $this->lng->txt('check_user_accounts'); + return $this->language->txt('check_user_accounts'); } public function getDescription(): string { - return $this->lng->txt('check_user_accounts_desc'); + return $this->language->txt('check_user_accounts_desc'); } public function getDefaultScheduleType(): JobScheduleType diff --git a/components/ILIAS/User/service.xml b/components/ILIAS/User/service.xml index cc986ad2e74c..2cb4f4c931e2 100755 --- a/components/ILIAS/User/service.xml +++ b/components/ILIAS/User/service.xml @@ -19,12 +19,6 @@ - - - - - - diff --git a/components/ILIAS/WOPI/WOPI.php b/components/ILIAS/WOPI/WOPI.php index 25474b5063e0..06d17bb8de7c 100644 --- a/components/ILIAS/WOPI/WOPI.php +++ b/components/ILIAS/WOPI/WOPI.php @@ -49,5 +49,12 @@ public function init( $contribute[PublicAsset::class] = fn(): ComponentJS => new ComponentJS($this, "js/dist/wopi.min.js"); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilWOPICrawler( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/WOPI/classes/Cron/class.ilWOPICrawler.php b/components/ILIAS/WOPI/classes/Cron/class.ilWOPICrawler.php index c4e5a45131fd..8bac2b582733 100755 --- a/components/ILIAS/WOPI/classes/Cron/class.ilWOPICrawler.php +++ b/components/ILIAS/WOPI/classes/Cron/class.ilWOPICrawler.php @@ -26,23 +26,22 @@ use ILIAS\WOPI\Discovery\ActionRepository; use ILIAS\Data\URI; use ILIAS\Cron\Job\JobResult; -use ILIAS\Cron\CronJob; +use ILIAS\Cron\AbstractCronJob; /** * @author Fabian Schmid */ -class ilWOPICrawler extends CronJob +class ilWOPICrawler extends AbstractCronJob { - private ilLanguage $language; private ilSetting $settings; private Crawler $crawler; private AppRepository $app_repository; private ActionRepository $action_repository; - public function __construct() + public function init(): void { global $DIC; - $this->language = $DIC->language(); + $this->language->loadLanguageModule('wopi'); $this->settings = $DIC->settings(); $this->crawler = new Crawler(); diff --git a/components/ILIAS/WOPI/service.xml b/components/ILIAS/WOPI/service.xml index 8e4540c995cf..b05406a3c17d 100755 --- a/components/ILIAS/WOPI/service.xml +++ b/components/ILIAS/WOPI/service.xml @@ -1,7 +1,4 @@ - - - - - - - + + + + diff --git a/components/ILIAS/WebServices/WebServices.php b/components/ILIAS/WebServices/WebServices.php index 6ae160704ecf..d3623bea5383 100644 --- a/components/ILIAS/WebServices/WebServices.php +++ b/components/ILIAS/WebServices/WebServices.php @@ -41,5 +41,12 @@ public function init( new \ilECSAgent( $pull[\ILIAS\Refinery\Factory::class] ); + + $contribute[\ILIAS\Cron\CronJob::class] = static fn() => + new \ilCronEcsTaskScheduler( + self::class, + $use[\ILIAS\Language\Language::class], + $use[\ILIAS\Logging\LoggerFactory::class] + ); } } diff --git a/components/ILIAS/WebServices/classes/class.ilCronEcsTaskScheduler.php b/components/ILIAS/WebServices/classes/class.ilCronEcsTaskScheduler.php index 85866638939f..d12f6408ea17 100755 --- a/components/ILIAS/WebServices/classes/class.ilCronEcsTaskScheduler.php +++ b/components/ILIAS/WebServices/classes/class.ilCronEcsTaskScheduler.php @@ -18,6 +18,7 @@ use ILIAS\Cron\Job\Schedule\JobScheduleType; use ILIAS\Cron\Job\JobResult; +use ILIAS\Cron\AbstractCronJob; /** * Class ilCronEcsTaskScheduler @@ -25,16 +26,16 @@ * Start execution of ecs tasks. * */ -class ilCronEcsTaskScheduler extends \ILIAS\Cron\CronJob +class ilCronEcsTaskScheduler extends AbstractCronJob { - public const ID = 'ecs_task_handler'; - public const DEFAULT_SCHEDULE_VALUE = 1; + public const string ID = 'ecs_task_handler'; + public const int DEFAULT_SCHEDULE_VALUE = 1; private ilLogger $logger; private ilLanguage $lng; private JobResult $result; - public function __construct() + public function init(): void { global $DIC; @@ -42,7 +43,7 @@ public function __construct() $this->lng = $DIC->language(); $this->lng->loadLanguageModule('ecs'); - $this->result = new \ILIAS\Cron\Job\JobResult(); + $this->result = new JobResult(); } public function getTitle(): string @@ -92,7 +93,7 @@ public function run(): JobResult $scheduler = \ilECSTaskScheduler::_getInstanceByServerId($server->getServerId()); $scheduler->startTaskExecution(); } catch (Exception $e) { - $this->result->setStatus(\ILIAS\Cron\Job\JobResult::STATUS_CRASHED); + $this->result->setStatus(JobResult::STATUS_CRASHED); $this->result->setMessage( mb_substr(sprintf('Exc.: %s / %s', $e->getMessage(), $e->getTraceAsString()), 0, 400) ); @@ -101,7 +102,7 @@ public function run(): JobResult return $this->result; } } - $this->result->setStatus(\ILIAS\Cron\Job\JobResult::STATUS_OK); + $this->result->setStatus(JobResult::STATUS_OK); return $this->result; } } diff --git a/components/ILIAS/WebServices/service.xml b/components/ILIAS/WebServices/service.xml index 6196f8e25a90..34913856dca0 100755 --- a/components/ILIAS/WebServices/service.xml +++ b/components/ILIAS/WebServices/service.xml @@ -1,25 +1,22 @@ - - - - - - - adm - - - - - - - - - - - - - - - - - + + + + + + + adm + + + + + + + + + + + + + +