Completed
Push — develop ( a05ff5...d1fb89 )
by Vladimir
03:27
created

UrlQuery::setPostFields()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2.0185

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 13
ccs 5
cts 6
cp 0.8333
rs 9.4285
cc 2
eloc 6
nc 2
nop 2
crap 2.0185
1
<?php
2
3
/**
4
 * This file contains the UrlQuery class which is a wrapper for cURL
5
 *
6
 * @copyright 2015 Vladimir Jimenez
7
 * @license   https://github.com/allejo/PhpPulse/blob/master/LICENSE.md MIT
8
 */
9
10
namespace allejo\DaPulse\Utilities;
11
12
use allejo\DaPulse\Exceptions\CurlException;
13
use allejo\DaPulse\Exceptions\HttpException;
14
15
/**
16
 * A wrapper class for working with cURL requests.
17
 *
18
 * This class configures cURL with all of the appropriate authentication information and proper cURL configuration for
19
 * processing requests.
20
 *
21
 * This class is provided as a convenience for all of the URL requests made by PhpPulse. This class may also be used
22
 * by external tools to make custom requests.
23
 *
24
 * @api
25
 * @package allejo\DaPulse\Utilities
26
 * @since   0.1.0
27
 */
28
class UrlQuery
29
{
30
    /**
31
     * Send a POST or PUT body as JSON instead of URL encoded values
32
     */
33
    const BODY_AS_JSON = 0x1;
34
35
    /**
36
     * The API endpoint that will be used in all requests
37
     *
38
     * @var string
39
     */
40
    private $url;
41
42
    /**
43
     * The cURL object this class is a wrapper for
44
     *
45
     * @var resource
46
     */
47
    private $cURL;
48
49
    /**
50
     * Configure all of the authentication needed for cURL requests and the API endpoint
51
     *
52
     * @param string $url       The API endpoint this instance will be calling
53
     * @param array  $urlParams Parameters that will be appended to the URL as GET parameters
54
     *
55
     * @since 0.1.0
56
     */
57 46
    public function __construct ($url, $urlParams)
58
    {
59 46
        $this->url  = $url . "?" . self::formatParameters($urlParams);
60 46
        $this->cURL = curl_init();
61
62 46
        $this->configureCurl();
63 46
    }
64
65
    /**
66
     * Clean up after ourselves; clean up the cURL object.
67
     */
68 46
    public function __destruct ()
69
    {
70 46
        curl_close($this->cURL);
71 46
    }
72
73
    /**
74
     * Set the credentials for basic authentication
75
     *
76
     * @param string $username The username basic authentication
77
     * @param string $password The password basic authentication
78
     *
79
     * @since 0.1.0
80
     *
81
     * @throws \InvalidArgumentException Either the username or the password was an empty or null string
82
     */
83
    public function setAuthentication ($username, $password)
84
    {
85
        if (StringUtilities::isNullOrEmpty($username) || StringUtilities::isNullOrEmpty($password))
86
        {
87
            throw new \InvalidArgumentException("Both the username and password must be non-empty strings.");
88
        }
89
90
        curl_setopt_array($this->cURL, array(
91
            CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
92
            CURLOPT_USERPWD  => $username . ":" . $password
93
        ));
94
    }
95
96
    /**
97
     * Set cURL headers
98
     *
99
     * @param array $headers The headers that will be sent with cURL
100
     *
101
     * @since 0.1.0
102
     *
103
     * @throws \InvalidArgumentException The $headers parameter was not an array or it was an empty array
104
     */
105
    public function setHeaders ($headers)
106
    {
107
        if (empty($headers) || !is_array($headers))
108
        {
109
            throw new \InvalidArgumentException("The headers parameter must be a non-empty array");
110
        }
111
112
        curl_setopt_array($this->cURL, array(
113
            CURLOPT_HEADER     => true,
114
            CURLOPT_HTTPHEADER => $headers
115
        ));
116
    }
117
118
    /**
119
     * Send a GET request
120
     *
121
     * @since  0.1.0
122
     *
123
     * @return mixed  An associative array matching the returned JSON result
124
     */
125 46
    public function sendGet ()
126
    {
127 46
        return $this->handleQuery();
128
    }
129
130
    /**
131
     * Send a POST request
132
     *
133
     * @param  array    $postArray The data that will be sent to DaPulse
134
     * @param  null|int $flags     Available flags: BODY_AS_JSON
135
     *
136
     * @since  0.1.0
137
     *
138
     * @throws HttpException
139
     *
140
     * @return mixed An associative array matching the returned JSON result
141
     */
142
    public function sendPost ($postArray, $flags = null)
143
    {
144
        $this->setPostFields($postArray, $flags);
0 ignored issues
show
Documentation introduced by
$postArray is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
145
146
        curl_setopt_array($this->cURL, array(
147
            CURLOPT_POST          => true,
148
            CURLOPT_CUSTOMREQUEST => "POST"
149
        ));
150
151
        return $this->handleQuery();
152
    }
153
154
    /**
155
     * Send a PUT request
156
     *
157
     * @param  array    $postArray The data that will be sent to DaPulse
158
     * @param  null|int $flags     Available flags: BODY_AS_JSON
159
     *
160
     * @since  0.1.0
161
     *
162
     * @return mixed  An associative array matching the returned JSON result
163
     */
164 7
    public function sendPut ($postArray, $flags = null)
165
    {
166 7
        $this->setPostFields($postArray, $flags);
0 ignored issues
show
Documentation introduced by
$postArray is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
167
168 7
        curl_setopt($this->cURL, CURLOPT_CUSTOMREQUEST, "PUT");
169
170 7
        return $this->handleQuery();
171
    }
172
173
    /**
174
     * Send a DELETE request
175
     *
176
     * @since  0.1.0
177
     *
178
     * @return mixed  An associative array matching the returned JSON result
179
     */
180
    public function sendDelete ()
181
    {
182
        curl_setopt($this->cURL, CURLOPT_CUSTOMREQUEST, "DELETE");
183
184
        return $this->handleQuery();
185
    }
186
187
    /**
188
     * Set the POST fields that will be submitted in the cURL request
189
     *
190
     * @param string   $postArray The POST fields that will be sent to DaPulse
191
     * @param null|int $flags     Available flags: BODY_AS_JSON
192
     *
193
     * @since 0.1.0
194
     */
195 7
    private function setPostFields ($postArray, $flags)
196
    {
197 7
        if ($flags & self::BODY_AS_JSON)
198
        {
199
            $postData = json_encode($postArray);
200
        }
201
        else
202
        {
203 7
            $postData = self::formatParameters($postArray);
0 ignored issues
show
Documentation introduced by
$postArray is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
204
        }
205
206 7
        curl_setopt($this->cURL, CURLOPT_POSTFIELDS, $postData);
207 7
    }
208
209
    /**
210
     * Handle the execution of the cURL request. This function will also save the returned HTTP headers and handle them
211
     * appropriately.
212
     *
213
     * @since  0.1.0
214
     *
215
     * @throws CurlException If cURL is misconfigured or encounters an error
216
     * @throws HttpException An HTTP status of something other 200 is returned
217
     *
218
     * @return mixed
219
     */
220 46
    private function handleQuery ()
221
    {
222 46
        $result   = $this->executeCurl();
223 46
        $httpCode = curl_getinfo($this->cURL, CURLINFO_HTTP_CODE);
224
225 46
        if ($httpCode != 200 && $httpCode != 201)
226
        {
227 1
            throw new HttpException($httpCode, $result);
228
        }
229
230 46
        return json_decode($result, true);
231
    }
232
233
    /**
234
     * Configure the cURL instance and its credentials for Basic Authentication that this instance will be working with
235
     *
236
     * @since 0.1.0
237
     */
238 46
    private function configureCurl ()
239
    {
240 46
        curl_setopt_array($this->cURL, array(
241 46
            CURLOPT_URL            => $this->url,
242 46
            CURLOPT_RETURNTRANSFER => true
243
        ));
244 46
    }
245
246
    /**
247
     * Execute the finalized cURL object that has already been configured
248
     *
249
     * @since  0.1.0
250
     *
251
     * @throws \allejo\DaPulse\Exceptions\CurlException If cURL is misconfigured or encounters an error
252
     *
253
     * @return mixed
254
     */
255 46
    private function executeCurl ()
256
    {
257 46
        $result = curl_exec($this->cURL);
258
259 46
        if (!$result)
260
        {
261
            throw new CurlException($this->cURL);
262
        }
263
264 46
        return $result;
265
    }
266
267
    /**
268
     * Format an array into a URL encoded values to be submitted in cURL requests
269
     *
270
     * **Input**
271
     *
272
     * ```php
273
     * array(
274
     *     "foo"   => "bar",
275
     *     "param" => "value"
276
     * )
277
     * ```
278
     *
279
     * **Output**
280
     *
281
     * ```php
282
     * array(
283
     *     "foo=bar",
284
     *     "param=value"
285
     * )
286
     * ```
287
     *
288
     * @param  array $params An array containing parameter names as keys and parameter values as values in the array.
289
     *
290
     * @since  0.1.0
291
     *
292
     * @return string         A URL encoded and combined array of GET or POST parameters to be sent
293
     */
294 46
    private static function formatParameters ($params)
295
    {
296 46
        $parameters = array();
297
298 46
        foreach ($params as $key => $value)
299
        {
300 46
            if (is_null($value))
301
            {
302
                continue;
303
            }
304 46
            else if (is_bool($value))
305
            {
306
                $value = StringUtilities::booleanLiteral($value);
307
            }
308 46
            else if (is_array($value))
309
            {
310
                $formattedArray = self::formatArray($key, $value);
311
                $parameters[]   = self::formatParameters($formattedArray);
312
313
                continue;
314
            }
315
316 46
            $parameters[] = rawurlencode($key) . "=" . rawurlencode($value);
317
        }
318
319 46
        return implode("&", $parameters);
320
    }
321
322
    /**
323
     * Convert an indexed array into an array that can be feed to `formatParameters()` to be formatted to an acceptable
324
     * structure to be sent via a GET or POST request.
325
     *
326
     * **Input**
327
     *
328
     * ```php
329
     * array(
330
     *     "first",
331
     *     "second",
332
     *     "third"
333
     * )
334
     * ```
335
     *
336
     * **Output**
337
     *
338
     * ```php
339
     * array(
340
     *     "prefix[0]" => "first",
341
     *     "prefix[1]" => "second",
342
     *     "prefix[2]" => "third",
343
     * )
344
     * ```
345
     *
346
     * @param  string   $prefix The name of the
347
     * @param  string[] $array
348
     *
349
     * @see    formatParameters()
350
     *
351
     * @since  0.1.0
352
     *
353
     * @return array
354
     */
355
    private static function formatArray ($prefix, $array)
356
    {
357
        $parameters = array();
358
359
        foreach ($array as $key => $value)
360
        {
361
            $arrayKey              = sprintf("%s[%s]", $prefix, $key);
362
            $parameters[$arrayKey] = $value;
363
        }
364
365
        return $parameters;
366
    }
367
}
368