Lines
77.77%
21 / 27
Functions and Methods
42.85%
3 / 7
Classes and Traits
0.00%
0 / 1
| Name | Lines | Functions and Methods | CRAP | Classes and Traits | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| ManualEntityTimeTask | 77.77% | 21 / 27 | 42.85% | 3 / 7 | 16.15 | 0.00% | 0 / 1 | |||
| __construct | 100.00% | 5 / 5 | 100.00% | 1 / 1 | 1 | |||||
| getId | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | |||||
| cancel | 100.00% | 3 / 3 | 100.00% | 1 / 1 | 1 | |||||
| isActive | 0.00% | 0 / 1 | 0.00% | 0 / 1 | 2 | |||||
| getNextRunAt | 0.00% | 0 / 1 | 0.00% | 0 / 1 | 6 | |||||
| rearmFor | 90.90% | 10 / 11 | 0.00% | 0 / 1 | 4.01 | |||||
| createScheduleFor | 40.00% | 2 / 5 | 0.00% | 0 / 1 | 7.46 | |||||
| 1 | <?php | |
| 2 | ||
| 3 | declare(strict_types=1); | |
| 4 | ||
| 5 | namespace Stewart\Testing\Schedule; | |
| 6 | ||
| 7 | use Closure; | |
| 8 | use Stewart\Contracts\Entity\EntityId; | |
| 9 | use Stewart\Contracts\HaContext; | |
| 10 | use Stewart\Contracts\Schedule\ScheduledRun; | |
| 11 | use Stewart\Contracts\Schedule\ScheduledTask; | |
| 12 | use Stewart\Contracts\State\EntityState; | |
| 13 | use Stewart\Contracts\State\StateChange; | |
| 14 | use Stewart\Contracts\Subscription; | |
| 15 | use Stewart\Contracts\Time\Clock; | |
| 16 | use Stewart\Contracts\Time\Instant; | |
| 17 | use Stewart\Support\Schedule\CalendarSchedule; | |
| 18 | use Stewart\Support\Schedule\EntityTime; | |
| 19 | use Stewart\Support\Schedule\OneShotSchedule; | |
| 20 | use Stewart\Support\Schedule\WallClockSchedule; | |
| 21 | ||
| 22 | final class ManualEntityTimeTask implements ScheduledTask | |
| 23 | { | |
| 24 | private EntityTime $armedTime; | |
| 25 | ||
| 26 | private ?ScheduledTask $inner = null; | |
| 27 | ||
| 28 | private readonly Subscription $following; | |
| 29 | ||
| 30 | private bool $active = true; | |
| 31 | ||
| 32 | /** | |
| 33 | * @param Closure(WallClockSchedule, Closure(ScheduledRun): void): ScheduledTask $armTask | |
| 34 | * @param Closure(ScheduledRun): void $handler | |
| 35 | */ | |
| 36 | public function __construct( | |
| 37 | private readonly string $id, | |
| 38 | private readonly EntityId $entityId, | |
| 39 | HaContext $ha, | |
| 40 | private readonly Clock $clock, | |
| 41 | private readonly Closure $armTask, | |
| 42 | private readonly Closure $handler, | |
| 43 | ) { | |
| 44 | $this->armedTime = EntityTime::none(); | |
| 45 | $this->rearmFor($ha->getState($entityId)); | |
| 46 | $this->following = $ha->watchStateChanges($entityId)->subscribe(function (StateChange $change): void { | |
| 47 | $this->rearmFor($change->to); | |
| 48 | }); | |
| 49 | } | |
| 50 | ||
| 51 | public function getId(): string | |
| 52 | { | |
| 53 | return $this->id; | |
| 54 | } | |
| 55 | ||
| 56 | public function cancel(): void | |
| 57 | { | |
| 58 | $this->active = false; | |
| 59 | $this->inner?->cancel(); | |
| 60 | $this->following->unsubscribe(); | |
| 61 | } | |
| 62 | ||
| 63 | public function isActive(): bool | |
| 64 | { | |
| 65 | return $this->active; | |
| 66 | } | |
| 67 | ||
| 68 | public function getNextRunAt(): ?Instant | |
| 69 | { | |
| 70 | return $this->active ? $this->inner?->getNextRunAt() : null; | |
| 71 | } | |
| 72 | ||
| 73 | private function rearmFor(?EntityState $state): void | |
| 74 | { | |
| 75 | $time = EntityTime::fromEntityState($state, $this->clock->getTimeZone()); | |
| 76 | ||
| 77 | if (!$this->active || $time->equals($this->armedTime)) { | |
| 78 | return; | |
| 79 | } | |
| 80 | ||
| 81 | $this->inner?->cancel(); | |
| 82 | $this->inner = null; | |
| 83 | $this->armedTime = $time; | |
| 84 | $schedule = $this->createScheduleFor($time); | |
| 85 | ||
| 86 | if ($schedule !== null) { | |
| 87 | $this->inner = ($this->armTask)($schedule, function (ScheduledRun $run): void { | |
| 88 | ($this->handler)(new ScheduledRun($this, $run->scheduledFor, $run->firedAt, $run->missedOccurrences)); | |
| 89 | }); | |
| 90 | } | |
| 91 | } | |
| 92 | ||
| 93 | private function createScheduleFor(EntityTime $time): ?WallClockSchedule | |
| 94 | { | |
| 95 | if ($time->dailyAt !== null) { | |
| 96 | return CalendarSchedule::dailyAt($time->dailyAt); | |
| 97 | } | |
| 98 | ||
| 99 | if ($time->moment !== null && $time->moment->isAfter($this->clock->getNow())) { | |
| 100 | return OneShotSchedule::fromMoment($time->moment->toDateTime($this->clock->getTimeZone())); | |
| 101 | } | |
| 102 | ||
| 103 | return null; | |
| 104 | } | |
| 105 | } |