Passed
Push — master ( 29fe5f...ea361d )
by Oleg
04:43
created

Request   B

Complexity

Total Complexity 42

Size/Duplication

Total Lines 299
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 0

Importance

Changes 10
Bugs 2 Features 0
Metric Value
wmc 42
c 10
b 2
f 0
lcom 2
cbo 0
dl 0
loc 299
rs 8.295

17 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 9 5
A isCli() 0 4 1
A isAjax() 0 4 1
A getMethod() 0 4 1
A getUserIP() 0 4 2
A getBrowser() 0 4 2
C getOption() 0 29 16
A getFiles() 0 4 2
A query() 0 8 2
A setQuery() 0 4 1
A post() 0 4 1
A cookie() 0 4 1
A session() 0 8 2
A unsetSession() 0 6 2
A server() 0 4 1
A requestPayload() 0 4 1
A setSession() 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. 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 Request, and based on these observations, apply Extract Interface, too.

1
<?php /** MicroRequest */
2
3
namespace Micro\Web;
4
5
/**
6
 * Request class file.
7
 *
8
 * @author Oleg Lunegov <[email protected]>
9
 * @link https://github.com/linpax/microphp-framework
10
 * @copyright Copyright &copy; 2013 Oleg Lunegov
11
 * @license /LICENSE
12
 * @package Micro
13
 * @subpackage Web
14
 * @version 1.0
15
 * @since 1.0
16
 */
