instances added god may help
This commit is contained in:
@@ -9,59 +9,67 @@ class ScheduledJobService
|
||||
{
|
||||
private const RUN_RETENTION_DAYS = 90;
|
||||
|
||||
public static function ensureSystemJobs(): void
|
||||
public function __construct(
|
||||
private readonly ScheduledJobRepository $scheduledJobRepository,
|
||||
private readonly ScheduledJobRunRepository $scheduledJobRunRepository,
|
||||
private readonly ScheduledJobRegistry $scheduledJobRegistry,
|
||||
private readonly ScheduleCalculator $scheduleCalculator
|
||||
) {
|
||||
}
|
||||
|
||||
public function ensureSystemJobs(): void
|
||||
{
|
||||
$definitions = ScheduledJobRegistry::definitions();
|
||||
$definitions = $this->scheduledJobRegistry->definitions();
|
||||
$nowUtc = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));
|
||||
|
||||
foreach ($definitions as $jobKey => $definition) {
|
||||
$existing = ScheduledJobRepository::findByKey($jobKey);
|
||||
$job = self::buildDefaultJob($definition, $jobKey, $nowUtc);
|
||||
$existing = $this->scheduledJobRepository->findByKey($jobKey);
|
||||
$job = $this->buildDefaultJob($definition, $jobKey, $nowUtc);
|
||||
|
||||
if (!$existing) {
|
||||
ScheduledJobRepository::create($job);
|
||||
$this->scheduledJobRepository->create($job);
|
||||
continue;
|
||||
}
|
||||
|
||||
$normalized = self::normalizeStoredJob($existing, $definition);
|
||||
if (!self::jobsDiffer($existing, $normalized)) {
|
||||
$normalized = $this->normalizeStoredJob($existing, $definition);
|
||||
if (!$this->jobsDiffer($existing, $normalized)) {
|
||||
continue;
|
||||
}
|
||||
ScheduledJobRepository::updateJobMeta((int) $existing['id'], $normalized);
|
||||
$this->scheduledJobRepository->updateJobMeta((int) $existing['id'], $normalized);
|
||||
}
|
||||
}
|
||||
|
||||
public static function listPaged(array $filters): array
|
||||
public function listPaged(array $filters): array
|
||||
{
|
||||
self::ensureSystemJobs();
|
||||
return ScheduledJobRepository::listPaged($filters);
|
||||
$this->ensureSystemJobs();
|
||||
return $this->scheduledJobRepository->listPaged($filters);
|
||||
}
|
||||
|
||||
public static function find(int $id): ?array
|
||||
public function find(int $id): ?array
|
||||
{
|
||||
self::ensureSystemJobs();
|
||||
return ScheduledJobRepository::find($id);
|
||||
$this->ensureSystemJobs();
|
||||
return $this->scheduledJobRepository->find($id);
|
||||
}
|
||||
|
||||
public static function updateFromAdmin(int $id, array $input): array
|
||||
public function updateFromAdmin(int $id, array $input): array
|
||||
{
|
||||
$job = self::find($id);
|
||||
$job = $this->find($id);
|
||||
if (!$job) {
|
||||
return ['ok' => false, 'errors' => [t('Scheduled job not found')]];
|
||||
return ['ok' => false, 'errors' => [$this->translate('Scheduled job not found')]];
|
||||
}
|
||||
|
||||
$definition = ScheduledJobRegistry::get((string) ($job['job_key'] ?? ''));
|
||||
$definition = $this->scheduledJobRegistry->get((string) ($job['job_key'] ?? ''));
|
||||
if (!$definition) {
|
||||
return ['ok' => false, 'errors' => [t('Scheduled job is not registered')]];
|
||||
return ['ok' => false, 'errors' => [$this->translate('Scheduled job is not registered')]];
|
||||
}
|
||||
|
||||
$form = [
|
||||
'enabled' => isset($input['enabled']) ? 1 : 0,
|
||||
'timezone' => ScheduleCalculator::normalizeTimezone((string) ($input['timezone'] ?? ($job['timezone'] ?? ''))),
|
||||
'schedule_type' => ScheduleCalculator::normalizeScheduleType((string) ($input['schedule_type'] ?? ($job['schedule_type'] ?? 'daily'))),
|
||||
'timezone' => $this->scheduleCalculator->normalizeTimezone((string) ($input['timezone'] ?? ($job['timezone'] ?? ''))),
|
||||
'schedule_type' => $this->scheduleCalculator->normalizeScheduleType((string) ($input['schedule_type'] ?? ($job['schedule_type'] ?? 'daily'))),
|
||||
'schedule_interval' => (int) ($input['schedule_interval'] ?? ($job['schedule_interval'] ?? 1)),
|
||||
'schedule_time' => ScheduleCalculator::normalizeTime((string) ($input['schedule_time'] ?? ($job['schedule_time'] ?? ''))),
|
||||
'schedule_weekdays_csv' => ScheduleCalculator::normalizeWeekdaysCsv(
|
||||
'schedule_time' => $this->scheduleCalculator->normalizeTime((string) ($input['schedule_time'] ?? ($job['schedule_time'] ?? ''))),
|
||||
'schedule_weekdays_csv' => $this->scheduleCalculator->normalizeWeekdaysCsv(
|
||||
array_key_exists('schedule_weekdays', $input)
|
||||
? $input['schedule_weekdays']
|
||||
: ($job['schedule_weekdays_csv'] ?? '')
|
||||
@@ -69,18 +77,18 @@ class ScheduledJobService
|
||||
'catchup_once' => isset($input['catchup_once']) ? 1 : 0,
|
||||
];
|
||||
|
||||
$errors = self::validateForm($form, $definition);
|
||||
$errors = $this->validateForm($form, $definition);
|
||||
if ($errors) {
|
||||
return ['ok' => false, 'errors' => $errors, 'form' => $form, 'job' => $job];
|
||||
}
|
||||
|
||||
$nextRunAt = null;
|
||||
if ((int) $form['enabled'] === 1) {
|
||||
$nextRun = ScheduleCalculator::calculateNextRunUtc($form, new \DateTimeImmutable('now', new \DateTimeZone('UTC')));
|
||||
$nextRun = $this->scheduleCalculator->calculateNextRunUtc($form, new \DateTimeImmutable('now', new \DateTimeZone('UTC')));
|
||||
$nextRunAt = $nextRun ? $nextRun->format('Y-m-d H:i:s') : null;
|
||||
}
|
||||
|
||||
$updated = ScheduledJobRepository::updateJobMeta((int) $job['id'], [
|
||||
$updated = $this->scheduledJobRepository->updateJobMeta((int) $job['id'], [
|
||||
'label' => (string) ($definition['label'] ?? (string) ($job['label'] ?? '')),
|
||||
'description' => (string) ($definition['description'] ?? (string) ($job['description'] ?? '')),
|
||||
'enabled' => (int) $form['enabled'],
|
||||
@@ -94,95 +102,95 @@ class ScheduledJobService
|
||||
]);
|
||||
|
||||
if (!$updated) {
|
||||
return ['ok' => false, 'errors' => [t('Scheduled job could not be saved')], 'form' => $form, 'job' => $job];
|
||||
return ['ok' => false, 'errors' => [$this->translate('Scheduled job could not be saved')], 'form' => $form, 'job' => $job];
|
||||
}
|
||||
|
||||
$fresh = self::find((int) $job['id']);
|
||||
$fresh = $this->find((int) $job['id']);
|
||||
return ['ok' => true, 'job' => $fresh, 'form' => $form];
|
||||
}
|
||||
|
||||
public static function listRunsByJobId(int $jobId, array $filters): array
|
||||
public function listRunsByJobId(int $jobId, array $filters): array
|
||||
{
|
||||
return ScheduledJobRunRepository::listPagedByJobId($jobId, $filters);
|
||||
return $this->scheduledJobRunRepository->listPagedByJobId($jobId, $filters);
|
||||
}
|
||||
|
||||
public static function purgeRunsExpired(): int
|
||||
public function purgeRunsExpired(): int
|
||||
{
|
||||
return ScheduledJobRunRepository::purgeOlderThanDays(self::RUN_RETENTION_DAYS);
|
||||
return $this->scheduledJobRunRepository->purgeOlderThanDays(self::RUN_RETENTION_DAYS);
|
||||
}
|
||||
|
||||
public static function scheduleSummary(array $job): string
|
||||
public function scheduleSummary(array $job): string
|
||||
{
|
||||
$type = ScheduleCalculator::normalizeScheduleType((string) ($job['schedule_type'] ?? 'daily'));
|
||||
$type = $this->scheduleCalculator->normalizeScheduleType((string) ($job['schedule_type'] ?? 'daily'));
|
||||
$interval = (int) ($job['schedule_interval'] ?? 1);
|
||||
$time = (string) ($job['schedule_time'] ?? '');
|
||||
|
||||
if ($type === 'hourly') {
|
||||
return sprintf(t('Every %d hour(s)'), max(1, $interval));
|
||||
return sprintf($this->translate('Every %d hour(s)'), max(1, $interval));
|
||||
}
|
||||
if ($type === 'daily') {
|
||||
return sprintf(t('Every %d day(s) at %s'), max(1, $interval), $time !== '' ? $time : '--:--');
|
||||
return sprintf($this->translate('Every %d day(s) at %s'), max(1, $interval), $time !== '' ? $time : '--:--');
|
||||
}
|
||||
|
||||
$weekdays = ScheduleCalculator::parseWeekdays((string) ($job['schedule_weekdays_csv'] ?? ''));
|
||||
$weekdays = $this->scheduleCalculator->parseWeekdays((string) ($job['schedule_weekdays_csv'] ?? ''));
|
||||
$labels = [];
|
||||
foreach ($weekdays as $day) {
|
||||
$labels[] = self::weekdayLabel($day);
|
||||
$labels[] = $this->weekdayLabel($day);
|
||||
}
|
||||
$weekdayText = $labels ? implode(', ', $labels) : t('No weekdays');
|
||||
$weekdayText = $labels ? implode(', ', $labels) : $this->translate('No weekdays');
|
||||
return sprintf(
|
||||
t('Every %d week(s) on %s at %s'),
|
||||
$this->translate('Every %d week(s) on %s at %s'),
|
||||
max(1, $interval),
|
||||
$weekdayText,
|
||||
$time !== '' ? $time : '--:--'
|
||||
);
|
||||
}
|
||||
|
||||
public static function weekdaysFromCsv(?string $csv): array
|
||||
public function weekdaysFromCsv(?string $csv): array
|
||||
{
|
||||
return ScheduleCalculator::parseWeekdays((string) ($csv ?? ''));
|
||||
return $this->scheduleCalculator->parseWeekdays((string) ($csv ?? ''));
|
||||
}
|
||||
|
||||
private static function validateForm(array $form, array $definition): array
|
||||
private function validateForm(array $form, array $definition): array
|
||||
{
|
||||
$errors = [];
|
||||
$allowedTypes = $definition['allowed_schedule_types'] ?? ['hourly', 'daily', 'weekly'];
|
||||
$type = (string) ($form['schedule_type'] ?? 'daily');
|
||||
if (!in_array($type, $allowedTypes, true)) {
|
||||
$errors[] = t('Schedule type is invalid');
|
||||
$errors[] = $this->translate('Schedule type is invalid');
|
||||
return $errors;
|
||||
}
|
||||
|
||||
$interval = (int) ($form['schedule_interval'] ?? 0);
|
||||
if ($type === 'hourly' && ($interval < 1 || $interval > 24)) {
|
||||
$errors[] = t('Hourly interval must be between 1 and 24');
|
||||
$errors[] = $this->translate('Hourly interval must be between 1 and 24');
|
||||
} elseif ($type === 'daily' && ($interval < 1 || $interval > 365)) {
|
||||
$errors[] = t('Daily interval must be between 1 and 365');
|
||||
$errors[] = $this->translate('Daily interval must be between 1 and 365');
|
||||
} elseif ($type === 'weekly' && ($interval < 1 || $interval > 52)) {
|
||||
$errors[] = t('Weekly interval must be between 1 and 52');
|
||||
$errors[] = $this->translate('Weekly interval must be between 1 and 52');
|
||||
}
|
||||
|
||||
$timezone = trim((string) ($form['timezone'] ?? ''));
|
||||
try {
|
||||
new \DateTimeZone($timezone);
|
||||
} catch (\Throwable $exception) {
|
||||
$errors[] = t('Timezone is invalid');
|
||||
$errors[] = $this->translate('Timezone is invalid');
|
||||
}
|
||||
|
||||
if (in_array($type, ['daily', 'weekly'], true) && $form['schedule_time'] === null) {
|
||||
$errors[] = t('Schedule time is required');
|
||||
$errors[] = $this->translate('Schedule time is required');
|
||||
}
|
||||
if ($type === 'weekly') {
|
||||
$weekdays = ScheduleCalculator::parseWeekdays((string) ($form['schedule_weekdays_csv'] ?? ''));
|
||||
$weekdays = $this->scheduleCalculator->parseWeekdays((string) ($form['schedule_weekdays_csv'] ?? ''));
|
||||
if (!$weekdays) {
|
||||
$errors[] = t('At least one weekday is required for weekly schedule');
|
||||
$errors[] = $this->translate('At least one weekday is required for weekly schedule');
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
private static function buildDefaultJob(array $definition, string $jobKey, \DateTimeImmutable $nowUtc): array
|
||||
private function buildDefaultJob(array $definition, string $jobKey, \DateTimeImmutable $nowUtc): array
|
||||
{
|
||||
$type = (string) ($definition['default_schedule_type'] ?? 'daily');
|
||||
$job = [
|
||||
@@ -190,40 +198,40 @@ class ScheduledJobService
|
||||
'label' => (string) ($definition['label'] ?? $jobKey),
|
||||
'description' => (string) ($definition['description'] ?? ''),
|
||||
'enabled' => (int) ($definition['default_enabled'] ?? 1),
|
||||
'timezone' => ScheduleCalculator::normalizeTimezone((string) ($definition['default_timezone'] ?? '')),
|
||||
'schedule_type' => ScheduleCalculator::normalizeScheduleType($type),
|
||||
'schedule_interval' => ScheduleCalculator::normalizeInterval($type, (int) ($definition['default_schedule_interval'] ?? 1)),
|
||||
'schedule_time' => ScheduleCalculator::normalizeTime((string) ($definition['default_schedule_time'] ?? '')),
|
||||
'schedule_weekdays_csv' => ScheduleCalculator::normalizeWeekdaysCsv($definition['default_schedule_weekdays_csv'] ?? null),
|
||||
'timezone' => $this->scheduleCalculator->normalizeTimezone((string) ($definition['default_timezone'] ?? '')),
|
||||
'schedule_type' => $this->scheduleCalculator->normalizeScheduleType($type),
|
||||
'schedule_interval' => $this->scheduleCalculator->normalizeInterval($type, (int) ($definition['default_schedule_interval'] ?? 1)),
|
||||
'schedule_time' => $this->scheduleCalculator->normalizeTime((string) ($definition['default_schedule_time'] ?? '')),
|
||||
'schedule_weekdays_csv' => $this->scheduleCalculator->normalizeWeekdaysCsv($definition['default_schedule_weekdays_csv'] ?? null),
|
||||
'catchup_once' => (int) ($definition['default_catchup_once'] ?? 1),
|
||||
'next_run_at' => null,
|
||||
];
|
||||
if ((int) $job['enabled'] === 1) {
|
||||
$nextRun = ScheduleCalculator::calculateNextRunUtc($job, $nowUtc);
|
||||
$nextRun = $this->scheduleCalculator->calculateNextRunUtc($job, $nowUtc);
|
||||
$job['next_run_at'] = $nextRun ? $nextRun->format('Y-m-d H:i:s') : null;
|
||||
}
|
||||
return $job;
|
||||
}
|
||||
|
||||
private static function normalizeStoredJob(array $existing, array $definition): array
|
||||
private function normalizeStoredJob(array $existing, array $definition): array
|
||||
{
|
||||
$type = ScheduleCalculator::normalizeScheduleType((string) ($existing['schedule_type'] ?? ($definition['default_schedule_type'] ?? 'daily')));
|
||||
$type = $this->scheduleCalculator->normalizeScheduleType((string) ($existing['schedule_type'] ?? ($definition['default_schedule_type'] ?? 'daily')));
|
||||
$normalized = [
|
||||
'label' => (string) ($definition['label'] ?? (string) ($existing['label'] ?? '')),
|
||||
'description' => (string) ($definition['description'] ?? (string) ($existing['description'] ?? '')),
|
||||
'enabled' => (int) ($existing['enabled'] ?? ($definition['default_enabled'] ?? 1)),
|
||||
'timezone' => ScheduleCalculator::normalizeTimezone((string) ($existing['timezone'] ?? ($definition['default_timezone'] ?? ''))),
|
||||
'timezone' => $this->scheduleCalculator->normalizeTimezone((string) ($existing['timezone'] ?? ($definition['default_timezone'] ?? ''))),
|
||||
'schedule_type' => $type,
|
||||
'schedule_interval' => ScheduleCalculator::normalizeInterval($type, (int) ($existing['schedule_interval'] ?? ($definition['default_schedule_interval'] ?? 1))),
|
||||
'schedule_time' => ScheduleCalculator::normalizeTime((string) ($existing['schedule_time'] ?? ($definition['default_schedule_time'] ?? ''))),
|
||||
'schedule_weekdays_csv' => ScheduleCalculator::normalizeWeekdaysCsv(
|
||||
'schedule_interval' => $this->scheduleCalculator->normalizeInterval($type, (int) ($existing['schedule_interval'] ?? ($definition['default_schedule_interval'] ?? 1))),
|
||||
'schedule_time' => $this->scheduleCalculator->normalizeTime((string) ($existing['schedule_time'] ?? ($definition['default_schedule_time'] ?? ''))),
|
||||
'schedule_weekdays_csv' => $this->scheduleCalculator->normalizeWeekdaysCsv(
|
||||
(string) ($existing['schedule_weekdays_csv'] ?? ($definition['default_schedule_weekdays_csv'] ?? ''))
|
||||
),
|
||||
'catchup_once' => (int) ($existing['catchup_once'] ?? ($definition['default_catchup_once'] ?? 1)),
|
||||
'next_run_at' => (string) ($existing['next_run_at'] ?? ''),
|
||||
];
|
||||
if ($normalized['next_run_at'] === '' && (int) $normalized['enabled'] === 1) {
|
||||
$nextRun = ScheduleCalculator::calculateNextRunUtc($normalized, new \DateTimeImmutable('now', new \DateTimeZone('UTC')));
|
||||
$nextRun = $this->scheduleCalculator->calculateNextRunUtc($normalized, new \DateTimeImmutable('now', new \DateTimeZone('UTC')));
|
||||
$normalized['next_run_at'] = $nextRun ? $nextRun->format('Y-m-d H:i:s') : null;
|
||||
} else {
|
||||
$normalized['next_run_at'] = $normalized['next_run_at'] !== '' ? $normalized['next_run_at'] : null;
|
||||
@@ -231,7 +239,7 @@ class ScheduledJobService
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
private static function jobsDiffer(array $existing, array $normalized): bool
|
||||
private function jobsDiffer(array $existing, array $normalized): bool
|
||||
{
|
||||
$keys = [
|
||||
'label',
|
||||
@@ -255,17 +263,28 @@ class ScheduledJobService
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function weekdayLabel(int $weekday): string
|
||||
private function weekdayLabel(int $weekday): string
|
||||
{
|
||||
return match ($weekday) {
|
||||
1 => t('Mon'),
|
||||
2 => t('Tue'),
|
||||
3 => t('Wed'),
|
||||
4 => t('Thu'),
|
||||
5 => t('Fri'),
|
||||
6 => t('Sat'),
|
||||
7 => t('Sun'),
|
||||
1 => $this->translate('Mon'),
|
||||
2 => $this->translate('Tue'),
|
||||
3 => $this->translate('Wed'),
|
||||
4 => $this->translate('Thu'),
|
||||
5 => $this->translate('Fri'),
|
||||
6 => $this->translate('Sat'),
|
||||
7 => $this->translate('Sun'),
|
||||
default => '-',
|
||||
};
|
||||
}
|
||||
|
||||
private function translate(string $text, mixed ...$args): string
|
||||
{
|
||||
if (function_exists('t')) {
|
||||
return t($text, ...$args);
|
||||
}
|
||||
if ($args === []) {
|
||||
return $text;
|
||||
}
|
||||
return vsprintf($text, array_map(static fn ($arg) => (string) $arg, $args));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user