Completed
Push — master ( e9d02e...810a04 )
by Benjamin
01:56
created

Agent::addListener()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
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 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 $max_concurrent max current requests
58
     */
59
    function __construct($max_concurrent = 10)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
60
    {
61
        $this->setMaxConcurrent($max_concurrent);
62
        $this->defaultRequest = new Request();
63
        $this->mh = curl_multi_init();
64
    }
65
66
    function __destruct()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
67
    {
68
        foreach($this->requests as $request) {
69
            curl_multi_remove_handle($this->mh, $request->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...
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
     * Set the maximum number of concurrent requests
109
     * @param int $max_requests maximum concurrent requests
110
     */
111
    public function setMaxConcurrent($max_requests)
112
    {
113
        if ($max_requests > 0) {
114
            $this->maxConcurrent = $max_requests;
115
        }
116
    }
117
118
    /**
119
     * Get the currently set value of maxConcurrent
120
     * @return int maximum number of concurrent requests
121
     */
122
    public function getMaxConcurrent()
123
    {
124
        return $this->maxConcurrent;
125
    }
126
127
    /**
128
     * Adds a new request to the queue and returns it
129
     * this request will have its default options set to global options
130
     * @param null $url URL to send the request to
131
     * @return RequestInterface the newly added request object
132
     */
133
    public function newRequest($url = null)
134
    {
135
        $request = clone $this->defaultRequest;
136
        $request->url = $url;
137
        return $this->addRequest($request);
138
    }
139
140
    /**
141
     * Add a request to the request queue
142
     * @param RequestInterface $request the request to add
143
     * @return RequestInterface
144
     */
145
    public function addRequest(RequestInterface $request)
146
    {
147
        $this->requests[] = $request;
148
        return $request;
149
    }
150
151
    /**
152
     * Returns the Request object for a give cUrl handle
153
     * @param resource $handle cUrl handle
154
     * @return RequestInterface Request with handle
155
     */
156
    protected function getRequestByHandle($handle)
157
    {
158
        foreach ($this->requests as $request) {
159
            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...
160
                return $request;
161
            }
162
        }
163
    }
164
165
    /**
166
     * Execute the request queue
167
     */
168
    public function execute()
169
    {
170
        foreach ($this->requests as $key => $request) {
171
            if ($this->requestCounter >= $this->maxConcurrent) {
172
                break;
173
            }
174
            curl_multi_add_handle($this->mh, $request->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...
175
            $this->requestCounter++;
176
        }
177
178
        // Start the request
179
        do {
180
            $mrc = curl_multi_exec($this->mh, $active);
181
        } while ($mrc == CURLM_CALL_MULTI_PERFORM);
182
183
        while ($active && $mrc == CURLM_OK) {
184
            while (curl_multi_exec($this->mh, $active) === CURLM_CALL_MULTI_PERFORM) ;
185
186
            if (curl_multi_select($this->mh) != -1) {
187
                do {
188
                    $mrc = curl_multi_exec($this->mh, $active);
189
                    if ($mrc == CURLM_OK) {
190
                        while ($info = curl_multi_info_read($this->mh)) {
191
                            $this->getRequestByHandle($info['handle'])->callBack($info);
192
                        }
193
                    }
194
                } while ($mrc == CURLM_CALL_MULTI_PERFORM);
195
            }
196
        }
197
    }
198
199
    public function addListener(callable $function)
200
    {
201
        $this->defaultRequest->addListener($function);
202
    }
203
}
204