Kernel   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 130
Duplicated Lines 0 %

Importance

Changes 15
Bugs 1 Features 1
Metric Value
eloc 78
c 15
b 1
f 1
dl 0
loc 130
rs 10
wmc 18

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
A __destruct() 0 8 4
A ensureContainerHasKernelServices() 0 11 3
A boot() 0 22 5
A handleCommand() 0 12 3
A handleRequest() 0 14 2
1
<?php
2
3
namespace pjpawel\LightApi;
4
5
use Exception;
6
use pjpawel\LightApi\Command\CommandsLoader;
7
use pjpawel\LightApi\Component\ClassWalker;
8
use pjpawel\LightApi\Component\Env;
9
use pjpawel\LightApi\Component\Event\EventHandler;
10
use pjpawel\LightApi\Container\ContainerLoader;
11
use pjpawel\LightApi\Route\Router;
12
use pjpawel\LightApi\Http\Request;
13
use pjpawel\LightApi\Http\Response;
14
use Psr\Log\LoggerInterface;
15
use Symfony\Component\Cache\Adapter\AbstractAdapter;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Cache\Adapter\AbstractAdapter 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...
16
17
class Kernel
18
{
19
20
    public const VERSION = 003000;
21
    public const VERSION_DOTTED = '0.3.0';
22
    /* only for stable version */
23
    //public const VERSION_END_OF_LIFE = '06/2023';
24
    //public const VERSION_END_OF_MAINTENANCE = '03/2023';
25
26
    public const KERNEL_CACHE_NAME = 'kernel.cache';
27
    public const KERNEL_LOGGER_NAME = 'kernel.logger';
28
    private const PROPERTIES_TO_CACHE = [
29
        'containerLoader' => 'kernel.container',
30
        'router' => 'kernel.router',
31
        'commandLoader' => 'kernel.command'
32
    ];
33
34
    /**
35
     * @var string project directory
36
     */
37
    public string $projectDir;
38
    public string $env;
39
    public bool $debug;
40
    private bool $makeCacheOnDestruct = true;
41
    private Router $router;
42
    private CommandsLoader $commandLoader;
43
    private ContainerLoader $containerLoader;
44
    private ?LoggerInterface $kernelLogger;
45
    private EventHandler $eventHandler;
46
    private AbstractAdapter $kernelCache;
47
48
    public function __construct(string $configDir)
49
    {
50
        $env = new Env();
51
        $config = $env->getConfigFromEnv($configDir);
52
        $this->projectDir = $config['projectDir'];
53
        $this->env = $config['env'];
54
        $this->debug = $config['debug'];
55
        $this->kernelCache = $env->createClassFromConfig($config['cache']);
56
        $this->boot($config);
57
        $this->ensureContainerHasKernelServices();
58
        $this->eventHandler->tryTriggering(EventHandler::KERNEL_AFTER_BOOT);
59
    }
60
61
    protected function boot(array $config): void
62
    {
63
        $loaded = false;
64
        if (!$this->debug) {
65
            $loaded = true;
66
            foreach (self::PROPERTIES_TO_CACHE as $property => $cacheName) {
67
                $routerItem = $this->kernelCache->getItem($cacheName);
68
                if (!$routerItem->isHit()) {
69
                    $loaded = false;
70
                    break;
71
                }
72
                $this->$property = $routerItem->get();
73
            }
74
            $this->makeCacheOnDestruct = false;
75
        }
76
        if (!$loaded) {
77
            $classWalker = new ClassWalker($config['services'] ?? $this->projectDir);
78
            $this->containerLoader = new ContainerLoader();
79
            $this->router = new Router();
80
            $this->commandLoader = new CommandsLoader();
81
            $classWalker->register($this->containerLoader, $this->router, $this->commandLoader);
82
            $this->containerLoader->createDefinitionsFromConfig($config['container']);
83
        }
84
    }
85
86
    private function ensureContainerHasKernelServices(): void
87
    {
88
        if (!$this->containerLoader->has(EventHandler::class)) {
89
            $this->containerLoader->add(['name' => EventHandler::class]);
90
            $this->eventHandler = $this->containerLoader->get(EventHandler::class);
91
        }
92
        $this->containerLoader->add(['name' => self::KERNEL_CACHE_NAME, 'object' => $this->kernelCache]);
93
        if ($this->containerLoader->has(self::KERNEL_LOGGER_NAME)) {
94
            $this->kernelLogger = $this->containerLoader->get(self::KERNEL_LOGGER_NAME);
95
        } else {
96
            $this->kernelLogger = null;
97
        }
98
    }
99
100
    /**
101
     * @param Request $request
102
     * @return Response
103
     * @throws Exception
104
     */
105
    public function handleRequest(Request $request): Response
106
    {
107
        $request->logRequest($this->kernelLogger);
108
        $request->validateIp();
109
        $this->eventHandler->tryTriggering(EventHandler::KERNEL_BEFORE_REQUEST);
110
        try {
111
            $route = $this->router->getRoute($request);
112
        } catch (Exception $e) {
113
            return $this->router->getErrorResponse($e);
114
        }
115
        $this->containerLoader->add(['name' => Request::class, 'args' => [], 'object' => $request]);
116
        $response = $route->execute($this->containerLoader, $request);
117
        $this->eventHandler->tryTriggering(EventHandler::KERNEL_AFTER_REQUEST);
118
        return $response;
119
    }
120
121
    /**
122
     * @param string|null $commandName
123
     * @return int
124
     */
125
    public function handleCommand(?string $commandName = null): int
126
    {
127
        if ($commandName === null) {
128
            $commandName = $this->commandLoader->getCommandNameFromServer();
129
        }
130
        $this->eventHandler->tryTriggering(EventHandler::KERNEL_BEFORE_COMMAND);
131
        if (str_starts_with($commandName, 'kernel:')) {
132
            return $this->commandLoader->runCommandFromName($commandName, $this->containerLoader, $this);
133
        }
134
        $code = $this->commandLoader->runCommandFromName($commandName, $this->containerLoader);
135
        $this->eventHandler->tryTriggering(EventHandler::KERNEL_AFTER_COMMAND);
136
        return $code;
137
    }
138
139
    public function __destruct()
140
    {
141
        $this->eventHandler->tryTriggering(EventHandler::KERNEL_ON_DESTRUCT);
142
        if (!$this->debug && $this->makeCacheOnDestruct) {
143
            foreach (self::PROPERTIES_TO_CACHE as $property => $cacheName) {
144
                $cacheItem = $this->kernelCache->getItem($cacheName);
145
                $cacheItem->set($this->$property);
146
                $this->kernelCache->save($cacheItem);
147
            }
148
        }
149
    }
150
}