17
class Request implements IRequest
18
{
19
    /** @var bool $cli Is running as CLI */
20
    protected $cli;
21
22
    /** @var array $get $_GET from request */
23
    protected $get;
24
    /** @var array $data $_POST from request */
25
    protected $data;
26
    /** @var array $files $_FILES from request */
27
    protected $files;
28
    /** @var array $options $_SERVER from request */
29
    protected $options;
30
31
32
    /**
33
     * Constructor Request
34
     *
35
     * @access public
36
     *
37
     * @param array $get
38
     * @param array $post
39
     * @param array $files
40
     * @param array $server
41
     *
42
     * @result void
43
     */
44
    public function __construct(array $get = [], array $post = [], array $files = [], array $server = [])
0 ignored issues
show
Coding Style introduced by
__construct uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
__construct uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
__construct uses the super-global variable $_FILES which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
__construct uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
45
    {
46
        $this->cli = PHP_SAPI === 'cli';
47
48
        $this->get = $get ?: $_GET;
49
        $this->data = $post ?: $_POST;
50
        $this->files = $files ?: $_FILES;
51
        $this->options = $server ?: $_SERVER;
52
    }
53
54
    /**
55
     * Get flag of running as CLI
56
     *
57
     * @access public
58
     *
59
     * @return bool
60
     */
61
    public function isCli()
62
    {
63
        return $this->cli;
64
    }
65
66
    /**
67
     * Check request is AJAX ?
68
     *
69
     * @access public
70
     *
71
     * @return bool
72
     */
73
    public function isAjax()
74
    {
75
        return strtolower(filter_input(INPUT_SERVER, 'HTTP_X_REQUESTED_WITH')) === 'xmlhttprequest';
76
    }
77
78
    /**
79
     * Get request method
80
     *
81
     * @access public
82
     *
83
     * @return string
84
     */
85
    public function getMethod()
86
    {
87
        return filter_input(INPUT_SERVER, 'REQUEST_METHOD');
88
    }
89
90
    /**
91
     * Get user IP-address
92
     *
93
     * @access public
94
     *
95
     * @return string
96
     */
97
    public function getUserIP()
98
    {
99
        return ($ip = filter_input(INPUT_SERVER, 'REMOTE_ADDR')) ? $ip : '127.0.0.1';
100
    }
101
102
    /**
103
     * Get browser data from user user agent string
104
     *
105
     * @access public
106
     *
107
     * @param null|string $agent User agent string
108
     *
109
     * @return mixed
110
     */
111
    public function getBrowser($agent = null)
112
    {
113
        return get_browser($agent ?: filter_input(INPUT_SERVER, 'HTTP_USER_AGENT'), true);
114
    }
115
116
    /**
117
     * Get arguments from command line
118
     *
119
     * @access public
120
     *
121
     * @param string $char -a .. -z option char
122
     * @param string $name --optionName_string
123
     * @param bool|null $required Required value?
124
     *
125
     * @return mixed
126
     */
127
    public function getOption($char = '', $name = '', $required = null)
128
    {
129
        if (!$char && !$name) {
130
            return false;
131
        }
132
133
        if ($char && (1 < strlen($char) || 1 !== preg_match('/^\w$/', $char))) {
134
            return false;
135
        }
136
137
        if ($name && (1 !== preg_match('/^\w+$/', $name))) {
138
            return false;
139
        }
140
141
        switch ($required) {
142
            case true:
143
                $char = $char ? $char.':' : $char;
144
                $name = $name ? $name.':' : $name;
145
                break;
146
            case false:
147
                $char = $char ? $char.'::' : $char;
148
                $name = $name ? $name.'::' : $name;
149
                break;
150
        }
151
152
        $argv = ($opts = getopt($char, [$name])) ? array_shift($opts) : [];
153
154
        return is_array($argv) ? array_shift($argv) : $argv;
155
    }
156
157
    /**
158
     * Get files mapper
159
     *
160
     * @access public
161
     *
162
     * @param string $className Class name of mapper
163
     *
164
     * @return mixed
165
     */
166
    public function getFiles($className = '\Micro\Web\Uploader')
167
    {
168
        return $this->files ? new $className($this->files) : false;
169
    }
170
171
    /**
172
     * Get value by key from query storage
173
     *
174
     * @access public
175
     *
176
     * @param string $name Key name
177
     * @param integer $filter
178
     * @param mixed $options
179
     *
180
     * @return bool
181
     */
182
    public function query($name, $filter = FILTER_DEFAULT, $options = null)
183
    {
184
        if (array_key_exists($name, $this->get)) {
185
            return filter_var($this->get[$name], $filter, $options);
186
        }
187
188
        return null;
189
    }
190
191
    /**
192
     * Set query by key
193
     *
194
     * @access public
195
     *
196
     * @param string $name
197
     * @param string|integer $value
198
     *
199
     * @return void
200
     */
201
    public function setQuery($name, $value)
202
    {
203
        $this->get[$name] = $value;
204
    }
205
206
    /**
207
     * Get value by key from post storage
208
     *
209
     * @access public
210
     *
211
     * @param string $name Key name
212
     * @param integer $filter
213
     * @param mixed $options
214
     *
215
     * @return mixed
216
     */
217
    public function post($name, $filter = FILTER_DEFAULT, $options = null)
218
    {
219
        return filter_input(INPUT_POST, $name, $filter, $options);
220
    }
221
222
    /**
223
     * Get value by key from cookie storage
224
     *
225
     * @access public
226
     *
227
     * @param string $name Key name
228
     * @param integer $filter
229
     * @param mixed $options
230
     *
231
     * @return bool
232
     */
233
    public function cookie($name, $filter = FILTER_DEFAULT, $options = null)
234
    {
235
        return filter_input(INPUT_COOKIE, $name, $filter, $options);
236
    }
237
238
    /**
239
     * Get value by key from session storage
240
     *
241
     * @access public
242
     *
243
     * @param string $name Key name
244
     * @param integer $filter
245
     * @param mixed $options
246
     *
247
     * @return mixed
248
     */
249
    public function session($name, $filter = FILTER_DEFAULT, $options = null)
0 ignored issues
show
Coding Style introduced by
session uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
250
    {
251
        if (array_key_exists($name, $_SESSION)) {
252
            return filter_var($_SESSION[$name], $filter, $options);
253
        }
254
255
        return null;
256
    }
257
258
    /**
259
     * Unset value by key from session storage
260
     *
261
     * @access public
262
     *
263
     * @param string $name Key name
264
     *
265
     * @return void
266
     */
267
    public function unsetSession($name)
0 ignored issues
show
Coding Style introduced by
unsetSession uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
268
    {
269
        if (array_key_exists($name, $_SESSION)) {
270
            unset($_SESSION[$name]);
271
        }
272
    }
273
274
275
    /**
276
     * Get value by key from server storage
277
     *
278
     * @access public
279
     *
280
     * @param string $name Key name
281
     * @param integer $filter
282
     * @param mixed $options
283
     *
284
     * @return bool
285
     */
286
    public function server($name, $filter = FILTER_DEFAULT, $options = null)
287
    {
288
        return filter_input(INPUT_SERVER, $name, $filter, $options);
289
    }
290
291
    /**
292
     * Get RequestPayload (RAW DATA)
293
     *
294
     * @return string|bool
295
     */
296
    public function requestPayload()
297
    {
298
        return file_get_contents('php://input');
299
    }
300
301
    /**
302
     * Set value into session storage
303
     *
304
     * @access public
305
     *
306
     * @param string $name Key name
307
     * @param string $value Key value
308
     *
309
     * @return void
310
     */
311
    public function setSession($name, $value)
0 ignored issues
show
Coding Style introduced by
setSession uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
312
    {
313
        $_SESSION[$name] = $value;
314
    }
315
}
316