context = $context; } /** * @return \Generator */ public function createDates( array $timeIntervals, bool $canceled ): \Generator { foreach ($timeIntervals as $date) { $dates = $this->createDate($date, $canceled); if (!$dates instanceof \Generator) { return null; } foreach ($dates as $createdDate) { yield $createdDate; } } } /** * @return \Generator|null */ private function createDate( array $date, bool $canceled ): ?\Generator { if ($this->isDateSingleDate($date)) { return $this->createSingleDate($date, $canceled); } if ($this->isDateInterval($date)) { return $this->createDateFromInterval($date, $canceled); } return null; } private function isDateSingleDate(array $date): bool { $frequency = $date['freq'] ?? ''; $start = $date['start'] ?? ''; return $frequency === '' && $start !== ''; } private function isDateInterval(array $date): bool { if (empty($date['repeatUntil'])) { return false; } $frequency = $date['freq'] ?? ''; if ($frequency == 'Daily' && empty($date['weekdays'])) { return true; } if ($frequency == 'Weekly' && !empty($date['weekdays'])) { return true; } return false; } /** * @return \Generator */ private function createSingleDate( array $date, bool $canceled ): \Generator { if (new \DateTimeImmutable($date['start']) > $this->getToday()) { yield Date::createFromDestinationDataDate($date, $canceled); } } /** * @return \Generator|null */ private function createDateFromInterval( array $date, bool $canceled ): ?\Generator { if ($date['freq'] == 'Daily') { return $this->createDailyDates($date, $canceled); } if ($date['freq'] == 'Weekly') { return $this->createWeeklyDates($date, $canceled); } return null; } /** * @return \Generator */ private function createDailyDates( array $date, bool $canceled ): \Generator { $today = $this->getToday(); $timeZone = new \DateTimeZone($date['tz']); $start = new \DateTimeImmutable($date['start'], $timeZone); $end = new \DateTimeImmutable($date['end'], $timeZone); $until = new \DateTimeImmutable($date['repeatUntil'], $timeZone); $nextDate = $start; while ($nextDate <= $until) { $dateToUse = $nextDate; $nextDate = $dateToUse->modify('+1 day'); if ($dateToUse < $today) { continue; } yield $this->createDateFromStartAndEnd( $dateToUse, $start, $end, $canceled ); } } /** * @return \Generator */ private function createWeeklyDates( array $date, bool $canceled ): \Generator { $today = $this->getToday(); $timeZone = new \DateTimeZone($date['tz']); $start = new \DateTimeImmutable($date['start'], $timeZone); $end = new \DateTimeImmutable($date['end'], $timeZone); $until = new \DateTimeImmutable($date['repeatUntil'], $timeZone); foreach ($date['weekdays'] as $day) { $nextDate = $start->modify($day); while ($nextDate <= $until) { $dateToUse = $nextDate; $nextDate = $dateToUse->modify('+1 week'); if ($dateToUse < $today) { continue; } yield $this->createDateFromStartAndEnd( $dateToUse, $start, $end, $canceled ); } } } private function createDateFromStartAndEnd( \DateTimeImmutable $dateToUse, \DateTimeImmutable $start, \DateTimeImmutable $end, bool $canceled ): Date { return Date::createFromDestinationData( $dateToUse->setTime((int) $start->format('H'), (int) $start->format('i')), $dateToUse->setTime((int) $end->format('H'), (int) $end->format('i')), $canceled ); } private function getToday(): \DateTimeImmutable { $today = $this->context->getPropertyFromAspect('date', 'full', new \DateTimeImmutable()); if (!$today instanceof \DateTimeImmutable) { $today = new \DateTimeImmutable(); } return $today->modify('midnight'); } }