Lines 51.72% 30 / 58
Methods 53.33% 8 / 15
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 valueInvalid 0.00% 0 / 1 0.00% 0 / 1 2
 workerIndexOutOfRange 0.00% 0 / 7 0.00% 0 / 1 2
 appUnknown 0.00% 0 / 5 0.00% 0 / 1 2
 appSelectionUnknown 0.00% 0 / 5 0.00% 0 / 1 2
 environmentVariableUnknown 0.00% 0 / 5 0.00% 0 / 1 6
 describeKnownApps 0.00% 0 / 3 0.00% 0 / 1 6
 [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
12final class ConfigurationException extends StewartException
13{
14    public static function valueInvalid(string $value, string $expected): self
15    {
16        return self::createForReason(ConfigurationError::ValueInvalid, value: $value, expected: $expected);
17    }
18
19    public static function workerIndexOutOfRange(AppId $appId, int $worker, int $workers): self
20    {
21        return self::createForReason(
22            ConfigurationError::WorkerIndexOutOfRange,
23            appId: $appId->value,
24            worker: $worker,
25            workers: $workers,
26            highestIndex: $workers - 1,
27        );
28    }
29
30    public static function appUnknown(AppId $appId, AppIdCollection $knownAppIds): self
31    {
32        return self::createForReasonWithAppendedText(
33            ConfigurationError::AppUnknown,
34            ['appId' => $appId->value, 'knownAppIds' => $knownAppIds->toStrings()],
35            self::describeKnownApps($knownAppIds),
36        );
37    }
38
39    public static function appSelectionUnknown(AppId $appId, AppIdCollection $knownAppIds): self
40    {
41        return self::createForReasonWithAppendedText(
42            ConfigurationError::AppSelectionUnknown,
43            ['appId' => $appId->value, 'knownAppIds' => $knownAppIds->toStrings()],
44            self::describeKnownApps($knownAppIds),
45        );
46    }
47
48    public static function environmentVariableUnknown(string $variable, ?string $suggestion): self
49    {
50        return self::createForReasonWithAppendedText(
51            ConfigurationError::EnvironmentVariableUnknown,
52            ['variable' => $variable, 'suggestion' => $suggestion],
53            $suggestion === null ? null : \sprintf('Did you mean %s?', $suggestion),
54        );
55    }
56
57    private static function describeKnownApps(AppIdCollection $knownAppIds): string
58    {
59        return $knownAppIds->isEmpty()
60            ? 'No automations were found; check the #[Automation] attribute.'
61            : 'Known automations: ' . implode(', ', $knownAppIds->toStrings()) . '.';
62    }
63}

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    }