Valkyrja::setEnv()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
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 Override;
0 ignored issues
show
Bug introduced by
The type Override 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
    #[Override]
70
    public function setup(Env $env, Config|Data $configData = new Config(), bool $force = false): void
71
    {
72
        // If the application was already setup, no need to do it again
73
        if ($this->setup && ! $force) {
74
            return;
75
        }
76
77
        // Avoid re-setting up the app later
78
        $this->setup = true;
79
80
        $this->setEnv(env: $env);
81
82
        $this->bootstrapContainer();
83
84
        if ($configData instanceof Config) {
85
            $this->bootstrapConfig(config: $configData);
86
        } else {
87
            $this->bootstrapData(data: $configData);
88
        }
89
90
        $this->bootstrapServices();
91
    }
92
93
    /**
94
     * @inheritDoc
95
     */
96
    #[Override]
97
    public function addComponent(string $component): void
98
    {
99
        if ($this->config === null) {
100
            throw new RuntimeException('Cannot add components to an app setup with Data');
101
        }
102
103
        $config = $this->config;
104
105
        $this->addComponentContainerAliases($config, $component);
106
        $this->addComponentContainerServices($config, $component);
107
        $this->addComponentContainerProviders($component);
108
        $this->addComponentEventListeners($config, $component);
109
        $this->addComponentCliControllers($config, $component);
110
        $this->addComponentHttpControllers($config, $component);
111
    }
112
113
    /**
114
     * @inheritDoc
115
     *
116
     * @return Env
117
     */
118
    #[Override]
119
    public function getEnv(): Env
120
    {
121
        return $this->env;
122
    }
123
124
    /**
125
     * @inheritDoc
126
     */
127
    #[Override]
128
    public function setEnv(Env $env): void
129
    {
130
        // Set the env class to use
131
        $this->env = $env;
132
133
        $this->bootstrapTimezone();
134
    }
135
136
    /**
137
     * @inheritDoc
138
     */
139
    #[Override]
140
    public function getContainer(): Container
141
    {
142
        return $this->container;
143
    }
144
145
    /**
146
     * @inheritDoc
147
     */
148
    #[Override]
149
    public function setContainer(Container $container): static
150
    {
151
        $this->container = $container;
152
153
        return $this;
154
    }
155
156
    /**
157
     * @inheritDoc
158
     */
159
    #[Override]
160
    public function getDebugMode(): bool
161
    {
162
        /** @var bool $debugMode */
163
        $debugMode = $this->env::APP_DEBUG_MODE;
164
165
        return $debugMode;
166
    }
167
168
    /**
169
     * @inheritDoc
170
     */
171
    #[Override]
172
    public function getEnvironment(): string
173
    {
174
        /** @var non-empty-string $env */
175
        $env = $this->env::APP_ENV;
176
177
        return $env;
178
    }
179
180
    /**
181
     * @inheritDoc
182
     */
183
    #[Override]
184
    public function getVersion(): string
185
    {
186
        /** @var non-empty-string $version */
187
        $version = $this->env::APP_VERSION;
188
189
        return $version;
190
    }
191
192
    /**
193
     * Bootstrap the config.
194
     */
195
    protected function bootstrapConfig(Config $config): void
196
    {
197
        $this->config = $config;
198
199
        $this->bootstrapComponents();
200
    }
201
202
    /**
203
     * Bootstrap all the components types for the application.
204
     */
205
    protected function bootstrapComponents(): void
206
    {
207
        $this->bootstrapRequiredComponents();
208
        $this->bootstrapCoreComponents();
209
        $this->bootstrapOptionalComponents();
210
        $this->bootstrapCustomComponents();
211
    }
212
213
    /**
214
     * Bootstrap all the required components for the application to run.
215
     */
216
    protected function bootstrapRequiredComponents(): void
217
    {
218
        /** @var class-string<Component>[] $components */
219
        $components = $this->env::APP_REQUIRED_COMPONENTS;
220
221
        foreach ($components as $component) {
222
            $this->addComponent(component: $component);
223
        }
224
    }
225
226
    /**
227
     * Bootstrap all the core components to run specific parts of the application.
228
     */
229
    protected function bootstrapCoreComponents(): void
230
    {
231
        /** @var class-string<Component>[] $components */
232
        $components = $this->env::APP_CORE_COMPONENTS;
233
234
        foreach ($components as $component) {
235
            $this->addComponent(component: $component);
236
        }
237
    }
238
239
    /**
240
     * Bootstrap all the optional components.
241
     */
242
    protected function bootstrapOptionalComponents(): void
243
    {
244
        /** @var class-string<Component>[] $components */
245
        $components = $this->env::APP_COMPONENTS;
246
247
        foreach ($components as $component) {
248
            $this->addComponent(component: $component);
249
        }
250
    }
