Passed
Push — master ( 8d0b59...1902d4 )
by Melech
09:45 queued 05:35
created

Valkyrja::bootstrapServices()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 14
dl 0
loc 22
rs 9.7998
c 0
b 0
f 0
cc 3
nc 4
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Valkyrja Framework package.
7
 *
8
 * (c) Melech Mizrachi <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Valkyrja\Application;
15
16
use Valkyrja\Application\Constant\ComponentClass;
0 ignored issues
show
Bug introduced by
The type Valkyrja\Application\Constant\ComponentClass 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...
17
use Valkyrja\Application\Contract\Application;
0 ignored issues
show
Bug introduced by
The type Valkyrja\Application\Contract\Application 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...
18
use Valkyrja\Application\Exception\RuntimeException;
19
use Valkyrja\Application\Support\Component;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Valkyrja\Application\Component. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
20
use Valkyrja\Cli\Routing\Data as CliData;
21
use Valkyrja\Container\Contract\Container;
22
use Valkyrja\Container\Data as ContainerData;
23
use Valkyrja\Event\Data as EventData;
24
use Valkyrja\Http\Routing\Data as HttpData;
25
26
/**
27
 * Class Valkyrja.
28
 *
29
 * @author Melech Mizrachi
30
 */
31
class Valkyrja implements Application
32
{
33
    /**
34
     * Application env.
35
     */
36
    protected Env $env;
0 ignored issues
show
Bug introduced by
The type Valkyrja\Application\Env 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...
37
38
    /**
39
     * Application config.
40
     */
41
    protected Config|null $config = null;
42
43
    /**
44
     * Application data.
45
     */
46
    protected Data|null $data = null;
47
48
    /**
49
     * Get the instance of the container.
50
     */
51
    protected Container $container;
52
53
    /**
54
     * Whether the application was setup.
55
     */
56
    protected bool $setup = false;
57
58
    /**
59
     * Application constructor.
60
     */
61
    public function __construct(Env $env, Config|Data $configData = new Config())
62
    {
63
        $this->setup(env: $env, configData: $configData);
64
    }
65
66
    /**
67
     * @inheritDoc
68
     */
69
    public function setup(Env $env, Config|Data $configData = new Config(), bool $force = false): void
70
    {
71
        // If the application was already setup, no need to do it again
72
        if ($this->setup && ! $force) {
73
            return;
74
        }
75
76
        // Avoid re-setting up the app later
77
        $this->setup = true;
78
79
        $this->setEnv(env: $env);
80
81
        $this->bootstrapContainer();
82
83
        if ($configData instanceof Config) {
84
            $this->bootstrapConfig(config: $configData);
85
        } else {
86
            $this->bootstrapData(data: $configData);
87
        }
88
89
        $this->bootstrapServices();
90
        $this->bootstrapTimezone();
91
    }
92
93
    /**
94
     * @inheritDoc
95
     */
96
    public function addComponent(string $component): void
97
    {
98
        if ($this->config === null) {
99
            throw new RuntimeException('Cannot add components to an app setup with Data');
100
        }
101
102
        $this->config->aliases = [
103
            ...$this->config->aliases,
104
            ...$component::getContainerAliases(),
105
        ];
106
107
        $this->config->services = [
108
            ...$this->config->services,
109
            ...$component::getContainerServices(),
110
        ];
111
112
        array_map(
113
            [$this->container, 'register'],
114
            $component::getContainerProviders(),
115
        );
116
117
        $this->config->listeners = [
118
            ...$this->config->listeners,
119
            ...$component::getEventListeners(),
120
        ];
121
122
        $this->config->commands = [
123
            ...$this->config->commands,
124
            ...$component::getCliControllers(),
125
        ];
126
127
        $this->config->controllers = [
128
            ...$this->config->controllers,
129
            ...$component::getHttpControllers(),
130
        ];
131
    }
132
133
    /**
134
     * @inheritDoc
135
     *
136
     * @return Env
137
     */
138
    public function getEnv(): Env
139
    {
140
        return $this->env;
141
    }
142
143
    /**
144
     * @inheritDoc
145
     */
146
    public function setEnv(Env $env): void
147
    {
148
        // Set the env class to use
149
        $this->env = $env;
150
    }
151
152
    /**
153
     * @inheritDoc
154
     */
155
    public function getContainer(): Container
156
    {
157
        return $this->container;
158
    }
159
160
    /**
161
     * @inheritDoc
162
     */
163
    public function setContainer(Container $container): static
164
    {
165
        $this->container = $container;
166
167
        return $this;
168
    }
169
170
    /**
171
     * @inheritDoc
172
     */
173
    public function getDebugMode(): bool
174
    {
175
        /** @var bool $debugMode */
176
        $debugMode = $this->env::APP_DEBUG_MODE;
177
178
        return $debugMode;
179
    }
180
181
    /**
182
     * @inheritDoc
183
     */
184
    public function getEnvironment(): string
185
    {
186
        /** @var non-empty-string $env */
187
        $env = $this->env::APP_ENV;
188
189
        return $env;
190
    }
191
192
    /**
193
     * @inheritDoc
194
     */
195
    public function getVersion(): string
196
    {
197
        /** @var non-empty-string $version */
198
        $version = $this->env::APP_VERSION;
199
200
        return $version;
201
    }
202
203
    /**
204
     * Bootstrap the config.
205
     */
206
    protected function bootstrapConfig(Config $config): void
207
    {
208
        $this->config = $config;
209
210
        $this->bootstrapComponents();
211
    }
212
213
    /**
214
     * Bootstrap all the components set in the config.
215
     */
216
    protected function bootstrapComponents(): void
217
    {
218
        // All all the components
219
        $this->addComponent(component: ComponentClass::CONTAINER);
220
        $this->addComponent(component: ComponentClass::APPLICATION);
221
        $this->addComponent(component: ComponentClass::ATTRIBUTE);
222
        $this->addComponent(component: ComponentClass::CLI);
223
        $this->addComponent(component: ComponentClass::DISPATCHER);
224
        $this->addComponent(component: ComponentClass::EVENT);
225
        $this->addComponent(component: ComponentClass::HTTP);
226
        $this->addComponent(component: ComponentClass::REFLECTION);
227
228
        /** @var class-string<Component>[] $components */
229
        $components = $this->env::APP_COMPONENTS;
230
231
        foreach ($components as $component) {
232
            $this->addComponent($component);
233
        }
234
    }
235
236
    /**
237
     * Bootstrap the data.
238
     */
239
    protected function bootstrapData(Data $data): void
240
    {
241
        $this->data = $data;
242
    }
243
244
    /**
245
     * Create the container.
246
     */
247
    protected function bootstrapContainer(): void
248
    {
249
        $container = new \Valkyrja\Container\Container();
250
251
        $this->setContainer($container);
252
    }
253
254
    /**
255
     * Bootstrap container services.
256
     */
257
    protected function bootstrapServices(): void
258
    {
259
        $container = $this->container;
260
261
        $container->setSingleton(Application::class, $this);
262
        $container->setSingleton(Env::class, $this->env);
263
        $container->setSingleton(Container::class, $container);
264
265
        if ($this->data !== null) {
266
            $container->setSingleton(ContainerData::class, $this->data->container);
267
            $container->setSingleton(EventData::class, $this->data->event);
268
            $container->setSingleton(CliData::class, $this->data->cli);
269
            $container->setSingleton(HttpData::class, $this->data->http);
270
271
            $container->setFromData($this->data->container);
272
        }
273
274
        if ($this->config !== null) {
275
            $container->setSingleton(Config::class, $this->config);
276
277
            $data = $container->getSingleton(ContainerData::class);
278
            $container->setFromData($data);
279
        }
280
    }
281
282
    /**
283
     * Bootstrap the timezone.
284
     */
285
    protected function bootstrapTimezone(): void
286
    {
287
        /** @var non-empty-string $timezone */
288
        $timezone = $this->env::APP_TIMEZONE;
289
290
        date_default_timezone_set($timezone);
291
    }
292
}
293