Completed
Pull Request — master (#28)
by Anton
09:49
created

PSR7Client   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 142
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
dl 0
loc 142
rs 10
c 0
b 0
f 0
wmc 17
lcom 1
cbo 5

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getWorker() 0 4 1
B acceptRequest() 0 47 8
A respond() 0 13 2
A configureServer() 0 9 1
A wrapUploads() 0 24 4
1
<?php
2
/**
3
 * High-performance PHP process supervisor and load balancer written in Go
4
 *
5
 * @author Wolfy-J
6
 */
7
8
namespace Spiral\RoadRunner;
9
10
use Psr\Http\Message\ResponseInterface;
11
use Psr\Http\Message\ServerRequestInterface;
12
use Zend\Diactoros;
13
14
/**
15
 * Manages PSR-7 request and response.
16
 */
17
class PSR7Client
18
{
19
    /**
20
     * @varWorker
21
     */
22
    private $worker;
23
24
    /**
25
     * @param Worker $worker
26
     */
27
    public function __construct(Worker $worker)
28
    {
29
        $this->worker = $worker;
30
    }
31
32
    /**
33
     * @return Worker
34
     */
35
    public function getWorker(): Worker
36
    {
37
        return $this->worker;
38
    }
39
40
    /**
41
     * @return ServerRequestInterface|null
42
     */
43
    public function acceptRequest()
44
    {
45
        $body = $this->worker->receive($ctx);
46
        if (empty($body) && empty($ctx)) {
47
            // termination request
48
            return null;
49
        }
50
51
        if (empty($ctx = json_decode($ctx, true))) {
52
            // invalid context
53
            return null;
54
        }
55
56
        parse_str($ctx['rawQuery'], $query);
57
58
        $bodyStream = 'php://input';
59
        $parsedBody = null;
60
        if ($ctx['parsed']) {
61
            $parsedBody = json_decode($body, true);
62
        } elseif ($body != null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $body of type Error|null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
63
            $bodyStream = new Diactoros\Stream("php://memory", "rwb");
64
            $bodyStream->write($body);
0 ignored issues
show
Bug introduced by
It seems like $body defined by $this->worker->receive($ctx) on line 45 can also be of type object<Error>; however, Zend\Diactoros\Stream::write() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
65
        }
66
67
        $_SERVER = $this->configureServer($ctx);
68
69
        $request = new Diactoros\ServerRequest(
70
            $_SERVER,
71
            $this->wrapUploads($ctx['uploads']),
72
            $ctx['uri'],
73
            $ctx['method'],
74
            $bodyStream,
75
            $ctx['headers'],
76
            $ctx['cookies'],
77
            $query,
0 ignored issues
show
Bug introduced by
It seems like $query can also be of type null; however, Zend\Diactoros\ServerRequest::__construct() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
78
            $parsedBody,
79
            $ctx['protocol']
80
        );
81
82
        if (!empty($ctx['attributes'])) {
83
            foreach ($ctx['attributes'] as $key => $value) {
84
                $request = $request->withAttribute($key, $value);
85
            }
86
        }
87
88
        return $request;
89
    }
90
91
    /**
92
     * Send response to the application server.
93
     *
94
     * @param ResponseInterface $response
95
     */
96
    public function respond(ResponseInterface $response)
97
    {
98
        $headers = $response->getHeaders();
99
        if (empty($headers)) {
100
            // this is required to represent empty header set as map and not as array
101
            $headers = new \stdClass();
102
        }
103
104
        $this->worker->send($response->getBody(), json_encode([
105
            'status'  => $response->getStatusCode(),
106
            'headers' => $headers
107
        ]));
108
    }
109
110
   /**
111
     * Returns altered copy of _SERVER variable. Sets ip-address,
112
     * request-time and other values.
113
     *
114
     * @param array $ctx
115
     * @return array
116
     */
117
    protected function configureServer(array $ctx): array
118
    {
119
        $server = $_SERVER;
120
        $server['REQUEST_TIME'] = time();
121
        $server['REQUEST_TIME_FLOAT'] = microtime(true);
122
        $server['REMOTE_ADDR'] = $ctx['attributes']['ipAddress'] ?? $ctx['remoteAddr'] ?? '127.0.0.1';
123
124
        return $server;
125
    }
126
127
    /**
128
     * Wraps all uploaded files with UploadedFile.
129
     *
130
     * @param array $files
131
     *
132
     * @return array
133
     */
134
    private function wrapUploads($files): array
135
    {
136
        if (empty($files)) {
137
            return [];
138
        }
139
140
        $result = [];
141
        foreach ($files as $index => $f) {
142
            if (!isset($f['name'])) {
143
                $result[$index] = $this->wrapUploads($f);
144
                continue;
145
            }
146
147
            $result[$index] = new Diactoros\UploadedFile(
148
                $f['tmpName'],
149
                $f['size'],
150
                $f['error'],
151
                $f['name'],
152
                $f['mime']
153
            );
154
        }
155
156
        return $result;
157
    }
158
}