Completed
Push — master ( 579110...b52e58 )
by Pierre
02:10
created

Request   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 342
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 94
c 3
b 0
f 0
dl 0
loc 342
rs 8.96
wmc 43

25 Methods

Rating   Name   Duplication   Size   Complexity  
A getContentType() 0 3 1
A isCli() 0 3 1
A getMethod() 0 5 2
A getIp() 0 3 1
A getServer() 0 5 2
A setHeaders() 0 6 2
A getRoute() 0 3 1
A setParam() 0 4 1
A setIsCli() 0 7 2
A getHeaders() 0 3 1
A getArgs() 0 5 2
A getFilename() 0 3 1
A setContentType() 0 6 2
A getAcceptEncoding() 0 6 2
A getInput() 0 13 3
A __construct() 0 14 2
A getUri() 0 5 2
A getParams() 0 3 1
A setParams() 0 18 6
A getHost() 0 3 1
A isJsonContentType() 0 6 1
A getHeaderManager() 0 3 1
A getParam() 0 5 2
A getCliParams() 0 9 2
A setMethod() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Request 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.

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 Request, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace App\Http;
4
5
use App\Http\Interfaces\IRequest;
6
use App\Http\Interfaces\IHeaders;
7
use App\Http\Session;
8
9
class Request extends Session implements IRequest
10
{
11
12
    protected $server;
13
    protected $method;
14
    protected $contentType;
15
    protected $isCli;
16
    protected $params;
17
18
    /**
19
     * headers list
20
     *
21
     * @var Headers
22
     */
23
    protected $headerManager;
24
25
    /**
26
     * instanciate
27
     */
28
    public function __construct()
29
    {
30
        $sapiName = php_sapi_name();
31
        $this->setIsCli(
32
            $sapiName == self::_CLI
33
                || $sapiName == self::_CLID
34
        );
35
        $this->headerManager = new Headers();
36
        $this->server = $_SERVER;
37
        $this->method = $this->getMethod();
38
        $this->setContentType(self::APPLICATION_JSON);
39
        $this->setParams();
40
        parent::__construct();
41
        $this->setHeaders();
42
    }
43
44
    /**
45
     * returns header manager
46
     *
47
     * @return Headers
48
     */
49
    public function getHeaderManager(): Headers
50
    {
51
        return $this->headerManager;
52
    }
53
54
    /**
55
     * returns http method
56
     *
57
     * @return string
58
     */
59
    public function getMethod(): string
60
    {
61
        return ($this->isCli)
62
            ? self::METHOD_TRACE
63
            : $this->getServer(self::REQUEST_METHOD);
64
    }
65
66
    /**
67
     * returns http param for a given key
68
     *
69
     * @return array
70
     */
71
    public function getParams(): array
72
    {
73
        return $this->params;
74
    }
75
76
    /**
77
     * returns http param for a given key
78
     *
79
     * @return array
80
     */
81
    public function getParam(string $key): string
82
    {
83
        return isset($this->params[$key])
0 ignored issues
show
Bug Best Practice introduced by
The expression return IssetNode ? $this->params[$key] : '' also could return the type string which is incompatible with the documented return type array.
Loading history...
84
            ? $this->params[$key]
85
            : '';
86
    }
87
88
    /**
89
     * returns active route
90
     *
91
     * @return string
92
     */
93
    public function getRoute(): string
94
    {
95
        return $this->getServer(self::SCRIPT_URL);
96
    }
97
98
    /**
99
     * return php script filename
100
     *
101
     * @return string
102
     */
103
    public function getFilename(): string
104
    {
105
        return $this->getServer(self::SCRIPT_FILENAME);
106
    }
107
108
    /**
109
     * return request uri
110
     *
111
     * @return string
112
     */
113
    public function getUri(): string
114
    {
115
        return ($this->isCli())
116
            ? $this->getArgs()
117
            : $this->getServer(self::REQUEST_URI);
118
    }
119
120
    /**
121
     * return request host
122
     *
123
     * @return string
124
     */
125
    public function getHost(): string
126
    {
127
        return $this->getServer(self::HTTP_HOST);
128
    }
129
130
    /**
131
     * return request client ip
132
     *
133
     * @return string
134
     */
135
    public function getIp(): string
136
    {
137
        return $this->getServer(self::REMOTE_ADDR);
138
    }
139
140
    /**
141
     * return request content type
142
     *
143
     * @return string
144
     */
145
    public function getContentType(): string
146
    {
147
        return $this->contentType;
148
    }
149
150
    /**
151
     * return request accept encoding
152
     *
153
     * @return string
154
     */
155
    public function getAcceptEncoding(): string
156
    {
157
        $headers = $this->getHeaders();
158
        return isset($headers[IHeaders::ACCEPT_ENCODING])
159
            ? $headers[IHeaders::ACCEPT_ENCODING]
160
            : '';
161
    }
162
163
    /**
164
     * return request headers
165
     *
166
     * @return array
167
     */
168
    public function getHeaders(): array
169
    {
170
        return $this->headerManager->get();
171
    }
172
173
    /**
174
     * return request headers
175
     *
176
     * @return array
177
     */
178
    protected function setHeaders(): Request
179
    {
180
        $this->headerManager->addMany(
181
            $this->isCli ? [] : getallheaders()
0 ignored issues
show
Bug introduced by
It seems like $this->isCli ? array() : getallheaders() can also be of type false; however, parameter $headers of App\Http\Headers::addMany() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

181
            /** @scrutinizer ignore-type */ $this->isCli ? [] : getallheaders()
Loading history...
182
        );
183
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type App\Http\Request which is incompatible with the documented return type array.
Loading history...
184
    }
185
186
    /**
187
     * build uri from cli args
188
     *
189
     * @return void
190
     */
191
    protected function getArgs(): string
192
    {
193
        return isset($this->server[self::_ARGV][1])
0 ignored issues
show
Bug Best Practice introduced by
The expression return IssetNode ? $this...er[self::_ARGV][1] : '' also could return the type string which is incompatible with the documented return type void.
Loading history...
194
            ? $this->server[self::_ARGV][1]
195
            : '';
196
    }
197
198
    /**
199
     * return server value for a given key
200
     *
201
     * @param string $key
202
     * @return string
203
     */
204
    protected function getServer(string $key): string
205
    {
206
        return (isset($this->server[$key]))
207
            ? $this->server[$key]
208
            : '';
209
    }
210
211
    /**
212
     * isJsonAppContentType
213
     *
214
     * @return bool
215
     */
216
    protected function isJsonContentType(): bool
217
    {
218
        return strpos(
219
            strtolower($this->contentType),
220
            self::APPLICATION_JSON
221
        ) !== false;
222
    }
223
224
    /**
225
     * getInput
226
     *
227
     * @return array
228
     */
229
    protected function getInput(): array
230
    {
231
        $input = [];
232
        $inputContent = file_get_contents('php://input');
233
        if ($this->isJsonContentType()) {
234
            $input = json_decode($inputContent, true);
235
            if (json_last_error() !== 0) {
236
                $input = [];
237
            }
238
        } else {
239
            parse_str($inputContent, $input);
240
        }
241
        return $input;
242
    }
243
244
    /**
245
     * set method
246
     * essentially for testing purposes
247
     *
248
     * @param string $method
249
     * @return Request
250
     */
251
    protected function setMethod(string $method): Request
252
    {
253
        $this->method = $method;
254
        return $this;
255
    }
256
257
    /**
258
     * set true if we are running from cli
259
     * essentially for testing purposes
260
     *
261
     * @param boolean $isCli
262
     * @return Request
263
     */
264
    protected function setIsCli(bool $isCli): Request
265
    {
266
        $this->isCli = $isCli;
267
        if (false === $this->isCli()) {
268
            $this->startSession($this->getFilename());
269
        }
270
        return $this;
271
    }
272
273
    /**
274
     * return true id sapi mode
275
     * essentially for testing purposes
276
     *
277
     * @return boolean
278
     */
279
    public function isCli(): bool
280
    {
281
        return $this->isCli;
282
    }
283
284
    /**
285
     * set content type
286
     *
287
     * @param string $contentType
288
     * @return Request
289
     */
290
    protected function setContentType(string $contentType = ''): Request
291
    {
292
        $this->contentType = (empty($contentType))
293
            ? $this->getServer(IHeaders::CONTENT_TYPE)
294
            : $contentType;
295
        return $this;
296
    }
297
298
    /**
299
     * get params in cli mode
300
     *
301
     * @return array
302
     */
303
    protected function getCliParams(): array
304
    {
305
        $params = $this->getInput();
306
        if ($this->isCli) {
307
            $queryString = parse_url($this->getArgs(), PHP_URL_QUERY);
308
            parse_str($queryString, $queryParams);
309
            $params = array_merge($params, $queryParams);
310
        }
311
        return $params;
312
    }
313
314
    /**
315
     * set an entry in params for key value
316
     *
317
     * @param string $key
318
     * @param string $value
319
     * @return Request
320
     */
321
    protected function setParam(string $key, string $value): Request
322
    {
323
        $this->params[$key] = $value;
324
        return $this;
325
    }
326
327
    /**
328
     * set http params
329
     *
330
     * @param array $params
331
     * @return Request
332
     */
333
    protected function setParams(array $params = []): Request
334
    {
335
        if ($params) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $params of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
336
            $this->params = $params;
337
            return $this;
338
        }
339
        if ($this->method === self::METHOD_GET) {
340
            $this->params = $_GET;
341
        } elseif ($this->method === self::METHOD_POST) {
342
            $this->params = ($this->isJsonContentType())
343
                ? $this->getInput()
344
                : $_POST;
345
        } elseif ($this->method === self::METHOD_TRACE) {
346
            $this->params = $this->getCliParams();
347
        } else {
348
            $this->params =  $this->getInput();
349
        }
350
        return $this;
351
    }
352
}
353