Test Failed
Pull Request — master (#1149)
by Aleksei
21:24
created

DebugBootloader::state()   C

Complexity

Conditions 13
Paths 41

Size

Total Lines 54
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 14.2244

Importance

Changes 0
Metric Value
eloc 30
c 0
b 0
f 0
dl 0
loc 54
ccs 25
cts 31
cp 0.8065
rs 6.6166
cc 13
nc 41
nop 2
crap 14.2244

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Spiral\Bootloader;
6
7
use Spiral\Boot\Bootloader\Bootloader;
8
use Spiral\Config\ConfiguratorInterface;
9
use Spiral\Config\Patch\Append;
10
use Spiral\Core\Attribute\Proxy;
11
use Spiral\Core\Attribute\Singleton;
12
use Spiral\Core\Container\Autowire;
13
use Spiral\Core\FactoryInterface;
14
use Spiral\Core\InvokerInterface;
15
use Spiral\Debug\Config\DebugConfig;
16
use Spiral\Debug\Exception\StateException;
17
use Spiral\Debug\State;
18
use Spiral\Debug\StateCollector\EnvironmentCollector;
19
use Spiral\Debug\StateCollectorInterface;
20
use Spiral\Debug\StateInterface;
21
22
/**
23
 * @psalm-import-type TCollector from DebugConfig
24
 * @psalm-import-type TTag from DebugConfig
25
 */
26
#[Singleton]
27
final class DebugBootloader extends Bootloader
28
{
29
    protected const SINGLETONS = [
30
        EnvironmentCollector::class => EnvironmentCollector::class,
31
    ];
32
33
    protected const BINDINGS = [
34
        StateInterface::class => [self::class, 'state'],
35
    ];
36 357
37
    public function __construct(
38
        private readonly InvokerInterface $invoker,
39
        private readonly ConfiguratorInterface $config,
40
    ) {
41 357
    }
42
43
    /**
44
     * Boot default state collector.
45
     */
46 357
    public function init(): void
47
    {
48 357
        $this->initDefaultConfig();
49 357
        $this->addStateCollector(EnvironmentCollector::class);
50
    }
51
52
    /**
53
     * @param non-empty-string $key
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
54
     * @param TTag $value
55
     */
56 1
    public function addTag(string $key, string|\Stringable|\Closure $value): void
57
    {
58 1
        $this->config->modify(DebugConfig::CONFIG, new Append('tags', $key, $value));
59
    }
60
61
    /**
62
     * @psalm-param TCollector $collector
63
     */
64 357
    public function addStateCollector(string|StateCollectorInterface|Autowire $collector): void
65
    {
66 357
        $this->config->modify(DebugConfig::CONFIG, new Append('collectors', null, $collector));
67
    }
68
69
    /**
70
     * Create state and populate it with collectors.
71
     */
72 5
    private function state(
73
        #[Proxy] FactoryInterface $factory,
74 5
        DebugConfig $config,
75
    ): StateInterface {
76 5
        $state = new State();
77 3
78 1
        foreach ($config->getTags() as $key => $value) {
79
            if ($value instanceof \Closure) {
80
                $value = $this->invoker->invoke($value);
81 3
            }
82 1
83 1
            if (!\is_string($value) && !$value instanceof \Stringable) {
84 1
                throw new StateException(
85 1
                    \sprintf(
86
                        'Invalid tag value, `string` expected got `%s`',
87
                        \is_object($value) ? $value::class : \gettype($value),
88 2
                    ),
89
                );
90
            }
91 4
92 3
            $state->setTag((string)$key, (string)$value);
93 3
        }
94 2
95 2
        $errors = [];
96 3
97
        foreach ($config->getCollectors() as $collector) {
98 3
            try {
99
                $collector = match (true) {
100
                    \is_string($collector) => $factory->make($collector),
101
                    $collector instanceof Autowire => $collector->resolve($factory),
102
                    default => $collector,
103
                };
104
            } catch (\Throwable) {
105
                $errors[] = \is_string($collector) || $collector instanceof \Stringable
106
                    ? (string) $collector
107 3
                    : \get_debug_type($collector);
108
                continue;
109
            }
110 4
111
            if (!$collector instanceof StateCollectorInterface) {
112
                throw new StateException(
113 357
                    \sprintf(
114
                        'Unable to populate state, invalid state collector %s',
115 357
                        \is_object($collector) ? $collector::class : \gettype($collector),
116 357
                    ),
117 357
                );
118 357
            }
119
120
            $collector->populate($state);
121
        }
122
123
        $errors === [] or $state->setTags(['unresolved-collectors' => \implode(', ', $errors)]);
124
125
        return $state;
126
    }
127
128
    private function initDefaultConfig(): void
129
    {
130
        $this->config->setDefaults(DebugConfig::CONFIG, [
131
            'collectors' => [],
132
            'tags' => [],
133
        ]);
134
    }
135
}
136