Completed
Push — master ( 990e98...abd222 )
by Benjamin
02:12
created

Request::__clone()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 2
eloc 3
nc 2
nop 0
1
<?php
2
3
namespace CurlX;
4
5
/**
6
 * Class Request
7
 * @package CurlX
8
 *
9
 * @property string $url url of the Request
10
 * @property array $post_data array of post data
11
 * @property float $total_time running time of the request
12
 * @property int $timeout time (in msec) after which the request will be aborted
13
 * @property array $options cUrl options of the request
14
 * @property array $headers headers of the request
15
 * @property resource $handle cUrl handle of the request
16
 * @property callable[] $listeners array of registered listeners which will be called upon when request finishes
17
 * @property mixed $response curl's response
18
 * @property mixed $result curl result
19
 */
20
class Request implements RequestInterface
21
{
22
    protected $url;
23
    protected $post = [];
24
    protected $result;
25
    protected $listeners = [];
26
    protected $timeout;
27
    protected $curlHandle;
28
    protected $headers = [];
29
    protected $options = [];
30
    protected $success;
31
    protected $response;
32
33
    /**
34
     * Camelizes a string
35
     * @param string $str string to camelize
36
     * @return string camelized string
37
     */
38
    public static function camelize($str)
39
    {
40
        return str_replace('_', '', ucwords($str, '_'));
41
    }
42
43
    /**
44
     * Magic setter function
45
     * @param string $name attribute to set
46
     * @param mixed $value the new value
47
     * @return void
48
     */
49 View Code Duplication
    public function __set($name, $value)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
50
    {
51
        $c = static::camelize($name);
52
        $m = "set$c";
53
        if (method_exists($this, $m)) {
54
            $this->$m($value);
55
        } else {
56
            user_error("undefined property $name");
57
        }
58
    }
59
60
    /**
61
     * Magic getter function
62
     * @param string $name of the attribute to get
63
     * @return mixed the attribute's value
64
     */
65 View Code Duplication
    public function __get($name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
66
    {
67
        $c = static::camelize($name);
68
        $m = "get$c";
69
        if (method_exists($this, $m)) {
70
            return $this->$m();
71
        } else {
72
            user_error("undefined property $name");
73
        }
74
    }
75
76
    /**
77
     * Request constructor.
78
     * @param string $url optional url
79
     */
80
    public function __construct($url = null)
81
    {
82
        $this->setUrl($url);
83
84
        // Defaults
85
        $this->options[CURLOPT_RETURNTRANSFER] = true;
86
        $this->options[CURLOPT_NOSIGNAL] = 1;
87
        $this->options[CURLOPT_FOLLOWLOCATION] = true;
88
    }
89
90
    public function __destruct()
91
    {
92
        if(isset($this->handle)) {
93
            curl_close($this->handle);
94
        }
95
    }
96
97
    /**
98
     * Clone the object
99
     */
100
    public function __clone()
101
    {
102
        if(isset($this->handle)) {
103
            $this->handle = curl_copy_handle($this->handle);
104
        }
105
    }
106
107
    /**
108
     * Normalize an array
109
     * change from ['key' => 'value'] format to ['key: value']
110
     * @param array $array array to normalize
111
     * @return array normalized array
112
     */
113
    protected function normalize(array $array)
114
    {
115
        $normalized = [];
116
        foreach ($array as $key => $value) {
117
            if (is_string($key)) {
118
                $normalized[] = $key . ': ' . $value;
119
            } else {
120
                $normalized[] = $value;
121
            }
122
        }
123
        return $normalized;
124
    }
125
126
    /**
127
     * Setter for the url field
128
     * @param string $url url
129
     * @return void
130
     */
131
    public function setUrl($url)
132
    {
133
        if (!filter_var($url, FILTER_VALIDATE_URL) === false) {
134
            $this->url = $url;
135
        }
136
    }
137
138
    /**
139
     * Getter for url field
140
     * @return string url
141
     */
142
    public function getUrl()
143
    {
144
        return $this->url;
145
    }
146
147
    /**
148
     * Setter for the post data array
149
     * @param array $postData post data
150
     * @return void
151
     */
152
    public function setPostData(array $postData)
153
    {
154
        $this->post = $postData + $this->post;
155
        $this->options[CURLOPT_POST] = 1;
156
        if (!empty($this->post)) {
157
            $this->options[CURLOPT_POSTFIELDS] = http_build_query($this->post);
158
        }
159
    }
160
161
    /**
162
     * Getter for the post data array
163
     * @return array post data
164
     */
165
    public function getPostData()
166
    {
167
        return $this->post;
168
    }
169
170
    /**
171
     * Returns the time (msec) it took to make the request
172
     * @return float time
173
     */
174
    public function getTime()
175
    {
176
        if (isset($this->handle)) {
177
            return curl_getinfo($this->handle)['total_time'];
178
        }
179
        return (float) 0;
180
    }
181
182
    /**
183
     * Get the result of a query
184
     * @return mixed result
185
     */
186
    public function getResult()
187
    {
188
        return $this->result;
189
    }
190
191
    /**
192
     * This gets called by an agent when a request has completed
193
     * @param array $multiInfo result
194
     */
195
    public function callBack(array $multiInfo)
196
    {
197
        if(isset($this->curlHandle)) {
198
            $requestInfo = curl_getinfo($this->curlHandle);
199
200
            $this->success = curl_errno($this->curlHandle) === 0 || intval($requestInfo['http_code']) === 200;
201
        }
202
203
        $this->notify();
204
    }
205
206
    /**
207
     * Add a listener that gets notified when the Request has completed
208
     * @param callable $function callback function
209
     * @return void
210
     */
211
    public function addListener(callable $function)
212
    {
213
        if (is_callable($function)) {
214
            if(!in_array($function, $this->listeners)) {
215
                $this->listeners[] = $function;
216
            }
217
        }
218
    }
219
220
    /**
221
     * Notify all listeners of request completion
222
     * @return void
223
     */
224
    protected function notify()
225
    {
226
        foreach ($this->listeners as $listener) {
227
            call_user_func($listener, $this);
228
        }
229
    }
230
231
    /**
232
     * Set a timeout value for the request
233
     * @param float $timeout timeout (msec)
234
     * @return void
235
     */
236
    public function setTimeout($timeout)
237
    {
238
        if ($timeout > 0) {
239
            $this->timeout = $timeout;
240
            $this->options[CURLOPT_TIMEOUT_MS] = $this->timeout;
241
        }
242
    }
243
244
    /**
245
     * Get the timeout value registered for the request
246
     * @return float timeout
247
     */
248
    public function getTimeout()
249
    {
250
        return $this->timeout;
251
    }
252
253
    /**
254
     * Get the cUrl handle for the request
255
     * @return resource cUrl handle
256
     */
257
    public function getHandle()
258
    {
259
        if (!isset($this->curlHandle)) {
260
            $this->curlHandle = curl_init($this->url);
261
            curl_setopt_array($this->curlHandle, $this->options);
262
        }
263
        return $this->curlHandle;
264
    }
265
266
    /**
267
     * Add headers to the request
268
     * @param array $headers headers in ['key' => 'value] or ['key: value'] format
269
     * @return void
270
     */
271
    public function setHeaders(array $headers)
272
    {
273
        $this->headers = $headers + $this->headers;
274
        $this->options[CURLOPT_HTTPHEADER] = $this->normalize($this->headers);
275
    }
276
277
    /**
278
     * Get headers set for the request
279
     * @return array headers in ['key' => 'value'] format
280
     */
281
    public function getHeaders()
282
    {
283
        return $this->headers;
284
    }
285
286
    /**
287
     * Add cUrl options to the request
288
     * @param array $options options in ['key' => 'value'] format
289
     * @return void
290
     */
291
    public function setOptions(array $options)
292
    {
293
        $this->options = $options + $this->options;
294
    }
295
296
    /**
297
     * Get cUrl options set for the request
298
     * @return array options in ['key' => 'value'] format
299
     */
300
    public function getOptions()
301
    {
302
        return $this->options;
303
    }
304
305
    /**
306
     * Get the response for the finished query
307
     * @return mixed response
308
     */
309
    public function getResponse()
310
    {
311
        if(!isset($this->response)) {
312
            if(isset($this->handle)) {
313
                $this->response = curl_multi_getcontent($this->handle);
314
            }
315
        }
316
        return $this->response;
317
    }
318
}
319