TestApplicationRunner   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 191
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 7
Bugs 0 Features 0
Metric Value
eloc 76
c 7
b 0
f 0
dl 0
loc 191
ccs 0
cts 80
cp 0
rs 10
wmc 12

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 30 1
A withRequest() 0 23 1
A createContainer() 0 30 5
A addProviders() 0 3 1
A run() 0 46 3
A preloadContainer() 0 11 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Testing;
6
7
use Psr\Container\ContainerInterface;
8
use Psr\Http\Message\ResponseInterface;
9
use Psr\Http\Message\ServerRequestFactoryInterface;
10
use Psr\Http\Message\ServerRequestInterface;
11
use Throwable;
12
use Yiisoft\Config\ConfigInterface;
13
use Yiisoft\Di\Container;
14
use Yiisoft\Di\ContainerConfig;
15
use Yiisoft\Di\ServiceProviderInterface;
16
use Yiisoft\ErrorHandler\ErrorHandler;
0 ignored issues
show
Bug introduced by
The type Yiisoft\ErrorHandler\ErrorHandler 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 Yiisoft\ErrorHandler\Middleware\ErrorCatcher;
18
use Yiisoft\Yii\Http\Application;
19
use Yiisoft\Yii\Http\Handler\ThrowableHandler;
20
use Yiisoft\Yii\Runner\ApplicationRunner;
21
22
final class TestApplicationRunner extends ApplicationRunner
23
{
24
    public ?ContainerInterface $container = null;
25
    private array $requestParameters = [];
26
    /**
27
     * @var ServiceProviderInterface[]
28
     */
29
    private array $providers = [];
30
31
    /**
32
     * @param string $rootPath The absolute path to the project root.
33
     * @param bool $debug Whether the debug mode is enabled.
34
     * @param bool $checkEvents Whether to check events' configuration.
35
     * @param string|null $environment The environment name.
36
     * @param string $bootstrapGroup The bootstrap configuration group name.
37
     * @param string $eventsGroup The events' configuration group name.
38
     * @param string $diGroup The container definitions' configuration group name.
39
     * @param string $diProvidersGroup The container providers' configuration group name.
40
     * @param string $diDelegatesGroup The container delegates' configuration group name.
41
     * @param string $diTagsGroup The container tags' configuration group name.
42
     * @param string $paramsGroup The configuration parameters group name.
43
     * @param array $nestedParamsGroups Configuration group names that included into configuration parameters group.
44
     * This is needed for recursive merging of parameters.
45
     * @param array $nestedEventsGroups Configuration group names that included into events' configuration group. This
46
     * is needed for reverse and recursive merge of events' configurations.
47
     *
48
     * @psalm-param list<string> $nestedParamsGroups
49
     * @psalm-param list<string> $nestedEventsGroups
50
     */
51
    public function __construct(
52
        public ResponseGrabber $responseGrabber,
53
        string $rootPath,
54
        bool $debug = false,
55
        bool $checkEvents = false,
56
        ?string $environment = null,
57
        string $bootstrapGroup = 'bootstrap-web',
58
        string $eventsGroup = 'events-web',
59
        string $diGroup = 'di-web',
60
        string $diProvidersGroup = 'di-providers-web',
61
        string $diDelegatesGroup = 'di-delegates-web',
62
        string $diTagsGroup = 'di-tags-web',
63
        string $paramsGroup = 'params-web',
64
        array $nestedParamsGroups = ['params'],
65
        array $nestedEventsGroups = ['events'],
66
    ) {
67
        parent::__construct(
68
            $rootPath,
69
            $debug,
70
            $checkEvents,
71
            $environment,
72
            $bootstrapGroup,
73
            $eventsGroup,
74
            $diGroup,
75
            $diProvidersGroup,
76
            $diDelegatesGroup,
77
            $diTagsGroup,
78
            $paramsGroup,
79
            $nestedParamsGroups,
80
            $nestedEventsGroups,
81
        );
82
    }
83
84
    /**
85
     * {@inheritDoc}
86
     */
87
    public function run(): void
88
    {
89
        $this->preloadContainer();
90
91
        /** @var ContainerInterface $container */
92
        $container = $this->container;
93
94
        $errorHandler = $container->get(ErrorHandler::class);
95
        if ($this->debug) {
96
            $errorHandler->debug();
97
        }
98
        $errorHandler->register();
99
100
        /** @var Application $application */
101
        $application = $container->get(Application::class);
102
103
        /**
104
         * @var ServerRequestInterface
105
         * @psalm-suppress MixedMethodCall
106
         */
107
        $serverRequest = $container
108
            ->get(ServerRequestFactoryInterface::class)
109
            ->createServerRequest(
110
                $this->requestParameters['server']['REQUEST_METHOD'],
111
                $this->requestParameters['server']['REQUEST_URI'],
112
            );
113
114
        /**
115
         * @var ResponseInterface|null $response
116
         */
117
        $response = null;
118
        try {
119
            $application->start();
120
            $response = $application->handle($serverRequest);
121
        } catch (Throwable $throwable) {
122
            $handler = new ThrowableHandler($throwable);
123
            /**
124
             * @psalm-suppress MixedMethodCall
125
             */
126
            $response = $container
127
                ->get(ErrorCatcher::class)
128
                ->process($serverRequest, $handler);
129
        } finally {
130
            $application->afterEmit($response ?? null);
131
            $application->shutdown();
132
            $this->responseGrabber->setResponse($response);
133
        }
134
    }
135
136
    public function withRequest(
137
        string $method,
138
        string $url,
139
        array $queryParams = [],
140
        array $postParams = [],
141
        mixed $body = null,
142
        array $headers = [],
143
        array $cookies = [],
144
        array $files = [],
145
    ): void {
146
        $this->requestParameters = [
147
            'server' => [
148
                'SCRIPT_NAME' => '/index.php',
149
                'REQUEST_METHOD' => $method,
150
                'SERVER_PROTOCOL' => '1.1',
151
                'REQUEST_URI' => $url,
152
            ],
153
            'headers' => $headers,
154
            'cookies' => $cookies,
155
            'get' => $queryParams,
156
            'post' => $postParams,
157
            'files' => $files,
158
            'body' => $body,
159
        ];
160
    }
161
162
    public function preloadContainer(): void
163
    {
164
        /**
165
         * @psalm-suppress UnresolvableInclude
166
         */
167
        require_once $this->rootPath . '/autoload.php';
168
169
        $this->container = $this->createContainer();
170
171
        $this->runBootstrap();
172
        $this->checkEvents();
173
    }
174
175
    /**
176
     * @param ServiceProviderInterface[] $providers
177
     */
178
    public function addProviders(array $providers): void
179
    {
180
        $this->providers = array_merge($this->providers, $providers);
181
    }
182
183
    private function createContainer(): Container
184
    {
185
        $containerConfig = ContainerConfig::create()->withValidate($this->debug);
186
187
        $config = $this->getConfig();
188
189
        if (null !== $definitions = $this->getConfiguration($this->diGroup)) {
190
            $containerConfig = $containerConfig->withDefinitions($definitions);
191
        }
192
193
        if (null !== $providers = $this->getConfiguration($this->diProvidersGroup)) {
194
            $providers = array_merge($providers, $this->providers);
195
        } else {
196
            $providers = $this->providers;
197
        }
198
        $containerConfig = $containerConfig->withProviders($providers);
199
200
        if (null !== $delegates = $this->getConfiguration($this->diDelegatesGroup)) {
201
            $containerConfig = $containerConfig->withDelegates($delegates);
202
        }
203
204
        if (null !== $tags = $this->getConfiguration($this->diTagsGroup)) {
205
            $containerConfig = $containerConfig->withTags($tags);
206
        }
207
208
        $containerConfig = $containerConfig->withDefinitions(
209
            array_merge($containerConfig->getDefinitions(), [ConfigInterface::class => $config])
210
        );
211
212
        return new Container($containerConfig);
213
    }
214
}
215