Passed
Pull Request — master (#1095)
by Aleksei
13:52 queued 04:04
created

EventsBootloader::boot()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 26
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 26
ccs 12
cts 12
cp 1
rs 9.6111
c 0
b 0
f 0
cc 5
nc 8
nop 7
crap 5
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Spiral\Events\Bootloader;
6
7
use Psr\Container\ContainerExceptionInterface;
8
use Psr\Container\ContainerInterface;
9
use Psr\EventDispatcher\EventDispatcherInterface;
10
use Spiral\Boot\AbstractKernel;
11
use Spiral\Boot\Bootloader\Bootloader;
12
use Spiral\Boot\FinalizerInterface;
13
use Spiral\Bootloader\Attributes\AttributesBootloader;
14
use Spiral\Config\ConfiguratorInterface;
15
use Spiral\Config\Patch\Append;
16
use Spiral\Core\Container;
17
use Spiral\Core\Container\Autowire;
18
use Spiral\Core\CoreInterceptorInterface;
19
use Spiral\Core\FactoryInterface;
20
use Spiral\Core\InterceptorPipeline;
21
use Spiral\Events\AutowireListenerFactory;
22
use Spiral\Events\Config\EventsConfig;
23
use Spiral\Events\EventDispatcher;
24
use Spiral\Events\EventDispatcherAwareInterface;
25
use Spiral\Events\Interceptor\Core;
26
use Spiral\Events\ListenerFactoryInterface;
27
use Spiral\Events\ListenerProcessorRegistry;
28
use Spiral\Events\Processor\AttributeProcessor;
29
use Spiral\Events\Processor\ConfigProcessor;
30
use Spiral\Events\Processor\ProcessorInterface;
31
use Spiral\Interceptors\InterceptorInterface;
32
use Spiral\Tokenizer\Bootloader\TokenizerListenerBootloader;
33
34
/**
35
 * @psalm-import-type TInterceptor from EventsConfig
36
 */
37
final class EventsBootloader extends Bootloader
38
{
39
    protected const DEPENDENCIES = [
40
        TokenizerListenerBootloader::class,
41
        AttributesBootloader::class,
42
    ];
43
44
    protected const SINGLETONS = [
45
        ListenerFactoryInterface::class => AutowireListenerFactory::class,
46
        ListenerProcessorRegistry::class => ListenerProcessorRegistry::class,
47
    ];
48
49 320
    public function __construct(
50
        private readonly ConfiguratorInterface $configs
51
    ) {
52 320
    }
53
54 320
    public function init(): void
55
    {
56 320
        $this->configs->setDefaults(EventsConfig::CONFIG, [
57 320
            'listeners' => [],
58 320
            'processors' => [
59 320
                AttributeProcessor::class,
60 320
                ConfigProcessor::class,
61 320
            ],
62 320
            'interceptors' => [],
63 320
        ]);
64
    }
65
66 320
    public function boot(
67
        Container $container,
68
        FactoryInterface $factory,
69
        EventsConfig $config,
70
        AbstractKernel $kernel,
71
        ListenerProcessorRegistry $registry,
72
        FinalizerInterface $finalizer,
73
        ?EventDispatcherInterface $eventDispatcher = null
74
    ): void {
75 320
        if ($eventDispatcher !== null) {
76 6
            $this->initEventDispatcher(new Core($eventDispatcher), $config, $container, $factory);
77
        }
78
79 320
        foreach ($config->getProcessors() as $processor) {
80 320
            $processor = $this->autowire($processor, $container, $factory);
81
82 320
            \assert($processor instanceof ProcessorInterface);
83 320
            $registry->addProcessor($processor);
84
        }
85
86 320
        $kernel->bootstrapped(static function () use ($registry): void {
87 320
            $registry->process();
88 320
        });
89
90 320
        if ($finalizer instanceof EventDispatcherAwareInterface && $eventDispatcher !== null) {
91 2
            $finalizer->setEventDispatcher($eventDispatcher);
92
        }
93
    }
94
95
    /**
96
     * @param TInterceptor $interceptor
0 ignored issues
show
Bug introduced by
The type Spiral\Events\Bootloader\TInterceptor was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
97
     */
98 1
    public function addInterceptor(string|CoreInterceptorInterface|Container\Autowire $interceptor): void
99
    {
100 1
        $this->configs->modify(EventsConfig::CONFIG, new Append('interceptors', null, $interceptor));
101
    }
102
103 6
    private function initEventDispatcher(
104
        Core $core,
105
        EventsConfig $config,
106
        Container $container,
107
        FactoryInterface $factory
108
    ): void {
109 6
        $pipeline = (new InterceptorPipeline())->withCore($core);
0 ignored issues
show
Deprecated Code introduced by
The class Spiral\Core\InterceptorPipeline has been deprecated: use {@see \Spiral\Interceptors\Handler\InterceptorPipeline} instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

109
        $pipeline = (/** @scrutinizer ignore-deprecated */ new InterceptorPipeline())->withCore($core);
Loading history...
110
111 6
        foreach ($config->getInterceptors() as $interceptor) {
112
            $interceptor = $this->autowire($interceptor, $container, $factory);
113
114
            \assert($interceptor instanceof CoreInterceptorInterface || $interceptor instanceof InterceptorInterface);
115
            $pipeline->addInterceptor($interceptor);
116
        }
117
118 6
        $container->removeBinding(EventDispatcherInterface::class);
119 6
        $container->bindSingleton(EventDispatcherInterface::class, new EventDispatcher($pipeline));
120
    }
121
122
    /**
123
     * @template T
124
     *
125
     * @param class-string<T>|Autowire<T>|T $id
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T>|Autowire<T>|T at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>|Autowire<T>|T.
Loading history...
126
     *
127
     * @return T
128
     *
129
     * @throws ContainerExceptionInterface
130
     */
131 320
    private function autowire(string|object $id, ContainerInterface $container, FactoryInterface $factory): object
132
    {
133 320
        return match (true) {
134 320
            \is_string($id) => $container->get($id),
0 ignored issues
show
Bug introduced by
It seems like $id can also be of type object; however, parameter $id of Psr\Container\ContainerInterface::get() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

134
            \is_string($id) => $container->get(/** @scrutinizer ignore-type */ $id),
Loading history...
135 320
            $id instanceof Autowire => $id->resolve($factory),
136 320
            default => $id,
137 320
        };
138
    }
139
}
140