From 7b551547b647f86028e2ce0fe01c759b20ee012e Mon Sep 17 00:00:00 2001 From: Daniel Siepmann <daniel.siepmann@codappix.com> Date: Tue, 11 Feb 2025 14:14:36 +0100 Subject: [PATCH] Refactor date factory Use a dedicated object to represent the incoming data. That way the factory can ask the data/date questions and fetch data. We do not need to expose the internals to the factory. --- Classes/Domain/DestinationData/Date.php | 117 ++++++++++++++++++ Classes/Domain/Model/Date.php | 8 +- .../DatesFactory.php | 95 ++++---------- 3 files changed, 148 insertions(+), 72 deletions(-) create mode 100644 Classes/Domain/DestinationData/Date.php diff --git a/Classes/Domain/DestinationData/Date.php b/Classes/Domain/DestinationData/Date.php new file mode 100644 index 0000000..ad38d58 --- /dev/null +++ b/Classes/Domain/DestinationData/Date.php @@ -0,0 +1,117 @@ +<?php + +declare(strict_types=1); + +namespace WerkraumMedia\Events\Domain\DestinationData; + +use DateTimeImmutable; +use DateTimeZone; +use RuntimeException; + +final class Date +{ + public function __construct( + private readonly array $data + ) { + } + + public function isSingle(): bool + { + $frequency = $this->data['freq'] ?? ''; + $start = $this->data['start'] ?? ''; + + return $frequency === '' + && $start !== ''; + } + + public function isInterval(): bool + { + return $this->isDaily() + || $this->isWeekly(); + } + + public function isDaily(): bool + { + return $this->getFrequency() == 'Daily' && empty($this->data['weekdays']); + } + + public function isWeekly(): bool + { + return $this->getFrequency() == 'Weekly' && !empty($this->data['weekdays']); + } + + public function isAfter(DateTimeImmutable $comparison): bool + { + return new DateTimeImmutable($this->data['start']) > $comparison; + } + + public function hasKnownRepeat(): bool + { + return empty($this->data['repeatUntil']) === false + || empty($this->data['repeatCount']) === false; + } + + public function withRepeatUntil(string $repeatUntil): self + { + $data = $this->data; + $data['repeatUntil'] = $repeatUntil; + + return new self($data); + } + + public function getStart(): DateTimeImmutable + { + return new DateTimeImmutable( + $this->data['start'], + new DateTimeZone($this->data['tz']) + ); + } + + public function getEnd(): DateTimeImmutable + { + return new DateTimeImmutable( + $this->data['end'], + new DateTimeZone($this->data['tz']) + ); + } + + public function getTimeZone(): DateTimeZone + { + return new DateTimeZone($this->data['tz']); + } + + /** + * @return string[] + */ + public function getWeekdays(): array + { + return $this->data['weekdays']; + } + + public function getRepeatUntil(): DateTimeImmutable + { + if (array_key_exists('repeatUntil', $this->data)) { + return new DateTimeImmutable($this->data['repeatUntil'], $this->getTimezone()); + } + + $repeatCountUnit = ''; + if ($this->isDaily()) { + $repeatCountUnit = 'days'; + } elseif ($this->isWeekly()) { + $repeatCountUnit = 'weeks'; + } + + if ($repeatCountUnit === '') { + throw new RuntimeException('The current date can not repeat.', 1739279561); + } + + return $this->getStart()->modify( + '+' . ((int)$this->data['repeatCount']) . ' ' . $repeatCountUnit + ); + } + + private function getFrequency(): string + { + return $this->data['freq'] ?? ''; + } +} diff --git a/Classes/Domain/Model/Date.php b/Classes/Domain/Model/Date.php index 4be5ecc..fb5e280 100644 --- a/Classes/Domain/Model/Date.php +++ b/Classes/Domain/Model/Date.php @@ -6,8 +6,8 @@ namespace WerkraumMedia\Events\Domain\Model; use DateTime; use DateTimeImmutable; -use DateTimeZone; use TYPO3\CMS\Extbase\DomainObject\AbstractEntity; +use WerkraumMedia\Events\Domain\DestinationData\Date as DestinationDataDate; /** * Date @@ -126,12 +126,12 @@ class Date extends AbstractEntity } public static function createFromDestinationDataDate( - array $date, + DestinationDataDate $date, bool $canceled ): self { return self::createFromDestinationData( - new DateTimeImmutable($date['start'], new DateTimeZone($date['tz'])), - new DateTimeImmutable($date['end'], new DateTimeZone($date['tz'])), + $date->getStart(), + $date->getEnd(), $canceled ); } diff --git a/Classes/Service/DestinationDataImportService/DatesFactory.php b/Classes/Service/DestinationDataImportService/DatesFactory.php index e0aeda3..879de14 100644 --- a/Classes/Service/DestinationDataImportService/DatesFactory.php +++ b/Classes/Service/DestinationDataImportService/DatesFactory.php @@ -7,11 +7,11 @@ namespace WerkraumMedia\Events\Service\DestinationDataImportService; use DateInterval; use DatePeriod; use DateTimeImmutable; -use DateTimeZone; use Generator; use Psr\Log\LoggerInterface; use TYPO3\CMS\Core\Context\Context; use TYPO3\CMS\Core\Log\LogManager; +use WerkraumMedia\Events\Domain\DestinationData\Date as DestinationDataDate; use WerkraumMedia\Events\Domain\Model\Date; use WerkraumMedia\Events\Domain\Model\Import; @@ -54,12 +54,14 @@ final class DatesFactory array $date, bool $canceled ): ?Generator { - if ($this->isDateSingleDate($date)) { + $date = new DestinationDataDate($date); + + if ($date->isSingle()) { $this->logger->info('Is single date', ['date' => $date]); return $this->createSingleDate($date, $canceled); } - if ($this->isDateInterval($date)) { + if ($date->isInterval()) { $this->logger->info('Is interval date', ['date' => $date]); return $this->createDateFromInterval($import, $date, $canceled); } @@ -67,38 +69,14 @@ final class DatesFactory return null; } - private function isDateSingleDate(array $date): bool - { - $frequency = $date['freq'] ?? ''; - $start = $date['start'] ?? ''; - - return $frequency === '' - && $start !== ''; - } - - private function isDateInterval(array $date): bool - { - $frequency = $date['freq'] ?? ''; - - if ($frequency == 'Daily' && empty($date['weekdays'])) { - return true; - } - - if ($frequency == 'Weekly' && !empty($date['weekdays'])) { - return true; - } - - return false; - } - /** * @return Generator<Date> */ private function createSingleDate( - array $date, + DestinationDataDate $date, bool $canceled ): Generator { - if (new DateTimeImmutable($date['start']) > $this->getToday()) { + if ($date->isAfter($this->getToday())) { yield Date::createFromDestinationDataDate($date, $canceled); } } @@ -108,16 +86,16 @@ final class DatesFactory */ private function createDateFromInterval( Import $import, - array $date, + DestinationDataDate $date, bool $canceled ): ?Generator { $date = $this->ensureRepeatUntil($import, $date); - if ($date['freq'] == 'Daily') { + if ($date->isDaily()) { return $this->createDailyDates($date, $canceled); } - if ($date['freq'] == 'Weekly') { + if ($date->isWeekly()) { return $this->createWeeklyDates($date, $canceled); } @@ -126,35 +104,31 @@ final class DatesFactory private function ensureRepeatUntil( Import $import, - array $date - ): array { - if (empty($date['repeatUntil']) === false) { - return $date; - } - if (empty($date['repeatCount']) === false) { + DestinationDataDate $date + ): DestinationDataDate { + if ($date->hasKnownRepeat()) { return $date; } - $date['repeatUntil'] = $this->getToday()->modify($import->getRepeatUntil())->format('c'); - $this->logger->info('Interval did not provide repeatUntil.', ['newRepeat' => $date['repeatUntil']]); + $repeatUntil = $this->getToday()->modify($import->getRepeatUntil())->format('c'); + $this->logger->info('Interval did not provide repeatUntil.', ['newRepeat' => $repeatUntil]); - return $date; + return $date->withRepeatUntil($repeatUntil); } /** * @return Generator<Date> */ private function createDailyDates( - array $date, + DestinationDataDate $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 = $this->createUntil($start, $date, 'days'); + $timeZone = $date->getTimeZone(); + $start = $date->getStart(); + $end = $date->getEnd(); - $period = new DatePeriod($start, new DateInterval('P1D'), $until); + $period = new DatePeriod($start, new DateInterval('P1D'), $date->getRepeatUntil()); foreach ($period as $day) { $day = $day->setTimezone($timeZone); if ($day < $today) { @@ -175,16 +149,16 @@ final class DatesFactory * @return Generator<Date> */ private function createWeeklyDates( - array $date, + DestinationDataDate $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 = $this->createUntil($start, $date, 'weeks'); + $timeZone = $date->getTimeZone(); + $start = $date->getStart(); + $end = $date->getEnd(); + $until = $date->getRepeatUntil(); - foreach ($date['weekdays'] as $day) { + foreach ($date->getWeekdays() as $day) { $dateToUse = $start->modify($day); $dateToUse = $dateToUse->setTime((int)$start->format('H'), (int)$start->format('i')); @@ -219,21 +193,6 @@ final class DatesFactory ); } - /** - * @param string $repeatCountUnit E.g. weeks or days - */ - private function createUntil( - DateTimeImmutable $start, - array $date, - string $repeatCountUnit, - ): DateTimeImmutable { - if (array_key_exists('repeatUntil', $date)) { - return new DateTimeImmutable($date['repeatUntil'], $start->getTimezone()); - } - - return $start->modify('+' . ((int)$date['repeatCount']) . ' ' . $repeatCountUnit); - } - private function getToday(): DateTimeImmutable { $today = $this->context->getPropertyFromAspect('date', 'full', new DateTimeImmutable());