Issues (6)

src/Kernel.php (4 issues)

1
<?php
2
3
/*
4
 *  This file is part of the Micro framework package.
5
 *
6
 *  (c) Stanislau Komar <[email protected]>
7
 *
8
 *  For the full copyright and license information, please view the LICENSE
9
 *  file that was distributed with this source code.
10
 */
11
12
namespace Micro\Framework\Kernel;
13
14
use Micro\Component\DependencyInjection\Autowire\AutowireHelperFactory;
15
use Micro\Component\DependencyInjection\Autowire\AutowireHelperFactoryInterface;
16
use Micro\Component\DependencyInjection\ContainerCompiled;
17
use Micro\Component\DependencyInjection\ContainerInterface;
18
use Micro\Component\DependencyInjection\Proxy\ProxyBuilder;
19
use Micro\Component\DependencyInjection\Proxy\ProxyBuilderInterface;
20
use Micro\Component\DependencyInjection\Proxy\ProxyBuilderProductionDecorator;
0 ignored issues
show
The type Micro\Component\Dependen...lderProductionDecorator 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...
21
use Micro\Component\DependencyInjection\Proxy\ProxyClassContentFactoryInterface;
22
use Micro\Component\DependencyInjection\Proxy\ProxyClassNameGenerator;
23
use Micro\Component\DependencyInjection\Proxy\ProxyClassNameGeneratorInterface;
24
use Micro\Component\DependencyInjection\Proxy\ProxyFactory;
25
use Micro\Component\DependencyInjection\Proxy\ProxyFileManager;
26
use Micro\Component\DependencyInjection\Proxy\ProxyFileManagerInterface;
27
use Micro\Framework\Kernel\Plugin\PluginBootLoaderInterface;
28
29
/**
30
 * @psalm-suppress ClassMustBeFinal
31
 */
