Lines 91.42% 32 / 35
Methods 83.33% 10 / 12
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 entityNotFound 0.00% 0 / 1 0.00% 0 / 1 2
 thresholdHysteresisNegative 100.00% 1 / 1 100.00% 1 / 1 2
 thresholdNotFinite 100.00% 1 / 1 100.00% 1 / 1 2
 [Stewart\Contracts\Exception\StewartException] __construct 100.00% 1 / 1 100.00% 1 / 1 1
 [Stewart\Contracts\Exception\StewartException] createForReason 100.00% 1 / 1 100.00% 1 / 1 1
 [Stewart\Contracts\Exception\StewartException] createForReasonWithAppendedText 100.00% 7 / 7 100.00% 1 / 1 3
 [Stewart\Contracts\Exception\StewartException] restoreFromWire 100.00% 1 / 1 100.00% 1 / 1 1
 [Stewart\Contracts\Exception\StewartException] findContextString 0.00% 0 / 2 0.00% 0 / 1 6
 [Stewart\Contracts\Exception\StewartException] requireNamedContext 100.00% 4 / 4 100.00% 1 / 1 3
 [Stewart\Contracts\Exception\StewartException] renderMessage 100.00% 5 / 5 100.00% 1 / 1 1
 [Stewart\Contracts\Exception\StewartException] renderPlaceholder 100.00% 8 / 8 100.00% 1 / 1 4
 [Stewart\Contracts\Exception\StewartException] renderScalar 100.00% 3 / 3 100.00% 1 / 1 5
10final class StateException extends StewartException
11{
12    public static function entityNotFound(EntityId $entityId): self
13    {
14        return self::createForReason(StateError::EntityNotFound, entityId: $entityId->value);
15    }
16
17    public static function thresholdHysteresisNegative(string $usage, float $hysteresis): self
18    {
19        return self::createForReason(StateError::ThresholdHysteresisNegative, usage: $usage, hysteresis: is_nan($hysteresis) ? 'NAN' : $hysteresis);
20    }
21
22    public static function thresholdNotFinite(string $usage, float $threshold): self
23    {
24        return self::createForReason(StateError::ThresholdNotFinite, usage: $usage, threshold: is_nan($threshold) ? 'NAN' : $threshold);
25    }
26}

Inherited from Stewart\Contracts\Exception\StewartException

24    final protected function __construct(
25        string $message,
26        public readonly ExceptionReason $reason,
27        public readonly ?array $context = null,
28        ?Throwable $previous = null,
29    ) {
30        parent::__construct($message, 0, $previous);
31    }
40    final public static function createForReason(
41        ExceptionReason $exceptionReason,
42        ?Throwable $previous = null,
43        string|int|float|bool|array|null ...$context,
44    ): static {
45        return self::createForReasonWithAppendedText($exceptionReason, self::requireNamedContext($context), null, $previous);
46    }
55    final protected static function createForReasonWithAppendedText(
56        ExceptionReason $reason,
57        array $context,
58        ?string $appendedText,
59        ?Throwable $previous = null,
60    ): static {
61        $message = self::renderMessage($reason, $context, $previous);
62
63        return new static(
64            $appendedText === null ? $message : $message . ' ' . $appendedText,
65            $reason,
66            $context === [] ? null : $context,
67            $previous,
68        );
69    }
78    final public static function restoreFromWire(ExceptionReason $reason, string $message, ?array $context): static
79    {
80        return new static($message, $reason, $context);
81    }
83    protected function findContextString(string $key): ?string
84    {
85        $value = $this->context[$key] ?? null;
86
87        return \is_string($value) ? $value : null;
88    }
94    private static function requireNamedContext(array $context): array
95    {
96        $named = [];
97
98        foreach ($context as $key => $value) {
99            $named[\is_string($key) ? $key : throw new LogicException('Pass the exception context as named arguments.')] = $value;
100        }
101
102        return $named;
103    }
106    private static function renderMessage(ExceptionReason $reason, array $context, ?Throwable $previous): string
107    {
108        return (string) preg_replace_callback(
109            '/\{(\w+)\}/',
110            static fn(array $placeholder): string => self::renderPlaceholder($placeholder[1], $context, $previous),
111            $reason->messageTemplate(),
112        );
113    }
116    private static function renderPlaceholder(string $name, array $context, ?Throwable $previous): string
117    {
118        if ($name === self::CAUSE_PLACEHOLDER) {
119            return $previous?->getMessage() ?? throw new LogicException('{cause} needs a previous exception.');
120        }
121
122        if (!\array_key_exists($name, $context)) {
123            throw new LogicException(\sprintf('The message template names {%s}, which the context lacks.', $name));
124        }
125
126        $value = $context[$name];
127
128        return \is_array($value)
129            ? implode(', ', array_map(self::renderScalar(...), $value))
130            : self::renderScalar($value);
131    }
133    private static function renderScalar(string|int|float|bool|null $value): string
134    {
135        return match (true) {
136            $value === null => 'none',
137            \is_bool($value) => $value ? 'true' : 'false',
138            default => (string) $value,
139        };
140    }