Total Complexity | 72 |
Total Lines | 388 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like Client often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Client, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
25 | class Client implements ClientInterface |
||
26 | { |
||
27 | /** @var array Default request options */ |
||
28 | private $config; |
||
29 | |||
30 | /** |
||
31 | * Clients accept an array of constructor parameters. |
||
32 | * |
||
33 | * Here's an example of creating a client using a base_uri and an array of |
||
34 | * default request options to apply to each request: |
||
35 | * |
||
36 | * $client = new Client([ |
||
37 | * 'base_uri' => 'http://www.foo.com/1.0/', |
||
38 | * 'timeout' => 0, |
||
39 | * 'allow_redirects' => false, |
||
40 | * 'proxy' => '192.168.16.1:10' |
||
41 | * ]); |
||
42 | * |
||
43 | * Client configuration settings include the following options: |
||
44 | * |
||
45 | * - handler: (callable) Function that transfers HTTP requests over the |
||
46 | * wire. The function is called with a Psr7\Http\Message\RequestInterface |
||
47 | * and array of transfer options, and must return a |
||
48 | * GuzzleHttp\Promise\PromiseInterface that is fulfilled with a |
||
49 | * Psr7\Http\Message\ResponseInterface on success. "handler" is a |
||
50 | * constructor only option that cannot be overridden in per/request |
||
51 | * options. If no handler is provided, a default handler will be created |
||
52 | * that enables all of the request options below by attaching all of the |
||
53 | * default middleware to the handler. |
||
54 | * - base_uri: (string|UriInterface) Base URI of the client that is merged |
||
55 | * into relative URIs. Can be a string or instance of UriInterface. |
||
56 | * - **: any request option |
||
57 | * |
||
58 | * @param array $config Client configuration settings. |
||
59 | * |
||
60 | * @see \GuzzleHttp\RequestOptions for a list of available request options. |
||
61 | */ |
||
62 | public function __construct(array $config = []) |
||
63 | { |
||
64 | if (!isset($config['handler'])) { |
||
65 | $config['handler'] = HandlerStack::create(); |
||
66 | } elseif (!is_callable($config['handler'])) { |
||
67 | throw new \InvalidArgumentException('handler must be a callable'); |
||
68 | } |
||
69 | |||
70 | // Convert the base_uri to a UriInterface |
||
71 | if (isset($config['base_uri'])) { |
||
72 | $config['base_uri'] = Psr7\uri_for($config['base_uri']); |
||
|
|||
73 | } |
||
74 | |||
75 | $this->configureDefaults($config); |
||
76 | } |
||
77 | |||
78 | public function __call($method, $args) |
||
79 | { |
||
80 | if (count($args) < 1) { |
||
81 | throw new \InvalidArgumentException('Magic request methods require a URI and optional options array'); |
||
82 | } |
||
83 | |||
84 | $uri = $args[0]; |
||
85 | $opts = isset($args[1]) ? $args[1] : []; |
||
86 | |||
87 | return substr($method, -5) === 'Async' |
||
88 | ? $this->requestAsync(substr($method, 0, -5), $uri, $opts) |
||
89 | : $this->request($method, $uri, $opts); |
||
90 | } |
||
91 | |||
92 | public function sendAsync(RequestInterface $request, array $options = []) |
||
93 | { |
||
94 | // Merge the base URI into the request URI if needed. |
||
95 | $options = $this->prepareDefaults($options); |
||
96 | |||
97 | return $this->transfer( |
||
98 | $request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')), |
||
99 | $options |
||
100 | ); |
||
101 | } |
||
102 | |||
103 | public function send(RequestInterface $request, array $options = []) |
||
104 | { |
||
105 | $options[RequestOptions::SYNCHRONOUS] = true; |
||
106 | return $this->sendAsync($request, $options)->wait(); |
||
107 | } |
||
108 | |||
109 | public function requestAsync($method, $uri = '', array $options = []) |
||
110 | { |
||
111 | $options = $this->prepareDefaults($options); |
||
112 | // Remove request modifying parameter because it can be done up-front. |
||
113 | $headers = isset($options['headers']) ? $options['headers'] : []; |
||
114 | $body = isset($options['body']) ? $options['body'] : null; |
||
115 | $version = isset($options['version']) ? $options['version'] : '1.1'; |
||
116 | // Merge the URI into the base URI. |
||
117 | $uri = $this->buildUri($uri, $options); |
||
118 | if (is_array($body)) { |
||
119 | $this->invalidBody(); |
||
120 | } |
||
121 | $request = new Psr7\Request($method, $uri, $headers, $body, $version); |
||
122 | // Remove the option so that they are not doubly-applied. |
||
123 | unset($options['headers'], $options['body'], $options['version']); |
||
124 | |||
125 | return $this->transfer($request, $options); |
||
126 | } |
||
127 | |||
128 | public function request($method, $uri = '', array $options = []) |
||
129 | { |
||
130 | $options[RequestOptions::SYNCHRONOUS] = true; |
||
131 | return $this->requestAsync($method, $uri, $options)->wait(); |
||
132 | } |
||
133 | |||
134 | public function getConfig($option = null) |
||
135 | { |
||
136 | return $option === null |
||
137 | ? $this->config |
||
138 | : (isset($this->config[$option]) ? $this->config[$option] : null); |
||
139 | } |
||
140 | |||
141 | private function buildUri($uri, array $config) |
||
142 | { |
||
143 | // for BC we accept null which would otherwise fail in uri_for |
||
144 | $uri = Psr7\uri_for($uri === null ? '' : $uri); |
||
145 | |||
146 | if (isset($config['base_uri'])) { |
||
147 | $uri = Psr7\UriResolver::resolve(Psr7\uri_for($config['base_uri']), $uri); |
||
148 | } |
||
149 | |||
150 | return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri; |
||
151 | } |
||
152 | |||
153 | /** |
||
154 | * Configures the default options for a client. |
||
155 | * |
||
156 | * @param array $config |
||
157 | */ |
||
158 | private function configureDefaults(array $config) |
||
159 | { |
||
160 | $defaults = [ |
||
161 | 'allow_redirects' => RedirectMiddleware::$defaultSettings, |
||
162 | 'http_errors' => true, |
||
163 | 'decode_content' => true, |
||
164 | 'verify' => true, |
||
165 | 'cookies' => false |
||
166 | ]; |
||
167 | |||
168 | // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set. |
||
169 | |||
170 | // We can only trust the HTTP_PROXY environment variable in a CLI |
||
171 | // process due to the fact that PHP has no reliable mechanism to |
||
172 | // get environment variables that start with "HTTP_". |
||
173 | if (php_sapi_name() == 'cli' && getenv('HTTP_PROXY')) { |
||
174 | $defaults['proxy']['http'] = getenv('HTTP_PROXY'); |
||
175 | } |
||
176 | |||
177 | if ($proxy = getenv('HTTPS_PROXY')) { |
||
178 | $defaults['proxy']['https'] = $proxy; |
||
179 | } |
||
180 | |||
181 | if ($noProxy = getenv('NO_PROXY')) { |
||
182 | $cleanedNoProxy = str_replace(' ', '', $noProxy); |
||
183 | $defaults['proxy']['no'] = explode(',', $cleanedNoProxy); |
||
184 | } |
||
185 | |||
186 | $this->config = $config + $defaults; |
||
187 | |||
188 | if (!empty($config['cookies']) && $config['cookies'] === true) { |
||
189 | $this->config['cookies'] = new CookieJar(); |
||
190 | } |
||
191 | |||
192 | // Add the default user-agent header. |
||
193 | if (!isset($this->config['headers'])) { |
||
194 | $this->config['headers'] = ['User-Agent' => default_user_agent()]; |
||
195 | } else { |
||
196 | // Add the User-Agent header if one was not already set. |
||
197 | foreach (array_keys($this->config['headers']) as $name) { |
||
198 | if (strtolower($name) === 'user-agent') { |
||
199 | return; |
||
200 | } |
||
201 | } |
||
202 | $this->config['headers']['User-Agent'] = default_user_agent(); |
||
203 | } |
||
204 | } |
||
205 | |||
206 | /** |
||
207 | * Merges default options into the array. |
||
208 | * |
||
209 | * @param array $options Options to modify by reference |
||
210 | * |
||
211 | * @return array |
||
212 | */ |
||
213 | private function prepareDefaults($options) |
||
214 | { |
||
215 | $defaults = $this->config; |
||
216 | |||
217 | if (!empty($defaults['headers'])) { |
||
218 | // Default headers are only added if they are not present. |
||
219 | $defaults['_conditional'] = $defaults['headers']; |
||
220 | unset($defaults['headers']); |
||
221 | } |
||
222 | |||
223 | // Special handling for headers is required as they are added as |
||
224 | // conditional headers and as headers passed to a request ctor. |
||
225 | if (array_key_exists('headers', $options)) { |
||
226 | // Allows default headers to be unset. |
||
227 | if ($options['headers'] === null) { |
||
228 | $defaults['_conditional'] = null; |
||
229 | unset($options['headers']); |
||
230 | } elseif (!is_array($options['headers'])) { |
||
231 | throw new \InvalidArgumentException('headers must be an array'); |
||
232 | } |
||
233 | } |
||
234 | |||
235 | // Shallow merge defaults underneath options. |
||
236 | $result = $options + $defaults; |
||
237 | |||
238 | // Remove null values. |
||
239 | foreach ($result as $k => $v) { |
||
240 | if ($v === null) { |
||
241 | unset($result[$k]); |
||
242 | } |
||
243 | } |
||
244 | |||
245 | return $result; |
||
246 | } |
||
247 | |||
248 | /** |
||
249 | * Transfers the given request and applies request options. |
||
250 | * |
||
251 | * The URI of the request is not modified and the request options are used |
||
252 | * as-is without merging in default options. |
||
253 | * |
||
254 | * @param RequestInterface $request |
||
255 | * @param array $options |
||
256 | * |
||
257 | * @return Promise\PromiseInterface |
||
258 | */ |
||
259 | private function transfer(RequestInterface $request, array $options) |
||
260 | { |
||
261 | // save_to -> sink |
||
262 | if (isset($options['save_to'])) { |
||
263 | $options['sink'] = $options['save_to']; |
||
264 | unset($options['save_to']); |
||
265 | } |
||
266 | |||
267 | // exceptions -> http_errors |
||
268 | if (isset($options['exceptions'])) { |
||
269 | $options['http_errors'] = $options['exceptions']; |
||
270 | unset($options['exceptions']); |
||
271 | } |
||
272 | |||
273 | $request = $this->applyOptions($request, $options); |
||
274 | $handler = $options['handler']; |
||
275 | |||
276 | try { |
||
277 | return Promise\promise_for($handler($request, $options)); |
||
278 | } catch (\Exception $e) { |
||
279 | return Promise\rejection_for($e); |
||
280 | } |
||
281 | } |
||
282 | |||
283 | /** |
||
284 | * Applies the array of request options to a request. |
||
285 | * |
||
286 | * @param RequestInterface $request |
||
287 | * @param array $options |
||
288 | * |
||
289 | * @return RequestInterface |
||
290 | */ |
||
291 | private function applyOptions(RequestInterface $request, array &$options) |
||
404 | } |
||
405 | |||
406 | private function invalidBody() |
||
413 | } |
||
414 | } |
||
415 |
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.