Completed
Push — dev ( b1013d...c10904 )
by Jonathan
11s queued 10s
created

HttpRequest::getBody()   C

Complexity

Conditions 7
Paths 8

Size

Total Lines 31
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 7

Importance

Changes 0
Metric Value
cc 7
eloc 17
nc 8
nop 0
dl 0
loc 31
ccs 17
cts 17
cp 1
crap 7
rs 6.7272
c 0
b 0
f 0
1
<?php
2
3
namespace Vectorface\SnappyRouter\Request;
4
5
use Vectorface\SnappyRouter\Exception\InternalErrorException;
6
7
/**
8
 * A class representing an controller-modelled web request.
9
 * @copyright Copyright (c) 2014, VectorFace, Inc.
10
 * @author Dan Bruce <[email protected]>
11
 */
12
class HttpRequest extends AbstractRequest implements HttpRequestInterface
13
{
14
    /** Holds the HTTP verb used in the request */
15
    private $verb;
16
17
    /** Holds the contents of the various inputs ($_GET, $_POST, etc) */
18
    private $input;
19
20
    /** The input stream (stream or location string) */
21
    private $stream;
22
23
    /** Array key for query parameters */
24
    const INPUT_METHOD_QUERY = 'QUERY';
25
    /** Array key for post parameters */
26
    const INPUT_METHOD_POST = 'POST';
27
    /** Array key for input stream body */
28
    const INPUT_METHOD_BODY = 'BODY';
29
30
    // mappings between magic filter strings and the filter functions
31
    private static $filterCallbacks = array(
32
        'int' => 'intval',
33
        'float' => 'floatval',
34
        'trim' => 'trim',
35
        'lower' => 'strtolower',
36
        'upper' => 'strtoupper',
37
        'squeeze' => array(__CLASS__, 'squeeze')
38
    );
39
40
    /**
41
     * Constructor for a request.
42
     * @param string $controller The controller being requested.
43
     * @param string $action The action being invoked.
44
     * @param string $verb The HTTP verb used in the request.
45
     * @param mixed $stream A stream or a string describing a stream location.
46
     */
47 42
    public function __construct($controller, $action, $verb, $stream = 'php://input')
48
    {
49 42
        parent::__construct($controller, $action);
50 42
        $this->setVerb($verb);
51 42
        $this->setStream($stream);
52
53 42
        $this->input = array(
54 42
            self::INPUT_METHOD_QUERY  => array(),
55 42
            self::INPUT_METHOD_POST   => array(),
56 42
            self::INPUT_METHOD_BODY   => null
57 42
        );
58 42
    }
59
60
    /**
61
     * Returns the HTTP verb used in the request.
62
     * @return string The HTTP verb used in the request.
63
     */
64 6
    public function getVerb()
65
    {
66 6
        return $this->verb;
67
    }
68
69
    /**
70
     * Sets the HTTP verb used in the request.
71
     * @param string $verb The HTTP verb used in the request.
72
     * @return RequestInterface Returns $this.
73
     */
74 42
    public function setVerb($verb)
75
    {
76 42
        $this->verb = $verb;
77 42
        return $this;
78
    }
79
80
    /**
81
     * Sets the stream used in the request.
82
     * @param mixed $stream The stream used in the request.
83
     * @return RequestInterface Returns $this.
84
     */
85 42
    public function setStream($stream)
86
    {
87 42
        $this->stream = $stream;
88 42
        return $this;
89
    }
90
91
    /**
92
     * Returns true if the request is a GET request and false otherwise.
93
     * @return bool Returns true if the request is a GET request and false
94
     *         otherwise.
95
     */
96 1
    public function isGet()
97
    {
98 1
        return ('GET' === strtoupper($this->getVerb()));
99
    }
100
101
    /**
102
     * Returns true if the request is a POST request and false otherwise.
103
     * @return bool Returns true if the request is a POST request and false
104
     *         otherwise.
105
     */
106 1
    public function isPost()
107
    {
108 1
        return ('POST' === strtoupper($this->getVerb()));
109
    }
110
111
    /**
112
     * Returns the GET data parameter associated with the specified key.
113
     * @param string $param The GET data parameter.
114
     * @param mixed $defaultValue The default value to use when the key is not present.
115
     * @param mixed $filters The array of filters (or single filter) to apply to the data.
116
     * @return mixed Returns the data from the GET parameter after being filtered (or
117
     *         the default value if the parameter is not present)
118
     */
119 7
    public function getQuery($param, $defaultValue = null, $filters = array())
120
    {
121 7
        return $this->fetchInputValue(
122 7
            $this->input[self::INPUT_METHOD_QUERY],
0 ignored issues
show
Bug introduced by
It seems like $this->input[self::INPUT_METHOD_QUERY] can also be of type null or string; however, Vectorface\SnappyRouter\...uest::fetchInputValue() 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...
123 7
            $param,
124 7
            $defaultValue,
125
            $filters
126 7
        );
127
    }
128
129
    /**
130
     * Sets all the QUERY data for the current request.
131
     * @param array $queryData The query data for the current request.
132
     * @return HttpRequestInterface Returns $this.
133
     */
134 33
    public function setQuery($queryData)
135
    {
136 33
        $this->input[self::INPUT_METHOD_QUERY] = (array)$queryData;
137 33
        return $this;
138
    }
139
140
    /**
141
     * Returns the POST data parameter associated with the specified key.
142
     * @param string $param The POST data parameter.
143
     * @param mixed $defaultValue The default value to use when the key is not present.
144
     * @param mixed $filters The array of filters (or single filter) to apply to the data.
145
     * @return mixed Returns the data from the POST parameter after being filtered (or
146
     *         the default value if the parameter is not present)
147
     */
148 1
    public function getPost($param, $defaultValue = null, $filters = array())
149
    {
150 1
        return $this->fetchInputValue(
151 1
            $this->input[self::INPUT_METHOD_POST],
0 ignored issues
show
Bug introduced by
It seems like $this->input[self::INPUT_METHOD_POST] can also be of type null or string; however, Vectorface\SnappyRouter\...uest::fetchInputValue() 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...
152 1
            $param,
153 1
            $defaultValue,
154
            $filters
155 1
        );
156
    }
157
158
    /**
159
     * Sets all the POST data for the current request.
160
     * @param array $postData The post data for the current request.
161
     * @return HttpRequestInterface Returns $this.
162
     */
163 27
    public function setPost($postData)
164
    {
165 27
        $this->input[self::INPUT_METHOD_POST] = (array)$postData;
166 27
        return $this;
167
    }
168
169
    /**
170
     * Returns the input stream data for the current request
171
     * @return string The input stream data
172
     */
173 3
    public function getBody()
174
    {
175
        // If this value has been read from the stream, retrieve it from storage
176 3
        if (null !== $this->input[self::INPUT_METHOD_BODY]) {
177 1
            return $this->input[self::INPUT_METHOD_BODY];
178
        }
179
180 3
        if (is_resource($this->stream) && 'stream' === get_resource_type($this->stream)) {
181 1
            $streamData = stream_get_contents($this->stream);
182 3
        } elseif (is_string($this->stream)) {
183 2
            $stream = @fopen($this->stream, "r");
184
185 2
            if (false === $stream) {
186 1
                throw new InternalErrorException('Unable to open request input stream.');
187
            }
188
189 1
            $streamData = stream_get_contents($stream);
190
191 1
            fclose($stream);
192 1
        } else {
193 1
            $streamData = false;
194
        }
195
196 2
        if (false === $streamData) {
197 1
            throw new InternalErrorException('Unable to open request input stream.');
198
        }
199
200 1
        $this->input[self::INPUT_METHOD_BODY] = $streamData;
201
202 1
        return $this->input[self::INPUT_METHOD_BODY];
203
    }
204
205
    /**
206
     * Returns an array of all the input parameters from the query and post data.
207
     * @return array An array of all input.
208
     */
209 1
    public function getAllInput()
210
    {
211 1
        return array_merge(
212 1
            $this->input[self::INPUT_METHOD_QUERY],
213 1
            $this->input[self::INPUT_METHOD_POST]
214 1
        );
215
    }
216
217
    /**
218
     * Fetches the input value from the given array, or the default value. Also
219
     * applies any requested filters.
220
     * @param array $array The array ($_POST, $_GET, $params, etc).
221
     * @param string $param The array key to lookup.
222
     * @param mixed $defaultValue The default value to use if the key is not
223
     *        found in the array.
224
     * @param mixed $filters The array of input filters to apply (or single filter).
225
     * @return mixed Returns the value filtered (or the default value filtered).
226
     */
227 7
    private function fetchInputValue($array, $param, $defaultValue, $filters)
228
    {
229 7
        $value = isset($array[$param]) ? $array[$param] : $defaultValue;
230 7
        return $this->applyInputFilters($value, is_array($filters) ? $filters : array($filters));
231
    }
232
233
    /**
234
     * Applies the array of filters against the input value.
235
     * @param string $value The input value.
236
     * @param array $filters The array of filters.
237
     * @return string Returns the value after the filters have been applied.
238
     */
239 7
    private function applyInputFilters($value, $filters)
240
    {
241 7
        foreach ($filters as $filter) {
242 7
            if (is_string($filter) && isset(self::$filterCallbacks[$filter])) {
243 7
                $value = call_user_func(self::$filterCallbacks[$filter], $value);
244 7
            }
245 7
        }
246 7
        return $value;
247
    }
248
249
    /**
250
     * Takes a string and removes empty lines.
251
     * @param string $string The input string.
252
     * @return string Returns the string with empty lines removed.
253
     */
254 1
    private static function squeeze($string)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
255
    {
256 1
        return implode(
257 1
            PHP_EOL,
258 1
            array_filter(
259 1
                array_map(
260 1
                    'trim',
261 1
                    explode(PHP_EOL, $string)
262 1
                ),
263
                'strlen'
264 1
            )
265 1
        );
266
    }
267
}
268