Failed Conditions
Push — master ( ad8d2e...e91cdf )
by Arnold
10s
created

Connector::createPsrRequest()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.1481

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 4
cts 6
cp 0.6667
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 0
crap 2.1481
1
<?php
2
3
namespace Jasny\Codeception;
4
5
use Psr\Http\Message\ServerRequestInterface;
6
use Psr\Http\Message\ResponseInterface;
7
use Psr\Http\Message\UploadedFileInterface;
8
use Psr\Http\Message\UriInterface;
9
use Jasny\HttpMessage\Response;
10
use Jasny\HttpMessage\ServerRequest;
11
use Jasny\HttpMessage\UploadedFile;
12
use Jasny\HttpMessage\Uri;
13
use Jasny\HttpMessage\Stream;
14
use Jasny\HttpMessage\OutputBufferStream;
15
use Jasny\Router;
16
use Symfony\Component\BrowserKit\Client;
17
use Symfony\Component\BrowserKit\Request as BrowserKitRequest;
18
use Symfony\Component\BrowserKit\Response as BrowserKitResponse;
19
20
/**
21
 * Codeception connector for Jasny\MVC
22
 */
23
class Connector extends Client
24
{
25
    /**
26
     * @var Router
27
     */
28
    protected $router;
29
    
30
    /**
31
     * Request with the current global environent
32
     * @var ServerRequestInterface
33
     */
34
    protected $baseRequest;
35
    
36
    /**
37
     * Request with the current global environent
38
     * @var ResponseInterface
39
     */
40
    protected $baseResponse;
41
    
42
    
43
    /**
44
     * Set the router
45
     * 
46
     * @param Router $router
47
     */
48 3
    public function setRouter(Router $router)
49
    {
50 3
        $this->router = $router;
51 3
    }
52
    
53
    /**
54
     * Get the router
55
     * 
56
     * @return Router
57
     */
58 4
    public function getRouter()
59
    {
60 4
        return $this->router;
61
    }
62
    
63
    
64
    /**
65
     * Set the base request
66
     * 
67
     * @param ServerRequestInterface $request
68
     */
69 3
    public function setBaseRequest(ServerRequestInterface $request)
70 1
    {
71 3
        if ($request instanceof ServerRequest && $request->isStale()) {
72 1
            throw new \RuntimeException("Unable to set base request: ServerRequest is stale");
73
        }
74
        
75 2
        $this->baseRequest = $request;
76 2
    }
77
    
78
    /**
79
     * Get the base request
80
     * 
81
     * @return ServerRequestInterface
82
     */
83 4
    public function getBaseRequest()
84
    {
85 4
        if (!isset($this->baseRequest)) {
86 2
            $this->baseRequest = new ServerRequest();
87 2
        }
88
        
89 4
        return $this->baseRequest;
90
    }
91
    
92
    
93
    /**
94
     * Set the base response
95
     * 
96
     * @param ResponseInterface $response
97
     */
98 3
    public function setBaseResponse(ResponseInterface $response)
99
    {
100 3
        if ($response instanceof Response && $response->isStale()) {
101 1
            throw new \RuntimeException("Unable to set base response: Response is stale");
102
        }
103
        
104 2
        $this->baseResponse = $response;
105 2
    }
106
    
107
    /**
108
     * Get the base response
109
     * 
110
     * @return ResponseInterface
111
     */
112 4
    public function getBaseResponse()
113
    {
114 4
        if (!isset($this->baseResponse)) {
115 2
            $this->baseResponse = new Response();
116 2
        }
117
        
118 4
        return $this->baseResponse;
119
    }
120
    
121
    /**
122
     * Reset the request and response.
123
     * This is only required when the request and/or response are bound to the global environment.
124
     */
125 3
    public function reset()
126
    {
127 3
        if (isset($this->baseRequest) && $this->baseRequest instanceof ServerRequest && $this->baseRequest->isStale()) {
128 1
            $this->baseRequest = $this->baseRequest->revive();
129 1
        }
130
131 3
        if (isset($this->baseResponse) && $this->baseResponse instanceof Response && $this->baseResponse->isStale()) {
132 1
            $this->baseResponse = $this->baseResponse->revive();
133 1
        }
134
        
135
        // Clear output buffer
136 3
        if (isset($this->baseResponse) && $this->baseResponse->getBody() instanceof OutputBufferStream) {
137 1
            $this->baseResponse = $this->baseResponse->withBody(clone $this->baseResponse->getBody());
138 1
        }
139 3
    }
140
141
142
    /**
143
     * Build a full URI from a request
144
     * 
145
     * @param BrowserKitRequest $request
146
     * @return array [Uri, queryParams]
147
     */
148 2
    protected function buildFullUri(BrowserKitRequest $request)
149
    {
150 2
        $uri = new Uri($request->getUri());
151
        
152 2
        $queryParams = [];
153 2
        parse_str($uri->getQuery(), $queryParams);
154
        
155 2
        if ($request->getMethod() === 'GET') {
156 1
            $queryParams = array_merge($queryParams, $request->getParameters());
157 1
            $uri = $uri->withQuery(http_build_query($queryParams));
158 1
        }
159
        
160 2
        return [$uri, $queryParams];
161
    }
162
    
163
    /**
164
     * Get additional server params from request.
165
     * @internal It would be nicer if this was solved by Jasny Http Message
166
     * 
167
     * @param BrowserKitRequest $request
168
     * @param UriInterface      $uri
169
     * @param array             $queryParams
170
     * @return array
171
     */
172 2
    protected function determineServerParams(BrowserKitRequest $request, UriInterface $uri, array $queryParams)
173
    {
174
        return [
175 2
            'REQUEST_METHOD' => $request->getMethod(),
176 2
            'QUERY_STRING' => http_build_query($queryParams),
177 2
            'REQUEST_URI' => (string)($uri->withScheme('')->withHost('')->withPort('')->withUserInfo(''))
178 2
        ];
179
    }
180
    
181
    /**
182
     * Convert a codeception request to a Jasny PSR-7 server request
183
     * 
184
     * @param BrowserKitRequest $request
185
     * @return ServerRequest
186
     */
187 2
    protected function convertRequest(BrowserKitRequest $request)
188
    {
189 2
        list($uri, $queryParams) = $this->buildFullUri($request);
190
        
191 2
        $stream = fopen('php://temp', 'r+');
192 2
        fwrite($stream, $request->getContent());
193 2
        fseek($stream, 0);
194
        
195 2
        $baseRequest = $this->getBaseRequest();
196
        
197 2
        if ($baseRequest instanceof ServerRequest) {
198 2
            $serverParams = $this->determineServerParams($request, $uri, (array)$queryParams);
199 2
            $baseRequest = $baseRequest->withServerParams($request->getServer() + $serverParams);
200 2
        }
201
        
202
        $psrRequest = $baseRequest
203 2
            ->withBody(new Stream($stream))
204 2
            ->withMethod($request->getMethod())
205 2
            ->withRequestTarget((string)($uri->withScheme('')->withHost('')->withPort('')->withUserInfo('')))
206 2
            ->withCookieParams($request->getCookies())
207 2
            ->withUri($uri)
208 2
            ->withQueryParams((array)$queryParams)
209 2
            ->withUploadedFiles($this->convertUploadedFiles($request->getFiles()));
210
        
211 2
        if ($request->getMethod() !== 'GET' && !empty($request->getParameters())) {
212 1
            $psrRequest = $psrRequest->withParsedBody($request->getParameters());
213 1
        }
214
        
215 2
        return $psrRequest;
216
    }
217
    
218
    /**
219
     * Convert a Jasny PSR-7 response to a codeception response
220
     * 
221
     * @param ResponseInterface $psrResponse
222
     * @return BrowserKitResponse
223
     */
224 2
    protected function convertResponse(ResponseInterface $psrResponse)
225
    {
226 2
        return new BrowserKitResponse(
227 2
            (string)$psrResponse->getBody(),
228 2
            $psrResponse->getStatusCode() ?: 200,
229 2
            $psrResponse->getHeaders()
230 2
        );
231
    }
232
    
233
    /**
234
     * Convert a list of uploaded files to a Jasny PSR-7 uploaded files
235
     * 
236
     * @param array $files
237
     * @return UploadedFile[]|array
238
     */
239 2
    protected function convertUploadedFiles(array $files)
240
    {
241 2
        $fileObjects = [];
242
        
243 2
        foreach ($files as $fieldName => $file) {
244 1
            if ($file instanceof UploadedFileInterface) {
245
                $fileObjects[$fieldName] = $file;
246 1
            } elseif (!isset($file['tmp_name']) && !isset($file['name'])) {
247
                $fileObjects[$fieldName] = $this->convertUploadedFiles($file);
248
            } else {
249 1
                $fileObjects[$fieldName] = new UploadedFile($file);
250
            }
251 2
        }
252
        
253 2
        return $fileObjects;
254
    }
255
    
256
    
257
    /**
258
     * Makes a request.
259
     * 
260
     * @param BrowserKitRequest $request
261
     * @return BrowserKitResponse
262
     */
263 3
    protected function doRequest($request)
264
    {
265 3
        if ($this->getRouter() === null) {
266 1
            throw new \BadMethodCallException("Router not set");
267
        }
268
        
269 2
        $this->reset(); // Reset before each HTTP request
270
        
271 2
        $psrRequest = $this->convertRequest($request);
272
        
273 2
        $router = $this->getRouter();
274 2
        $psrResponse = $router->handle($psrRequest, $this->getBaseResponse());
275
        
276 2
        return $this->convertResponse($psrResponse);
277
    }
278
}
279