Lines 100.00% 29 / 29
Methods 100.00% 8 / 8
Classes 100.00% 1 / 1
Name Lines Methods CRAP
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 armForEntity 100.00% 19 / 19 100.00% 1 / 1 2
 refreshTasksOf 100.00% 2 / 2 100.00% 1 / 1 2
 cancelTasksOf 100.00% 2 / 2 100.00% 1 / 1 2
 cancelAll 100.00% 2 / 2 100.00% 1 / 1 2
 countFor 100.00% 1 / 1 100.00% 1 / 1 1
 forgetTask 100.00% 1 / 1 100.00% 1 / 1 1
 listTasksOf 100.00% 1 / 1 100.00% 1 / 1 1
18final class EntityTimeScheduler
19{
20    /** @var array<string, EntityTimeTask> */
21    private array $tasksById = [];
22
23    public function __construct(
24        private readonly ScheduleRegistry $registry,
25        private readonly ScopeLifecycle $scopes,
26        private readonly StateCache $states,
27        private readonly DispatchStreams $streams,
28        private readonly Clock $clock,
29    ) {}
30
31    /** @param Closure(ScheduledRun): void $handler */
32    public function armForEntity(ResourceScope $scope, LoggerInterface $logger, EntityId $entityId, Closure $handler): EntityTimeTask
33    {
34        $task = new EntityTimeTask(
35            $this->registry->claimTaskId(),
36            $entityId,
37            $scope,
38            $logger,
39            $handler,
40            $this->registry,
41            $this->states,
42            $this->clock,
43            $this->forgetTask(...),
44        );
45
46        if ($this->scopes->findOrCreateStateOf($scope)->isClosed()) {
47            $logger->debug('Ignored an entity time armed after its app stopped', ['entity' => $entityId->value]);
48            $task->cancel();
49
50            return $task;
51        }
52
53        $this->tasksById[$task->getId()] = $task;
54
55        $task->rearmFromCache();
56        $task->startFollowing($this->streams->watchStateChanges($scope, Selector::exact($entityId->value)));
57
58        return $task;
59    }
60
61    public function refreshTasksOf(ResourceScope $scope): void
62    {
63        foreach ($this->listTasksOf($scope) as $task) {
64            $task->rearmFromCache();
65        }
66    }
67
68    public function cancelTasksOf(ResourceScope $scope): void
69    {
70        foreach ($this->listTasksOf($scope) as $task) {
71            $task->cancel();
72        }
73    }
74
75    public function cancelAll(): void
76    {
77        foreach ($this->tasksById as $task) {
78            $task->cancel();
79        }
80    }
81
82    public function countFor(ResourceScope $scope): int
83    {
84        return \count($this->listTasksOf($scope));
85    }
86
87    private function forgetTask(EntityTimeTask $task): void
88    {
89        unset($this->tasksById[$task->getId()]);
90    }
91
92    /** @return array<string, EntityTimeTask> */
93    private function listTasksOf(ResourceScope $scope): array
94    {
95        return array_filter($this->tasksById, static fn(EntityTimeTask $task): bool => $task->scope->equals($scope));
96    }
97}