Passed
Push — master ( 24c04a...5c4bac )
by butschster
15:41 queued 05:00
created

DebugBootloader::initDefaultConfig()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
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\Container\Autowire;
11
use Spiral\Core\Container\SingletonInterface;
12
use Spiral\Core\FactoryInterface;
13
use Spiral\Core\InvokerInterface;
14
use Spiral\Debug\Config\DebugConfig;
15
use Spiral\Debug\Exception\StateException;
16
use Spiral\Debug\State;
17
use Spiral\Debug\StateCollector\EnvironmentCollector;
18
use Spiral\Debug\StateCollectorInterface;
19
use Spiral\Debug\StateInterface;
20
21
/**
22
 * @psalm-import-type TCollector from DebugConfig
23
 * @psalm-import-type TTag from DebugConfig
24
 */
25
final class DebugBootloader extends Bootloader implements SingletonInterface
26
{
27
    protected const SINGLETONS = [
28
        EnvironmentCollector::class => EnvironmentCollector::class,
29
    ];
30
31
    protected const BINDINGS = [
32
        StateInterface::class => [self::class, 'state'],
33
    ];
34
35 318
    public function __construct(
36
        private readonly FactoryInterface $factory,
37
        private readonly InvokerInterface $invoker,
38
        private readonly ConfiguratorInterface $config,
39
    ) {
40 318
    }
41
42
    /**
43
     * Boot default state collector.
44
     */
45 318
    public function init(): void
46
    {
47 318
        $this->initDefaultConfig();
48 318
        $this->addStateCollector(EnvironmentCollector::class);
49
    }
50
51
    /**
52
     * @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...
53
     * @param TTag $value
54
     */
55 1
    public function addTag(string $key, string|\Stringable|\Closure $value): void
56
    {
57 1
        $this->config->modify(DebugConfig::CONFIG, new Append('tags', $key, $value));
58
    }
59
60
    /**
61
     * @psalm-param TCollector $collector
62
     */
63 318
    public function addStateCollector(string|StateCollectorInterface|Autowire $collector): void
64
    {
65 318
        $this->config->modify(DebugConfig::CONFIG, new Append('collectors', null, $collector));
66
    }
67
68
    /**
69
     * Create state and populate it with collectors.
70
     */
71 5
    private function state(DebugConfig $config): StateInterface
72
    {
73 5
        $state = new State();
74
75 5
        foreach ($config->getTags() as $key => $value) {
76 3
            if ($value instanceof \Closure) {
77 1
                $value = $this->invoker->invoke($value);
78
            }
79
80 3
            if (!\is_string($value) && !$value instanceof \Stringable) {
81 1
                throw new StateException(\sprintf(
82 1
                    'Invalid tag value, `string` expected got `%s`',
83 1
                    \is_object($value) ? $value::class : \gettype($value)
84 1
                ));
85
            }
86
87 2
            $state->setTag((string) $key, (string) $value);
88
        }
89
90 4
        foreach ($config->getCollectors() as $collector) {
91 3
            $collector = match (true) {
92 3
                \is_string($collector) => $this->factory->make($collector),
93 3
                $collector instanceof Autowire => $collector->resolve($this->factory),
94 3
                default => $collector,
95 3
            };
96
97 3
            if (!$collector instanceof StateCollectorInterface) {
98
                throw new StateException(
99
                    \sprintf(
100
                        'Unable to populate state, invalid state collector %s',
101
                        \is_object($collector) ? $collector::class : \gettype($collector)
102
                    )
103
                );
104
            }
105
106 3
            $collector->populate($state);
107
        }
108
109 4
        return $state;
110
    }
111
112 318
    private function initDefaultConfig(): void
113
    {
114 318
        $this->config->setDefaults(DebugConfig::CONFIG, [
115 318
            'collectors' => [],
116 318
            'tags' => [],
117 318
        ]);
118
    }
119
}
120