Passed
Push — master ( 91f02d...65071d )
by Melech
21:33 queued 07:21
created

App::bootstrapExceptionHandler()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 12
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
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\Entry;
15
16
use Valkyrja\Application\Config;
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\Data;
19
use Valkyrja\Application\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...
20
use Valkyrja\Application\Exception\RuntimeException;
21
use Valkyrja\Application\Valkyrja;
22
use Valkyrja\Cli\Interaction\Factory\InputFactory;
23
use Valkyrja\Cli\Interaction\Input\Contract\Input;
24
use Valkyrja\Cli\Server\Contract\InputHandler;
25
use Valkyrja\Container\Contract\Container;
26
use Valkyrja\Exception\Contract\ExceptionHandler as ErrorHandlerContract;
27
use Valkyrja\Exception\ExceptionHandler;
28
use Valkyrja\Http\Message\Factory\RequestFactory;
29
use Valkyrja\Http\Message\Request\Contract\ServerRequest;
30
use Valkyrja\Http\Server\Contract\RequestHandler;
31
use Valkyrja\Support\Directory;
0 ignored issues
show
Bug introduced by
The type Valkyrja\Support\Directory 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...
32
use Valkyrja\Support\Microtime;
33
34
use function define;
35
use function defined;
36
37
/**
38
 * Abstract Class App.
39
 *
40
 * @author Melech Mizrachi
41
 */
42
abstract class App
43
{
44
    /**
45
     * Start the application.
46
     *
47
     * @param non-empty-string $dir The directory
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
48
     */
49
    public static function start(string $dir, Env $env): Application
50
    {
51
        static::defaultExceptionHandler();
52
        static::appStart();
53
        static::directory(dir: $dir);
54
55
        return static::app(env: $env);
56
    }
57
58
    /**
59
     * Now that the application has been bootstrapped and setup correctly with all our requirements lets run it!
60
     *
61
     * @param non-empty-string $dir The directory
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
62
     */
63
    public static function http(string $dir, Env $env): void
64
    {
65
        $app = static::start(
66
            dir: $dir,
67
            env: $env,
68
        );
69
70
        $container = $app->getContainer();
71
72
        self::bootstrapExceptionHandler($app, $container);
73
74
        $handler = $container->getSingleton(RequestHandler::class);
75
        $request = static::getRequest();
76
        $handler->run($request);
77
    }
78
79
    /**
80
     * Now that the application has been bootstrapped and setup correctly with all our requirements lets run it!
81
     *
82
     * @param non-empty-string $dir The directory
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
83
     */
84
    public static function cli(string $dir, Env $env): void
85
    {
86
        $app = static::start(
87
            dir: $dir,
88
            env: $env,
89
        );
90
91
        $container = $app->getContainer();
92
93
        self::bootstrapExceptionHandler($app, $container);
94
95
        $handler = $container->getSingleton(InputHandler::class);
96
        $input   = static::getInput();
97
        $handler->run($input);
98
    }
99
100
    /**
101
     * Set a global constant for when the application as a whole started.
102
     */
103
    public static function appStart(): void
104
    {
105
        if (! defined('APP_START')) {
106
            define('APP_START', Microtime::get());
107
        }
108
    }
109
110
    /**
111
     * Let's set the base directory within the web server for our application
112
     * so that when we locate directories and files within the application
113
     * we have a standard location from which to do so.
114
     *
115
     * @param non-empty-string $dir The directory
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
116
     */
117
    public static function directory(string $dir): void
118
    {
119
        Directory::$BASE_PATH = $dir;
120
    }
121
122
    /**
123
     * Let's start up the application by creating a new instance of the
124
     * application class. This is going to bind all the various
125
     * components together into a singular hub. This will set the
126
     *  correct environment class file to use, and appropriate the config
127
     *  that should be loaded by the application. In dev you'll want to
128
     *  use the default config out of the root config directory, but
129
     *  when you're on a production environment definitely have
130
     *  your config cached and the flag set in your env class.
131
     */
132
    public static function app(Env $env): Application
133
    {
134
        /** @var non-empty-string $cacheFilepath */
135
        $cacheFilepath = $env::APP_CACHE_FILE_PATH;
136
137
        if (is_file($cacheFilepath)) {
138
            $configData = static::getData(cacheFilePath: $cacheFilepath);
139
        } else {
140
            $configData = static::getConfig();
141
        }
142
143
        return new Valkyrja(env: $env, configData: $configData);
144
    }
145
146
    /**
147
     * Get the application config.
148
     */
149
    protected static function getConfig(): Config
150
    {
151
        return new Config();
152
    }
153
154
    /**
155
     * Get the application data.
156
     *
157
     * @param non-empty-string $cacheFilePath The cache file path
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
158
     */
159
    protected static function getData(string $cacheFilePath): Data
160
    {
161
        $cache = file_get_contents($cacheFilePath);
162
163
        if ($cache === false || $cache === '') {
164
            throw new RuntimeException('Error occurred when retrieving cache file contents');
165
        }
166
167
        // Allow all classes, and filter for only Data classes down below since allowed_classes cannot be
168
        // a class that others extend off of, and we don't want to limit what a cached data class could be
169
        $data = unserialize($cache, ['allowed_classes' => true]);
170
171
        if (! $data instanceof Data) {
172
            throw new RuntimeException('Invalid cache');
173
        }
174
175
        return $data;
176
    }
177
178
    /**
179
     * Set a default exception handler until the one specified in config is set in the Container\AppProvider.
180
     */
181
    protected static function defaultExceptionHandler(): void
182
    {
183
        ExceptionHandler::enable(
184
            displayErrors: true
185
        );
186
    }
187
188
    /**
189
     * Bootstrap exception handler.
190
     */
191
    protected static function bootstrapExceptionHandler(Application $app, Container $container): void
192
    {
193
        $errorHandler = static::getExceptionHandler();
194
195
        // Set error handler in the service container
196
        $container->setSingleton(ErrorHandlerContract::class, $errorHandler);
197
198
        // If debug is on, enable debug handling
199
        if ($app->getDebugMode()) {
200
            // Enable error handling
201
            $errorHandler::enable(
202
                displayErrors: true
203
            );
204
        }
205
    }
206
207
    /**
208
     * Get the exception handler.
209
     */
210
    protected static function getExceptionHandler(): ErrorHandlerContract
211
    {
212
        return new ExceptionHandler();
213
    }
214
215
    /**
216
     * Get the request.
217
     */
218
    protected static function getRequest(): ServerRequest
219
    {
220
        return RequestFactory::fromGlobals();
221
    }
222
223
    /**
224
     * Get the input.
225
     */
226
    protected static function getInput(): Input
227
    {
228
        return InputFactory::fromGlobals();
229
    }
230
}
231