Agent   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 193
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 13
Bugs 0 Features 0
Metric Value
wmc 23
c 13
b 0
f 0
lcom 1
cbo 1
dl 0
loc 193
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __set() 0 10 2
A __get() 0 10 2
A __construct() 0 6 1
A __destruct() 0 4 1
A addListener() 0 4 1
A setMaxConcurrent() 0 6 2
A getMaxConcurrent() 0 4 1
A newRequest() 0 6 1
A addRequest() 0 5 1
A getRequestByHandle() 0 8 3
C execute() 0 33 8
1
<?php
2
3
namespace CurlX;
4
5
/**
6
 * Class Agent
7
 * @package CurlX
8
 *
9
 * @property int $max_concurrent The maximum number of simultaneous connections allowed
10
 * @property int $maxConcurrent The maximum number of simultaneous connections allowed
11
 * @property string $url default url for requests
12
 * @property array $post_data array of default post data for requests
13
 * @property float $time running time of the agent
14
 * @property int $timeout default timeout (in msec) for requests
15
 * @property array $options default cUrl options for requests
16
 * @property array $headers default headers for requests
17
 * @property resource $handle cUrl Multi Handle
18
 * @property callable[] $listeners array of registered listeners which will be registered to newly created requests
19
 * @property array $response responses of the individual requests
20
 */
21
class Agent
22
{
23
    /**
24
     * @var array results
25
     */
26
    protected $result;
27
28
    /**
29
     * @var array responses
30
     */
31
    protected $response;
32
33
    /**
34
     * @var int The maximum number of simultaneous connections allowed
35
     */
36
    protected $maxConcurrent = 0;
37
38
    /**
39
     * @var RequestInterface[] array of Requests
40
     */
41
    protected $requests;
42
43
    /**
44
     * @var Request default request
45
     */
46
    protected $defaultRequest;
47
48
    /**
49
     * @var resource cUrl Multi Handle
50
     */
51
    protected $mh;
52
53
    protected $requestCounter = 0;
54
55
    /**
56
     * Agent constructor.
57
     * @param int $maxConcurrent max current requests
58
     */
59
    public function __construct($maxConcurrent = 10)
60
    {
61
        $this->setMaxConcurrent($maxConcurrent);
62
        $this->defaultRequest = new Request();
63
        $this->mh = curl_multi_init();
64
    }
65
66
    /**
67
     * Destructor
68
     */
69
    public function __destruct()
70
    {
71
        curl_multi_close($this->mh);
72
    }
73
74
    /**
75
     * Magic setter function
76
     * @param string $name attribute to set
77
     * @param mixed $value the new value
78
     * @return void
79
     */
80
    public function __set($name, $value)
81
    {
82
        $c = Request::camelize($name);
83
        $m = "set$c";
84
        if (method_exists($this, $m)) {
85
            $this->$m($value);
86
        } else {
87
            $this->defaultRequest->__set($name, $value);
88
        }
89
    }
90
91
    /**
92
     * Magic getter function
93
     * @param string $name of the attribute to get
94
     * @return mixed the attribute's value
95
     */
96
    public function __get($name)
97
    {
98
        $c = Request::camelize($name);
99
        $m = "get$c";
100
        if (method_exists($this, $m)) {
101
            return $this->$m();
102
        } else {
103
            return $this->defaultRequest->__get($name);
104
        }
105
    }
106
107
    /**
108
     * Add a default listener to be added to all new Requests
109
     * @param callable $listener the listener
110
     * @return void
111
     */
112
    public function addListener(callable $listener)
113
    {
114
        $this->defaultRequest->addListener($listener);
115
    }
116
117
    /**
118
     * Set the maximum number of concurrent requests
119
     * @param int $maxConcurrent maximum concurrent requests
120
     * @return void
121
     */
122
    public function setMaxConcurrent($maxConcurrent)
123
    {
124
        if ($maxConcurrent > 0) {
125
            $this->maxConcurrent = $maxConcurrent;
126
        }
127
    }
128
129
    /**
130
     * Get the currently set value of maxConcurrent
131
     * @return int maximum number of concurrent requests
132
     */
133
    public function getMaxConcurrent()
134
    {
135
        return $this->maxConcurrent;
136
    }
137
138
    /**
139
     * Adds a new request to the queue and returns it
140
     * this request will have its default options set to global options
141
     * @param null $url URL to send the request to
142
     * @return RequestInterface the newly added request object
143
     */
144
    public function newRequest($url = null)
145
    {
146
        $request = clone $this->defaultRequest;
147
        $request->url = $url;
148
        return $this->addRequest($request);
149
    }
150
151
    /**
152
     * Add a request to the request queue
153
     * @param RequestInterface $request the request to add
154
     * @return RequestInterface
155
     */
156
    public function addRequest(RequestInterface $request)
157
    {
158
        $this->requests[] = $request;
159
        return $request;
160
    }
161
162
    /**
163
     * Returns the Request object for a give cUrl handle
164
     * @param resource $handle cUrl handle
165
     * @return RequestInterface Request with handle
166
     */
167
    protected function getRequestByHandle($handle)
168
    {
169
        foreach ($this->requests as $request) {
170
            if ($request->handle === $handle) {
0 ignored issues
show
Bug introduced by
Accessing handle on the interface CurlX\RequestInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
171
                return $request;
172
            }
173
        }
174
    }
175
176
    /**
177
     * Execute the request queue
178
     * @return void
179
     */
180
    public function execute()
181
    {
182
        // start the first batch of requests
183
        $numOfRequests = count($this->requests);
184
        while ($this->requestCounter < $this->maxConcurrent && $this->requestCounter < $numOfRequests) {
185
            curl_multi_add_handle($this->mh, $this->requests[$this->requestCounter]->handle);
0 ignored issues
show
Bug introduced by
Accessing handle on the interface CurlX\RequestInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
186
            $this->requestCounter++;
187
        }
188
189
        do {
190
            while (($mrc = curl_multi_exec($this->mh, $running)) == CURLM_CALL_MULTI_PERFORM) {
0 ignored issues
show
Unused Code introduced by
This while loop is empty and can be removed.

This check looks for while loops that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Consider removing the loop.

Loading history...
191
192
            }
193
            if ($mrc != CURLM_OK) {
194
                break;
195
            }
196
197
            // a request was just completed -- find out which one
198
            while ($done = curl_multi_info_read($this->mh)) {
199
                // Callback
200
                $this->getRequestByHandle($done['handle'])->callBack($done);
201
202
                // start a new request
203
                if ($this->requestCounter < $numOfRequests) {
204
                    curl_multi_add_handle($this->mh, $this->requests[$this->requestCounter]->handle);
0 ignored issues
show
Bug introduced by
Accessing handle on the interface CurlX\RequestInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
205
                    $this->requestCounter++;
206
207
                    // remove the curl handle that just completed
208
                    curl_multi_remove_handle($this->mh, $done['handle']);
209
                }
210
            }
211
        } while ($running);
212
    }
213
}
214