32
class Kernel implements KernelInterface
33
{
34
    private bool $isStarted;
35
36
    /**
37
     * @var object[]
38
     */
39
    private array $plugins;
40 7
41
    /**
42 7
     * @var class-string[]
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string[] at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string[].
Loading history...
43 7
     */
44
    private array $pluginsLoaded;
45
46
    private ContainerCompiled $container;
47
48 4
    /**
49 1
     * @param class-string[]              $applicationPluginCollection
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string[] at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string[].
Loading history...
50
     * @param PluginBootLoaderInterface[] $pluginBootLoaderCollection
51
     *
52 4
     * @psalm-suppress PossiblyUnusedMethod
53
     */
54 4
    public function __construct(
55
        private readonly array $applicationPluginCollection,
56
        private array $pluginBootLoaderCollection,
57
        private readonly AppModeEnum $mode,
58
        private readonly string $proxyNamespace = 'Micro\Proxy',
59 4
        private readonly string $proxyFileDestination = 'var/proxy/micro_proxy.php',
60
    ) {
61 4
        $this->isStarted = false;
62 4
63
        $this->pluginsLoaded = [];
64
        $this->plugins = [];
65 4
        $this->container = $this->createDefaultContainer();
66
    }
67
68
    #[\Override]
69
    public function getMode(): AppModeEnum
70
    {
71
        return $this->mode;
72
    }
73 5
74 1
    #[\Override]
75
    public function addBootLoader(PluginBootLoaderInterface $bootLoader): self
76
    {
77 5
        if ($this->isStarted) {
78 5
            throw new \LogicException('Bootloaders must be installed before starting the kernel.');
79
        }
80
81
        $this->pluginBootLoaderCollection[] = $bootLoader;
82
83
        return $this;
84
    }
85
86 2
    #[\Override]
87
    public function setBootLoaders(iterable $bootLoaders): self
88
    {
89
        $this->pluginBootLoaderCollection = [];
90
91
        foreach ($bootLoaders as $loader) {
92
            $this->addBootLoader($loader);
93
        }
94 5
95 4
        return $this;
96
    }
97
98 5
    #[\Override]
99
    public function run(): void
100 5
    {
101 5
        if ($this->isStarted) {
102
            return;
103
        }
104 5
105 5
        $this->loadPlugins();
106
        $this->container->compile();
107
        $this->initializePlugins();
108
        $this->isStarted = true;
109
    }
110
111
    #[\Override]
112
    public function container(): ContainerInterface
113 1
    {
114 1
        return $this->container;
115 1
    }
116
117
    #[\Override]
118
    public function loadPlugin(string $applicationPluginClass): void
119
    {
120
        if (\in_array($applicationPluginClass, $this->pluginsLoaded, true)) {
121
            return;
122 5
        }
123 5
        $autowireHelper = $this->autowireHelperFactory()->create();
124
        $this->container->register($applicationPluginClass, $autowireHelper->autowire($applicationPluginClass));
125
        $this->pluginsLoaded[] = $applicationPluginClass;
126
    }
127
128
    protected function initializePlugins(): void
129
    {
130
        foreach ($this->pluginsLoaded as $pluginClass) {
131
            $this->initializePlugin($pluginClass);
132
        }
133
    }
134
135
    /**
136
     * @param class-string $pluginClass
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
137
     */
138
    protected function initializePlugin(string $pluginClass): void
139
    {
140
        $plugin = $this->container->get($pluginClass);
141
        foreach ($this->pluginBootLoaderCollection as $bootLoader) {
142
            $bootLoader->boot($plugin);
143
        }
144
145
        $this->plugins[] = $plugin;
146
    }
147
148
    #[\Override]
149
    public function plugins(?string $interfaceInherited = null): \Traversable
150
    {
151
        foreach ($this->plugins as $plugin) {
152
            if (null === $interfaceInherited || ($plugin instanceof $interfaceInherited)) {
153
                yield $plugin;
154
            }
155
        }
156
    }
157
158
    protected function loadPlugins(): void
159
    {
160
        foreach ($this->applicationPluginCollection as $applicationPlugin) {
161
            $this->loadPlugin($applicationPlugin);
162
        }
163
    }
164
165
    /**
166
     * @psalm-suppress PossiblyUnusedMethod
167
     */
168
    public function getContainer(): ContainerInterface
169
    {
170
        return $this->container;
171
    }
172
173
    private function createDefaultContainer(): ContainerCompiled
174
    {
175
        $proxyClassNameGenerator = $this->createProxyClassNameGenerator();
176
        $proxyFileManager = $this->createProxyFileManager();
177
        $proxyClassContentFactory = $this->createProxyClassContentFactory();
178
        $classProxyBuilder = $this->createClassProxyBuilder($proxyClassContentFactory, $proxyFileManager);
179
180
        return new ContainerCompiled(
181
            $proxyClassNameGenerator,
182
            $classProxyBuilder
183
        );
184
    }
185
186
    private function createClassProxyBuilder(
187
        ProxyClassContentFactoryInterface $classContentFactory,
188
        ProxyFileManagerInterface $proxyFileManager,
189
    ): ProxyBuilderInterface {
190
        $proxyBuilder = new ProxyBuilder(
191
            $classContentFactory,
192
            $proxyFileManager,
193
            $this->proxyNamespace,
194
        );
195
196
        if (!$this->mode->isProd()) {
197
            return $proxyBuilder;
198
        }
199
200
        return new ProxyBuilderProductionDecorator(
201
            $proxyBuilder,
202
            $proxyFileManager,
203
        );
204
    }
205
206
    private function autowireHelperFactory(): AutowireHelperFactoryInterface
207
    {
208
        return new AutowireHelperFactory(
209
            $this->container,
210
        );
211
    }
212
213
    private function createProxyClassNameGenerator(): ProxyClassNameGeneratorInterface
214
    {
215
        return new ProxyClassNameGenerator(
216
            $this->proxyNamespace
217
        );
218
    }
219
220
    private function createProxyClassContentFactory(): ProxyClassContentFactoryInterface
221
    {
222
        return new ProxyFactory(
223
            $this->createProxyClassNameGenerator()
224
        );
225
    }
226
227
    private function createProxyFileManager(): ProxyFileManagerInterface
228
    {
229
        return new ProxyFileManager(
230
            $this->proxyFileDestination,
231
        );
232
    }
233
}
234