Lines 94.73% 18 / 19
Functions and Methods 90.00% 9 / 10
Classes and Traits 0.00% 0 / 1
Name Lines Functions and Methods CRAP Classes and Traits
EntityStateCollection 94.73% 18 / 19 90.00% 9 / 10 13.02 0.00% 0 / 1
 keyedByEntityId 100.00% 1 / 1 100.00% 1 / 1 1
 find 100.00% 1 / 1 100.00% 1 / 1 1
 withState 100.00% 1 / 1 100.00% 1 / 1 1
 withoutState 100.00% 1 / 1 100.00% 1 / 1 1
 listEntityIds 100.00% 1 / 1 100.00% 1 / 1 1
 filterBySelector 100.00% 5 / 5 100.00% 1 / 1 3
 filterByEntityFilter 100.00% 1 / 1 100.00% 1 / 1 1
 sortedByEntityId 0.00% 0 / 1 0.00% 0 / 1 2
 groupByDomain 100.00% 4 / 4 100.00% 1 / 1 2
 listDomains 100.00% 3 / 3 100.00% 1 / 1 1
1<?php
2
3declare(strict_types=1);
4
5namespace Stewart\Contracts\State\Collection;
6
7use Stewart\Contracts\Collection\KeyedCollection;
8use Stewart\Contracts\Entity\Collection\EntityIdCollection;
9use Stewart\Contracts\Entity\EntityId;
10use Stewart\Contracts\Registry\EntityFilter;
11use Stewart\Contracts\Registry\Registry;
12use Stewart\Contracts\Selector\Selector;
13use Stewart\Contracts\State\EntityState;
14
15/** @extends KeyedCollection<string, EntityState> */
16final readonly class EntityStateCollection extends KeyedCollection
17{
18    /** @param iterable<EntityState> $states */
19    public static function keyedByEntityId(iterable $states): self
20    {
21        return self::keyedBy($states, static fn(EntityState $state): string => $state->entityId->value);
22    }
23
24    public function find(EntityId $entityId): ?EntityState
25    {
26        return $this->elementAt($entityId->value);
27    }
28
29    public function withState(EntityState $state): self
30    {
31        return $this->withElementAt($state->entityId->value, $state);
32    }
33
34    public function withoutState(EntityId $entityId): self
35    {
36        return $this->withoutKey($entityId->value);
37    }
38
39    public function listEntityIds(): EntityIdCollection
40    {
41        return EntityIdCollection::fromList($this->mapToList(static fn(EntityState $state): EntityId => $state->entityId));
42    }
43
44    public function filterBySelector(Selector $selector): self
45    {
46        $exactPattern = $selector->findExactPattern();
47
48        if ($exactPattern !== null) {
49            $state = $this->elementAt($exactPattern);
50
51            return $state === null ? self::empty() : new self([$exactPattern => $state]);
52        }
53
54        return $this->filter(static fn(EntityState $state): bool => $selector->matches($state->entityId->value));
55    }
56
57    public function filterByEntityFilter(EntityFilter $filter, Registry $registry): self
58    {
59        return $this->filter(static fn(EntityState $state): bool => $filter->matchesEntity($state->entityId, $registry));
60    }
61
62    public function sortedByEntityId(): self
63    {
64        return $this->sortedBy(static fn(EntityState $a, EntityState $b): int => strcmp($a->entityId->value, $b->entityId->value));
65    }
66
67    /** @return array<string, self> */
68    public function groupByDomain(): array
69    {
70        $grouped = [];
71
72        foreach ($this as $key => $state) {
73            $grouped[$state->getDomain()][$key] = $state;
74        }
75
76        return array_map(static fn(array $states): self => new self($states), $grouped);
77    }
78
79    /** @return list<string> */
80    public function listDomains(): array
81    {
82        $domains = array_values(array_unique($this->mapToList(static fn(EntityState $state): string => $state->getDomain())));
83        sort($domains);
84
85        return $domains;
86    }
87}