Lines 83.33% 20 / 24
Methods 73.33% 11 / 15
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 getDomain 0.00% 0 / 1 0.00% 0 / 1 2
 getObjectId 0.00% 0 / 1 0.00% 0 / 1 2
 isUnavailable 100.00% 1 / 1 100.00% 1 / 1 2
 wasLastChangedBy 100.00% 1 / 1 100.00% 1 / 1 2
 getAttribute 0.00% 0 / 1 0.00% 0 / 1 2
 getFloatAttribute 100.00% 2 / 2 100.00% 1 / 1 2
 getIntAttribute 75.00% 3 / 4 0.00% 0 / 1 4.25
 getStringAttribute 100.00% 2 / 2 100.00% 1 / 1 2
 getBoolAttribute 100.00% 2 / 2 100.00% 1 / 1 2
 getArrayAttribute 100.00% 2 / 2 100.00% 1 / 1 2
 getStateAsFloat 100.00% 1 / 1 100.00% 1 / 1 2
 getHeldDuration 100.00% 1 / 1 100.00% 1 / 1 2
 hasHeldFor 100.00% 2 / 2 100.00% 1 / 1 2
 getFriendlyName 100.00% 2 / 2 100.00% 1 / 1 2
12final readonly class EntityState
13{
14    public const string UNAVAILABLE = 'unavailable';
15
16    public const string UNKNOWN = 'unknown';
17
18    /** @param array<string, mixed> $attributes */
19    public function __construct(
20        public EntityId $entityId,
21        public string $state,
22        public array $attributes = [],
23        public ?Instant $lastChangedAt = null,
24        public ?Instant $lastUpdatedAt = null,
25        public ?EventContext $context = null,
26    ) {}
27
28    public function getDomain(): string
29    {
30        return $this->entityId->domain;
31    }
32
33    public function getObjectId(): string
34    {
35        return $this->entityId->objectId;
36    }
37
38    public function isUnavailable(): bool
39    {
40        return $this->state === self::UNAVAILABLE || $this->state === self::UNKNOWN;
41    }
42
43    public function wasLastChangedBy(EventContext $context): bool
44    {
45        return $this->context !== null && $context->isSameOrParentOf($this->context);
46    }
47
48    public function getAttribute(string $name): mixed
49    {
50        return $this->attributes[$name] ?? null;
51    }
52
53    public function getFloatAttribute(string $name): ?float
54    {
55        $value = $this->attributes[$name] ?? null;
56
57        return is_numeric($value) ? (float) $value : null;
58    }
59
60    public function getIntAttribute(string $name): ?int
61    {
62        $value = $this->attributes[$name] ?? null;
63
64        if (!\is_int($value) && !\is_float($value) && !\is_string($value)) {
65            return null;
66        }
67
68        return filter_var($value, \FILTER_VALIDATE_INT, \FILTER_NULL_ON_FAILURE);
69    }
70
71    public function getStringAttribute(string $name): ?string
72    {
73        $value = $this->attributes[$name] ?? null;
74
75        return \is_string($value) ? $value : null;
76    }
77
78    public function getBoolAttribute(string $name): ?bool
79    {
80        $value = $this->attributes[$name] ?? null;
81
82        return \is_bool($value) ? $value : null;
83    }
84
85    /** @return array<array-key, mixed>|null */
86    public function getArrayAttribute(string $name): ?array
87    {
88        $value = $this->attributes[$name] ?? null;
89
90        return \is_array($value) ? $value : null;
91    }
92
93    public function getStateAsFloat(): ?float
94    {
95        return is_numeric($this->state) ? (float) $this->state : null;
96    }
97
98    public function getHeldDuration(Clock $clock): ?Duration
99    {
100        return $this->lastChangedAt === null ? null : $clock->getNow()->elapsedSince($this->lastChangedAt);
101    }
102
103    public function hasHeldFor(Duration $duration, Clock $clock): bool
104    {
105        $held = $this->getHeldDuration($clock);
106
107        return $held !== null && !$duration->isLongerThan($held);
108    }
109
110    public function getFriendlyName(): string
111    {
112        $name = $this->attributes['friendly_name'] ?? null;
113
114        return \is_string($name) ? $name : $this->entityId->value;
115    }
116}