Passed
Pull Request — master (#383)
by Wilmer
03:15
created

WebApplicationRunner::run()   A

Complexity

Conditions 3
Paths 32

Size

Total Lines 56
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 3.0236

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 28
c 1
b 0
f 0
nc 32
nop 0
dl 0
loc 56
ccs 25
cts 29
cp 0.8621
crap 3.0236
rs 9.472

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace App\Runner;
6
7
use App\Handler\ThrowableHandler;
8
use ErrorException;
9
use Psr\Container\ContainerInterface;
10
use Psr\Http\Message\RequestInterface;
11
use Psr\Http\Message\ResponseInterface;
12
use Psr\Http\Message\ServerRequestInterface;
13
use Throwable;
14
use Yiisoft\Di\Container;
15
use Yiisoft\ErrorHandler\ErrorHandler;
16
use Yiisoft\ErrorHandler\Middleware\ErrorCatcher;
17
use Yiisoft\ErrorHandler\Renderer\HtmlRenderer;
18
use Yiisoft\Definitions\Exception\CircularReferenceException;
19
use Yiisoft\Definitions\Exception\InvalidConfigException;
20
use Yiisoft\Definitions\Exception\NotFoundException;
21
use Yiisoft\Definitions\Exception\NotInstantiableException;
22
use Yiisoft\Http\Method;
23
use Yiisoft\Log\Logger;
24
use Yiisoft\Log\Target\File\FileTarget;
25
use Yiisoft\Yii\Event\ListenerConfigurationChecker;
26
use Yiisoft\Yii\Web\Application;
27
use Yiisoft\Yii\Web\Exception\HeadersHaveBeenSentException;
28
use Yiisoft\Yii\Web\SapiEmitter;
29
use Yiisoft\Yii\Web\ServerRequestFactory;
30
31
use function dirname;
32
use function microtime;
33
34
final class WebApplicationRunner
35
{
36
    private bool $debug;
37
    private ?string $environment;
38
39 10
    public function __construct(bool $debug, ?string $environment)
40
    {
41 10
        $this->debug = $debug;
42 10
        $this->environment = $environment;
43 10
    }
44
45
    /**
46
     * @throws CircularReferenceException|ErrorException|HeadersHaveBeenSentException|InvalidConfigException
47
     * @throws NotFoundException|NotInstantiableException|
48
     */
49 10
    public function run(): void
50
    {
51 10
        $startTime = microtime(true);
52
53
        // Register temporary error handler to catch error while container is building.
54 10
        $errorHandler = $this->createTemporaryErrorHandler();
55 10
        $this->registerErrorHandler($errorHandler);
56
57 10
        $config = ConfigFactory::create($this->environment);
58
59 10
        $container = new Container(
60 10
            $config->get('web'),
61 10
            $config->get('providers-web'),
62 10
            [],
63 10
            $this->debug,
64 10
            $config->get('delegates-web')
65
        );
66
67
        // Register error handler with real container-configured dependencies.
68 10
        $this->registerErrorHandler($container->get(ErrorHandler::class), $errorHandler);
69
70
        // Run bootstrap
71 10
        $this->runBootstrap($container, $config->get('bootstrap-web'));
72
73 10
        $container = $container->get(ContainerInterface::class);
74
75 10
        if ($this->debug) {
76
            /** @psalm-suppress MixedMethodCall */
77 10
            $container->get(ListenerConfigurationChecker::class)->check($config->get('events-web'));
78
        }
79
80
        /** @var Application */
81 10
        $application = $container->get(Application::class);
82
83
        /**
84
         * @var ServerRequestInterface
85
         * @psalm-suppress MixedMethodCall
86
         */
87 10
        $serverRequest = $container->get(ServerRequestFactory::class)->createFromGlobals();
88 10
        $request = $serverRequest->withAttribute('applicationStartTime', $startTime);
89
90
        try {
91 10
            $application->start();
92 10
            $response = $application->handle($request);
93 10
            $this->emit($request, $response);
94
        } catch (Throwable $throwable) {
95
            $handler = new ThrowableHandler($throwable);
96
            /**
97
             * @var ResponseInterface
98
             * @psalm-suppress MixedMethodCall
99
             */
100
            $response = $container->get(ErrorCatcher::class)->process($request, $handler);
101
            $this->emit($request, $response);
102 10
        } finally {
103 10
            $application->afterEmit($response ?? null);
104 10
            $application->shutdown();
105
        }
106 10
    }
107
108 10
    private function createTemporaryErrorHandler(): ErrorHandler
109
    {
110 10
        $logger = new Logger([new FileTarget(dirname(__DIR__) . '/runtime/logs/app.log')]);
111 10
        return new ErrorHandler($logger, new HtmlRenderer());
112
    }
113
114
    /**
115
     * @throws HeadersHaveBeenSentException
116
     */
117 10
    private function emit(RequestInterface $request, ResponseInterface $response): void
118
    {
119 10
        (new SapiEmitter())->emit($response, $request->getMethod() === Method::HEAD);
120 10
    }
121
122
    /**
123
     * @throws ErrorException
124
     */
125 10
    private function registerErrorHandler(ErrorHandler $registered, ErrorHandler $unregistered = null): void
126
    {
127 10
        if ($unregistered !== null) {
128 10
            $unregistered->unregister();
129
        }
130
131 10
        if ($this->debug) {
132 10
            $registered->debug();
133
        }
134
135 10
        $registered->register();
136 10
    }
137
138 10
    private function runBootstrap(Container $container, array $bootstrapList): void
139
    {
140 10
        (new BootstrapRunner($container, $bootstrapList))->run();
141 10
    }
142
}
143