Passed
Push — master ( d60b94...cd9ad7 )
by Alexander
05:03 queued 03:06
created

RoadRunnerApplicationRunner::run()   A

Complexity

Conditions 3
Paths 12

Size

Total Lines 53
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 6
Bugs 0 Features 0
Metric Value
cc 3
eloc 30
c 6
b 0
f 0
nc 12
nop 0
dl 0
loc 53
ccs 0
cts 31
cp 0
crap 12
rs 9.44

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 Yiisoft\Yii\Runner\RoadRunner;
6
7
use ErrorException;
8
use JsonException;
9
use Psr\Container\ContainerExceptionInterface;
10
use Psr\Container\NotFoundExceptionInterface;
11
use Psr\Http\Message\ResponseInterface;
12
use Psr\Http\Message\ServerRequestFactoryInterface;
13
use Psr\Http\Message\StreamFactoryInterface;
14
use Psr\Http\Message\UploadedFileFactoryInterface;
15
use Spiral\RoadRunner;
16
use Throwable;
17
use Yiisoft\Definitions\Exception\CircularReferenceException;
18
use Yiisoft\Definitions\Exception\InvalidConfigException;
19
use Yiisoft\Definitions\Exception\NotInstantiableException;
20
use Yiisoft\Di\NotFoundException;
21
use Yiisoft\Di\StateResetter;
22
use Yiisoft\ErrorHandler\ErrorHandler;
23
use Yiisoft\ErrorHandler\Middleware\ErrorCatcher;
24
use Yiisoft\ErrorHandler\Renderer\PlainTextRenderer;
25
use Yiisoft\Log\Logger;
26
use Yiisoft\Log\Target\File\FileTarget;
27
use Yiisoft\Yii\Http\Application;
28
use Yiisoft\Yii\Http\Handler\ThrowableHandler;
29
use Yiisoft\Yii\Runner\ApplicationRunner;
30
31
use function gc_collect_cycles;
32
use function microtime;
33
34
/**
35
 * `RoadRunnerApplicationRunner` runs the Yii HTTP application for RoadRunner.
36
 */
37
final class RoadRunnerApplicationRunner extends ApplicationRunner
38
{
39
    private ?ErrorHandler $temporaryErrorHandler = null;
40
41
    /**
42
     * @param string $rootPath The absolute path to the project root.
43
     * @param bool $debug Whether the debug mode is enabled.
44
     * @param string|null $environment The environment name.
45
     */
46
    public function __construct(string $rootPath, bool $debug, ?string $environment)
47
    {
48
        parent::__construct($rootPath, $debug, $environment);
49
        $this->bootstrapGroup = 'bootstrap-web';
50
        $this->eventsGroup = 'events-web';
51
    }
52
53
    /**
54
     * Returns a new instance with the specified temporary error handler instance {@see ErrorHandler}.
55
     *
56
     * A temporary error handler is needed to handle the creation of configuration and container instances,
57
     * then the error handler configured in your application configuration will be used.
58
     *
59
     * @param ErrorHandler $temporaryErrorHandler The temporary error handler instance.
60
     *
61
     * @return self
62
     */
63
    public function withTemporaryErrorHandler(ErrorHandler $temporaryErrorHandler): self
64
    {
65
        $new = clone $this;
66
        $new->temporaryErrorHandler = $temporaryErrorHandler;
67
        return $new;
68
    }
69
70
    /**
71
     * {@inheritDoc}
72
     *
73
     * @throws CircularReferenceException|ErrorException|InvalidConfigException|JsonException
74
     * @throws ContainerExceptionInterface|NotFoundException|NotFoundExceptionInterface|NotInstantiableException
75
     */
76
    public function run(): void
77
    {
78
        // Register temporary error handler to catch error while container is building.
79
        $temporaryErrorHandler = $this->createTemporaryErrorHandler();
80
        $this->registerErrorHandler($temporaryErrorHandler);
81
82
        $config = $this->getConfig();
83
        $container = $this->getContainer($config, 'web');
84
85
        // Register error handler with real container-configured dependencies.
86
        /** @var ErrorHandler $actualErrorHandler */
87
        $actualErrorHandler = $container->get(ErrorHandler::class);
88
        $this->registerErrorHandler($actualErrorHandler, $temporaryErrorHandler);
89
90
        $this->runBootstrap($config, $container);
91
        $this->checkEvents($config, $container);
92
93
        $worker = RoadRunner\Worker::create();
94
        /** @var ServerRequestFactoryInterface $serverRequestFactory */
95
        $serverRequestFactory = $container->get(ServerRequestFactoryInterface::class);
96
        /** @var StreamFactoryInterface $streamFactory */
97
        $streamFactory = $container->get(StreamFactoryInterface::class);
98
        /** @var UploadedFileFactoryInterface $uploadsFactory */
99
        $uploadsFactory = $container->get(UploadedFileFactoryInterface::class);
100
        $worker = new RoadRunner\Http\PSR7Worker($worker, $serverRequestFactory, $streamFactory, $uploadsFactory);
101
102
        /** @var Application $application */
103
        $application = $container->get(Application::class);
104
        $application->start();
105
106
        while ($request = $worker->waitRequest()) {
107
            $request = $request->withAttribute('applicationStartTime', microtime(true));
108
            $response = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $response is dead and can be removed.
Loading history...
109
            try {
110
                $response = $application->handle($request);
111
                $worker->respond($response);
112
            } catch (Throwable $t) {
113
                $handler = new ThrowableHandler($t);
114
                /**
115
                 * @var ResponseInterface
116
                 * @psalm-suppress MixedMethodCall
117
                 */
118
                $response = $container->get(ErrorCatcher::class)->process($request, $handler);
119
                $worker->respond($response);
120
            } finally {
121
                $application->afterEmit($response ?? null);
122
                /** @psalm-suppress MixedMethodCall */
123
                $container->get(StateResetter::class)->reset(); // We should reset the state of such services every request.
124
                gc_collect_cycles();
125
            }
126
        }
127
128
        $application->shutdown();
129
    }
130
131
    private function createTemporaryErrorHandler(): ErrorHandler
132
    {
133
        if ($this->temporaryErrorHandler !== null) {
134
            return $this->temporaryErrorHandler;
135
        }
136
137
        $logger = new Logger([new FileTarget("$this->rootPath/runtime/logs/app.log")]);
138
        return new ErrorHandler($logger, new PlainTextRenderer());
139
    }
140
141
    /**
142
     * @throws ErrorException
143
     */
144
    private function registerErrorHandler(ErrorHandler $registered, ErrorHandler $unregistered = null): void
145
    {
146
        $unregistered?->unregister();
147
148
        if ($this->debug) {
149
            $registered->debug();
150
        }
151
152
        $registered->register();
153
    }
154
}
155