251
252
    /**
253
     * Bootstrap all the custom components.
254
     */
255
    protected function bootstrapCustomComponents(): void
256
    {
257
        /** @var class-string<Component>[] $components */
258
        $components = $this->env::APP_CUSTOM_COMPONENTS;
259
260
        foreach ($components as $component) {
261
            $this->addComponent(component: $component);
262
        }
263
    }
264
265
    /**
266
     * Add a component's container aliases.
267
     *
268
     * @param class-string<Component> $component The component class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<Component> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<Component>.
Loading history...
269
     */
270
    protected function addComponentContainerAliases(Config $config, string $component): void
271
    {
272
        $config->aliases = [
273
            ...$config->aliases,
274
            ...$component::getContainerAliases(),
275
        ];
276
    }
277
278
    /**
279
     * Add a component's container services.
280
     *
281
     * @param class-string<Component> $component The component class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<Component> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<Component>.
Loading history...
282
     */
283
    protected function addComponentContainerServices(Config $config, string $component): void
284
    {
285
        $config->services = [
286
            ...$config->services,
287
            ...$component::getContainerServices(),
288
        ];
289
    }
290
291
    /**
292
     * Add a component's container services.
293
     *
294
     * @param class-string<Component> $component The component class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<Component> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<Component>.
Loading history...
295
     */
296
    protected function addComponentContainerProviders(string $component): void
297
    {
298
        array_map(
299
            [$this->container, 'register'],
300
            $component::getContainerProviders(),
301
        );
302
    }
303
304
    /**
305
     * Add a component's event listeners.
306
     *
307
     * @param class-string<Component> $component The component class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<Component> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<Component>.
Loading history...
308
     */
309
    protected function addComponentEventListeners(Config $config, string $component): void
310
    {
311
        if ($this->env::APP_ADD_EVENT_LISTENERS) {
312
            $config->listeners = [
313
                ...$config->listeners,
314
                ...$component::getEventListeners(),
315
            ];
316
        }
317
    }
318
319
    /**
320
     * Add a component's cli controllers.
321
     *
322
     * @param class-string<Component> $component The component class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<Component> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<Component>.
Loading history...
323
     */
324
    protected function addComponentCliControllers(Config $config, string $component): void
325
    {
326
        if ($this->env::APP_ADD_CLI_CONTROLLERS) {
327
            $config->commands = [
328
                ...$config->commands,
329
                ...$component::getCliControllers(),
330
            ];
331
        }
332
    }
333
334
    /**
335
     * Add a component's http controllers.
336
     *
337
     * @param class-string<Component> $component The component class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<Component> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<Component>.
Loading history...
338
     */
339
    protected function addComponentHttpControllers(Config $config, string $component): void
340
    {
341
        if ($this->env::APP_ADD_HTTP_CONTROLLERS) {
342
            $config->controllers = [
343
                ...$config->controllers,
344
                ...$component::getHttpControllers(),
345
            ];
346
        }
347
    }
348
349
    /**
350
     * Bootstrap the data.
351
     */
352
    protected function bootstrapData(Data $data): void
353
    {
354
        $this->data = $data;
355
    }
356
357
    /**
358
     * Create the container.
359
     */
360
    protected function bootstrapContainer(): void
361
    {
362
        $container = new \Valkyrja\Container\Container();
363
364
        $this->setContainer($container);
365
    }
366
367
    /**
368
     * Bootstrap container services.
369
     */
370
    protected function bootstrapServices(): void
371
    {
372
        $container = $this->container;
373
374
        $container->setSingleton(Application::class, $this);
375
        $container->setSingleton(Env::class, $this->env);
376
        $container->setSingleton(Container::class, $container);
377
378
        if ($this->data !== null) {
379
            $container->setSingleton(ContainerData::class, $this->data->container);
380
            $container->setSingleton(EventData::class, $this->data->event);
381
            $container->setSingleton(CliData::class, $this->data->cli);
382
            $container->setSingleton(HttpData::class, $this->data->http);
383
384
            $container->setFromData($this->data->container);
385
        }
386
387
        if ($this->config !== null) {
388
            $container->setSingleton(Config::class, $this->config);
389
390
            $data = $container->getSingleton(ContainerData::class);
391
            $container->setFromData($data);
392
        }
393
    }
394
395
    /**
396
     * Bootstrap the timezone.
397
     */
398
    protected function bootstrapTimezone(): void
399
    {
400
        /** @var non-empty-string $timezone */
401
        $timezone = $this->env::APP_TIMEZONE;
402
403
        date_default_timezone_set($timezone);
404
    }
405
}
406