Completed
Push — master ( fbf566...079bfa )
by Michal
03:01 queued 01:16
created

ConsoleRequest   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 220
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 72%

Importance

Changes 0
Metric Value
wmc 44
lcom 1
cbo 4
dl 0
loc 220
ccs 90
cts 125
cp 0.72
rs 8.8798
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
F makeRequest() 0 96 19
C processValues() 0 48 13
A processParam() 0 21 5
A normalizeValues() 0 17 6

How to fix   Complexity   

Complex Class

Complex classes like ConsoleRequest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ConsoleRequest, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Tomaj\NetteApi\Misc;
6
7
use Nette\Http\FileUpload;
8
use Tomaj\NetteApi\EndpointInterface;
9
use Tomaj\NetteApi\Handlers\ApiHandlerInterface;
10
use Tomaj\NetteApi\Link\ApiLink;
11
use Tomaj\NetteApi\Params\InputParam;
12
use Tomaj\NetteApi\Params\ParamInterface;
13
14
class ConsoleRequest
15
{
16
    /** @var ApiHandlerInterface */
17
    private $handler;
18
19
    /** @var EndpointInterface|null */
20
    private $endpoint;
21
22
    /** @var ApiLink|null */
23
    private $apiLink;
24
25 3
    public function __construct(ApiHandlerInterface $handler, ?EndpointInterface $endpoint = null, ?ApiLink $apiLink = null)
26
    {
27 3
        $this->handler = $handler;
28 3
        $this->endpoint = $endpoint;
29 3
        $this->apiLink = $apiLink;
30 3
    }
31
32 3
    public function makeRequest(string $url, string $method, array $values, array $additionalValues = [], ?string $token = null): ConsoleResponse
33
    {
34 3
        list($postFields, $getFields, $cookieFields, $rawPost, $putFields) = $this->processValues($values);
35
36 3
        $postFields = array_merge($postFields, $additionalValues['postFields'] ?? []);
37 3
        $getFields = array_merge($getFields, $additionalValues['getFields'] ?? []);
38 3
        $cookieFields = array_merge($cookieFields, $additionalValues['cookieFields'] ?? []);
39 3
        $putFields = array_merge($putFields, $additionalValues['putFields'] ?? []);
40
41 3
        $postFields = $this->normalizeValues($postFields);
42 3
        $getFields = $this->normalizeValues($getFields);
43 3
        $putFields = $this->normalizeValues($putFields);
44
45 3
        if ($this->endpoint && $this->apiLink) {
46
            $url = $this->apiLink->link($this->endpoint, $getFields);
47 3
        } elseif (count($getFields)) {
48 3
            $parts = [];
49 3
            foreach ($getFields as $key => $value) {
50 3
                $parts[] = "$key=$value";
51
            }
52 3
            $url = $url . '?' . implode('&', $parts);
53
        }
54
55 3
        $putRawPost = null;
56 3
        if (count($putFields)) {
57
            $parts = [];
58
            foreach ($putFields as $key => $value) {
59
                $parts[] = "$key=$value";
60
            }
61
            $putRawPost = implode('&', $parts);
62
        }
63
64 3
        $startTime = microtime(true);
65
66 3
        $curl = curl_init();
67 3
        curl_setopt($curl, CURLOPT_URL, $url);
68 3
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
69 3
        curl_setopt($curl, CURLOPT_NOBODY, false);
70 3
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
71 3
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
72 3
        curl_setopt($curl, CURLOPT_VERBOSE, false);
73 3
        curl_setopt($curl, CURLOPT_TIMEOUT, $additionalValues['timeout'] ?? 30);
74 3
        curl_setopt($curl, CURLOPT_HEADER, true);
75
76 3
        if (count($postFields) || $rawPost || $putRawPost !== null) {
77
            curl_setopt($curl, CURLOPT_POST, true);
78
            curl_setopt($curl, CURLOPT_POSTFIELDS, count($postFields) ? $postFields : ($rawPost ?: $putRawPost));
79
        }
80
81 3
        $headers = $additionalValues['headers'] ?? [];
82 3
        if (count($cookieFields)) {
83
            $parts = [];
84
            foreach ($cookieFields as $key => $value) {
85
                $parts[] = "$key=$value";
86
            }
87
            $headers[] = "Cookie: " . implode('&', $parts);
88
        }
89 3
        if ($token !== null && $token !== false) {
90
            $headers[] = 'Authorization: Bearer ' . $token;
91
        }
92 3
        if (count($headers)) {
93
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
94
        }
95
96 3
        $consoleResponse = new ConsoleResponse(
97 3
            $url,
98 2
            $method,
99 2
            $postFields,
100 2
            $getFields,
101 2
            $cookieFields,
102 2
            $headers,
103 2
            $rawPost
104
        );
105
106 3
        $response = curl_exec($curl);
107 3
        $elapsed = intval((microtime(true) - $startTime) * 1000);
108
109 3
        if ($response === false) {
110 3
            $response = '';
111
        }
112
113 3
        $headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
114 3
        $responseHeaders = substr($response, 0, $headerSize);
115 3
        $responseBody = substr($response, $headerSize);
116
117 3
        $curlErrorNumber = curl_errno($curl);
118 3
        $curlError = curl_error($curl);
119 3
        if ($curlErrorNumber > 0) {
120 3
            $consoleResponse->logError($curlErrorNumber, $curlError, $elapsed);
121
        } else {
122
            $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
123
            $consoleResponse->logRequest($httpCode, $responseBody, $responseHeaders, $elapsed);
124
        }
125
126 3
        return $consoleResponse;
127
    }
128
129
    /**
130
     * Process given values to POST and GET fields
131
     *
132
     * @param array $values
133
     *
134
     * @return array
135
     */
136 3
    private function processValues(array $values): array
137
    {
138 3
        $params = $this->handler->params();
139
140 3
        $postFields = [];
141 3
        $rawPost = isset($values['post_raw']) ? $values['post_raw'] : null;
142 3
        $getFields = [];
143 3
        $putFields = [];
144 3
        $cookieFields = [];
145
146 3
        foreach ($values as $key => $value) {
147 3
            if (strstr($key, '___') !== false) {
148
                $parts = explode('___', $key);
149
                $key = $parts[0];
150
            }
151
152 3
            foreach ($params as $param) {
153 3
                $valueData = $this->processParam($param, $key, $value);
154 3
                if ($valueData === null) {
155 3
                    continue;
156
                }
157
158 3
                if ($param->isMulti()) {
159
                    if (in_array($param->getType(), [InputParam::TYPE_POST, InputParam::TYPE_FILE])) {
160
                        $postFields[$key][] = $valueData;
161
                    } elseif ($param->getType() === InputParam::TYPE_PUT) {
162
                        $putFields[$key][] = $valueData;
163
                    } elseif ($param->getType() === InputParam::TYPE_COOKIE) {
164
                        $cookieFields[$key][] = $valueData;
165
                    } else {
166
                        $getFields[$key][] = urlencode($valueData);
167
                    }
168
                } else {
169 3
                    if (in_array($param->getType(), [InputParam::TYPE_POST, InputParam::TYPE_FILE])) {
170
                        $postFields[$key] = $valueData;
171 3
                    } elseif ($param->getType() === InputParam::TYPE_PUT) {
172
                        $putFields[$key] = $valueData;
173 3
                    } elseif ($param->getType() === InputParam::TYPE_COOKIE) {
174
                        $cookieFields[$key] = $valueData;
175
                    } else {
176 3
                        $getFields[$key] = urlencode($valueData);
177
                    }
178
                }
179
            }
180
        }
181
182 3
        return [$postFields, $getFields, $cookieFields, $rawPost, $putFields];
183
    }
184
185
    /**
186
     * Process one param and returns value
187
     *
188
     * @param ParamInterface  $param   input param
189
     * @param string          $key     param key
190
     * @param mixed           $value   actual value from request
191
     *
192
     * @return mixed
193
     */
194 3
    private function processParam(ParamInterface $param, string $key, $value)
195
    {
196 3
        if ($param->getKey() === $key) {
197 3
            $valueData = $value;
198
199 3
            if ($param->getType() === InputParam::TYPE_FILE) {
200
                /** @var FileUpload $file */
201
                $file = $value;
202
                if ($file->isOk()) {
203
                    $valueData = curl_file_create($file->getTemporaryFile(), $file->getContentType(), $file->getName());
204
                } else {
205
                    $valueData = false;
206
                }
207 3
            } elseif ($param->getType() === InputParam::TYPE_POST_RAW) {
208
                $valueData = file_get_contents('php://input');
209
            }
210
211 3
            return $valueData;
212
        }
213 3
        return null;
214
    }
215
216 3
    private function normalizeValues(array $values): array
217
    {
218 3
        $result = [];
219 3
        foreach ($values as $key => $value) {
220 3
            if (!is_array($value)) {
221 3
                $result[$key] = $value;
222 3
                continue;
223
            }
224
225
            foreach ($value as $innerKey => $innerValue) {
226
                if ($innerValue !== '' && $innerValue !== null) {
227
                    $result[$key . "[" . $innerKey . "]"] = $innerValue;
228
                }
229
            }
230
        }
231 3
        return $result;
232
    }
233
}
234