Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Request 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
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 Request, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
17 | class Request implements LoggerAwareInterface |
||
18 | { |
||
19 | const URI = 'https://secure.gaug.es/'; |
||
20 | |||
21 | /** @var null|ClientInterface */ |
||
22 | private $client; |
||
23 | |||
24 | /** @var HandlerStack */ |
||
25 | private $handlerStack; |
||
26 | |||
27 | /** @var LoggerInterface */ |
||
28 | private $logger; |
||
29 | |||
30 | /** @var string */ |
||
31 | private $logLevel; |
||
32 | |||
33 | /** @var MessageFormatter */ |
||
34 | private $messageFormatter; |
||
35 | |||
36 | /** @var array */ |
||
37 | private $options; |
||
38 | |||
39 | /** @var string */ |
||
40 | protected $token; |
||
41 | |||
42 | /** |
||
43 | * Constructor |
||
44 | * |
||
45 | * @param string $token Your API token |
||
46 | * @param array $options See Guzzle documentation (proxy, etc.) |
||
47 | */ |
||
48 | 23 | public function __construct($token, array $options = array()) |
|
49 | { |
||
50 | 23 | $this->client = null; |
|
51 | 23 | $this->handlerStack = HandlerStack::create(); |
|
52 | 23 | $this->logger = null; |
|
53 | 23 | $this->logLevel = LogLevel::INFO; |
|
54 | 23 | $this->messageFormatter = new MessageFormatter(); |
|
55 | 23 | $this->options = array_merge( |
|
56 | 23 | array('timeout' => 10), |
|
57 | $options |
||
58 | 23 | ); |
|
59 | 23 | $this->options['base_uri'] = self::URI; |
|
60 | 23 | $this->token = $token; |
|
61 | 23 | } |
|
62 | |||
63 | /** |
||
64 | * Getter for the HTTP client. |
||
65 | * |
||
66 | * @return Client |
||
67 | */ |
||
68 | 22 | protected function getHttpClient() |
|
69 | { |
||
70 | 22 | if ($this->client === null) { |
|
71 | 22 | if ($this->logger instanceof LoggerInterface) { |
|
72 | 22 | $this->handlerStack->push( |
|
73 | 22 | Middleware::log( |
|
74 | 22 | $this->logger, |
|
75 | 22 | $this->messageFormatter, |
|
76 | 22 | $this->logLevel |
|
77 | 22 | ) |
|
78 | 22 | ); |
|
79 | 22 | } |
|
80 | |||
81 | 22 | $this->options['handler'] = $this->handlerStack; |
|
82 | 22 | $this->client = new Client($this->options); |
|
83 | 22 | } |
|
84 | |||
85 | 22 | return $this->client; |
|
86 | } |
||
87 | |||
88 | /** |
||
89 | * Setter for the Guzzle HandlerStack |
||
90 | */ |
||
91 | 22 | public function setHandlerStack(HandlerStack $handlerStack) |
|
92 | { |
||
93 | 22 | $this->handlerStack = $handlerStack; |
|
94 | |||
95 | 22 | return $this; |
|
96 | } |
||
97 | |||
98 | 23 | public function setLogger(LoggerInterface $logger) |
|
99 | { |
||
100 | 23 | $this->logger = $logger; |
|
101 | |||
102 | 23 | return $this; |
|
103 | } |
||
104 | |||
105 | 22 | public function setLogLevel($logLevel) |
|
106 | { |
||
107 | 22 | $this->logLevel = $logLevel; |
|
108 | |||
109 | 22 | return $this; |
|
110 | } |
||
111 | |||
112 | /** |
||
113 | * Setter for the Guzzle MessageFormatter |
||
114 | */ |
||
115 | 23 | public function setMessageFormatter(MessageFormatter $messageFormatter) |
|
116 | { |
||
117 | 23 | $this->messageFormatter = $messageFormatter; |
|
118 | |||
119 | 23 | return $this; |
|
120 | } |
||
121 | |||
122 | /** |
||
123 | * Get Your Information |
||
124 | * |
||
125 | * Returns your information. |
||
126 | * |
||
127 | * @return GuzzleHttp\Psr7\Response |
||
128 | */ |
||
129 | 2 | public function me() |
|
130 | { |
||
131 | 2 | return $this->makeApiCall('GET', 'me'); |
|
132 | } |
||
133 | |||
134 | /** |
||
135 | * Update Your Information |
||
136 | * |
||
137 | * Updates and returns your information with the updates applied. |
||
138 | * |
||
139 | * @param string $first_name Your first name. |
||
140 | * @param string $last_name Your last name. |
||
141 | * |
||
142 | * @return GuzzleHttp\Psr7\Response |
||
143 | */ |
||
144 | 1 | View Code Duplication | public function update_me($first_name = null, $last_name = null) |
|
|||
145 | { |
||
146 | 1 | $params = array(); |
|
147 | |||
148 | 1 | if (isset($first_name)) { |
|
149 | 1 | $params['first_name'] = (string) $first_name; |
|
150 | 1 | } |
|
151 | |||
152 | 1 | if (isset($last_name)) { |
|
153 | 1 | $params['last_name'] = (string) $last_name; |
|
154 | 1 | } |
|
155 | |||
156 | 1 | return $this->makeApiCall('PUT', 'me', $params); |
|
157 | } |
||
158 | |||
159 | /** |
||
160 | * API Client List |
||
161 | * |
||
162 | * Returns an array of your API clients. |
||
163 | * |
||
164 | * @return GuzzleHttp\Psr7\Response |
||
165 | */ |
||
166 | 1 | public function list_clients() |
|
167 | { |
||
168 | 1 | return $this->makeApiCall('GET', 'clients'); |
|
169 | } |
||
170 | |||
171 | /** |
||
172 | * Creating an API Client |
||
173 | * |
||
174 | * Creates an API client, which can be used to authenticate against |
||
175 | * the Gaug.es API. |
||
176 | * |
||
177 | * @param string $description Short description for the key |
||
178 | * |
||
179 | * @return GuzzleHttp\Psr7\Response |
||
180 | */ |
||
181 | 1 | public function create_client($description = null) |
|
182 | { |
||
183 | 1 | $params = array(); |
|
184 | |||
185 | 1 | if (isset($description)) { |
|
186 | 1 | $params['description'] = (string) $description; |
|
187 | 1 | } |
|
188 | |||
189 | 1 | return $this->makeApiCall('POST', 'clients', $params); |
|
190 | } |
||
191 | |||
192 | /** |
||
193 | * Delete an API Client |
||
194 | * |
||
195 | * Permanently deletes an API client key. |
||
196 | * |
||
197 | * @param string $id |
||
198 | * |
||
199 | * @return GuzzleHttp\Psr7\Response |
||
200 | */ |
||
201 | 1 | public function delete_client($id) |
|
202 | { |
||
203 | 1 | return $this->makeApiCall('DELETE', 'clients/' . $id); |
|
204 | } |
||
205 | |||
206 | /** |
||
207 | * Gauges List |
||
208 | * |
||
209 | * Returns an array of your gauges, with recent traffic included. |
||
210 | * |
||
211 | * @return GuzzleHttp\Psr7\Response |
||
212 | */ |
||
213 | 1 | View Code Duplication | public function list_gauges($page = null) |
223 | |||
224 | /** |
||
225 | * Create a New Gauge |
||
226 | * |
||
227 | * Creates a gauge. |
||
228 | * |
||
229 | * @param string $title |
||
230 | * @param string $tz |
||
231 | * @param string $allowedHosts (Optional) |
||
232 | * |
||
233 | * @return GuzzleHttp\Psr7\Response |
||
234 | */ |
||
235 | 1 | View Code Duplication | public function create_gauge($title, $tz, $allowedHosts = null) |
236 | { |
||
237 | $params = array( |
||
238 | 1 | 'title' => $title, |
|
239 | 'tz' => $tz |
||
240 | 1 | ); |
|
241 | |||
242 | 1 | if (isset($allowedHosts)) { |
|
243 | 1 | $params['allowed_hosts'] = (string) $allowedHosts; |
|
244 | 1 | } |
|
245 | |||
246 | 1 | return $this->makeApiCall('POST', 'gauges', $params); |
|
247 | } |
||
248 | |||
249 | /** |
||
250 | * Gauge Detail |
||
251 | * |
||
252 | * Gets details for a gauge. |
||
253 | * |
||
254 | * @param string $id |
||
255 | * |
||
256 | * @return GuzzleHttp\Psr7\Response |
||
257 | */ |
||
258 | 1 | public function gauge_detail($id) |
|
262 | |||
263 | /** |
||
264 | * Update a Gauge |
||
265 | * |
||
266 | * Updates and returns a gauge with the updates applied. |
||
267 | * |
||
268 | * @param string $id |
||
269 | * @param string $title |
||
270 | * @param string $tz |
||
271 | * @param string $allowedHosts (Optional) |
||
272 | * |
||
273 | * @return GuzzleHttp\Psr7\Response |
||
274 | */ |
||
275 | 1 | View Code Duplication | public function update_gauge($id, $title, $tz, $allowedHosts = null) |
288 | |||
289 | /** |
||
290 | * Delete a Gauge |
||
291 | * |
||
292 | * Permanently deletes a gauge. |
||
293 | * |
||
294 | * @param string $id |
||
295 | * |
||
296 | * @return GuzzleHttp\Psr7\Response |
||
297 | */ |
||
298 | 1 | public function delete_gauge($id) |
|
299 | { |
||
300 | 1 | return $this->makeApiCall('DELETE', 'gauges/' . $id); |
|
302 | |||
303 | /** |
||
304 | * List Shares |
||
305 | * |
||
306 | * Lists the people that have access to a Gauge. |
||
307 | * |
||
308 | * @param string $id |
||
309 | * |
||
310 | * @return GuzzleHttp\Psr7\Response |
||
311 | */ |
||
312 | 1 | public function list_shares($id) |
|
316 | |||
317 | /** |
||
318 | * Share a Gauge |
||
319 | * |
||
320 | * Shares gauge with a person by their email. Any valid email will work |
||
321 | * and will receive an invite even if there is no existing Gauges user |
||
322 | * with that email. |
||
323 | * |
||
324 | * @param string $id |
||
325 | * @param string $email |
||
326 | * |
||
327 | * @return GuzzleHttp\Psr7\Response |
||
328 | */ |
||
329 | 1 | public function share_gauge($id, $email) |
|
337 | |||
338 | /** |
||
339 | * Un-share Gauge |
||
340 | * |
||
341 | * @param string $id |
||
342 | * @param string $user_id |
||
343 | * |
||
344 | * @return GuzzleHttp\Psr7\Response |
||
345 | */ |
||
346 | 1 | public function unshare_gauge($id, $user_id) |
|
350 | |||
351 | /** |
||
352 | * Top Content |
||
353 | * |
||
354 | * Gets top content for a gauge, paginated. |
||
355 | * |
||
356 | * @param string $id |
||
357 | * @param string $date (Optional) Date in format YYYY-MM-DD |
||
358 | * @param int $page (Optional) |
||
359 | * @param string $group (Optional) Either "day" or "month". Default is "day". |
||
360 | * |
||
361 | * @return GuzzleHttp\Psr7\Response |
||
362 | 1 | */ |
|
363 | public function top_content($id, $date = null, $page = null, $group = null) |
||
381 | |||
382 | /** |
||
383 | * Top Referrers |
||
384 | * |
||
385 | * Gets top referrers for a gauge, paginated. |
||
386 | * |
||
387 | * @param string $id |
||
388 | 1 | * @param string $date (Optional) Date in format YYYY-MM-DD |
|
389 | * @param int $page (Optional) |
||
390 | 1 | * |
|
391 | * @return GuzzleHttp\Psr7\Response |
||
392 | 1 | */ |
|
393 | 1 | View Code Duplication | public function top_referrers($id, $date = null, $page = null) |
407 | |||
408 | /** |
||
409 | * Traffic |
||
410 | * |
||
411 | * Gets traffic for a gauge. |
||
412 | * |
||
413 | 1 | * @param string $id |
|
414 | * @param string $date (Optional) Date in format YYYY-MM-DD |
||
415 | 1 | * |
|
416 | * @return GuzzleHttp\Psr7\Response |
||
417 | 1 | */ |
|
418 | 1 | View Code Duplication | public function traffic($id, $date = null) |
428 | |||
429 | /** |
||
430 | * Browser Resolutions |
||
431 | * |
||
432 | * Gets browsers heights, browser widths, and screen widths for a gauge. |
||
433 | * |
||
434 | 1 | * @param string $id |
|
435 | * @param string $date (Optional) Date in format YYYY-MM-DD |
||
436 | 1 | * |
|
437 | * @return GuzzleHttp\Psr7\Response |
||
438 | 1 | */ |
|
439 | 1 | View Code Duplication | public function browser_resolutions($id, $date = null) |
449 | |||
450 | /** |
||
451 | * Technology |
||
452 | * |
||
453 | * Gets browsers and platforms for a gauge. |
||
454 | * |
||
455 | 1 | * @param string $id |
|
456 | * @param string $date (Optional) Date in format YYYY-MM-DD |
||
457 | 1 | * |
|
458 | * @return GuzzleHttp\Psr7\Response |
||
459 | 1 | */ |
|
460 | 1 | View Code Duplication | public function technology($id, $date = null) |
470 | |||
471 | /** |
||
472 | * Search Terms |
||
473 | * |
||
474 | * Gets search terms for a gauge, paginated. |
||
475 | * |
||
476 | * @param string $id |
||
477 | 1 | * @param string $date (Optional) Date in format YYYY-MM-DD |
|
478 | * @param int $page (Optional) |
||
479 | 1 | * |
|
480 | * @return GuzzleHttp\Psr7\Response |
||
481 | 1 | */ |
|
482 | 1 | View Code Duplication | public function search_terms($id, $date = null, $page = null) |
496 | |||
497 | /** |
||
498 | * Search Engines |
||
499 | * |
||
500 | * Gets search engines for a gauge. |
||
501 | * |
||
502 | 1 | * @param string $id |
|
503 | * @param string $date (Optional) Date in format YYYY-MM-DD |
||
504 | 1 | * |
|
505 | * @return GuzzleHttp\Psr7\Response |
||
506 | 1 | */ |
|
507 | 1 | View Code Duplication | public function search_engines($id, $date = null) |
517 | |||
518 | /** |
||
519 | * Locations |
||
520 | * |
||
521 | * Gets locations for a gauge. |
||
522 | * |
||
523 | 1 | * @param string $id |
|
524 | * @param string $date (Optional) Date in format YYYY-MM-DD |
||
525 | 1 | * |
|
526 | * @return GuzzleHttp\Psr7\Response |
||
527 | 1 | */ |
|
528 | 1 | View Code Duplication | public function locations($id, $date = null) |
538 | |||
539 | /** |
||
540 | * Browser stats |
||
541 | * |
||
542 | * Get the browser statistics in a format used with the browserlist module. |
||
543 | 22 | * (See https://github.com/ai/browserslist) |
|
544 | * |
||
545 | * @param string $id |
||
546 | 22 | * @param string $date (Optional) Date in format YYYY-MM-DD |
|
547 | * |
||
548 | * @return GuzzleHttp\Psr7\Response |
||
549 | 22 | */ |
|
550 | 22 | View Code Duplication | public function browser_stats($id, $date = null) |
560 | |||
561 | /** |
||
562 | * Make the actual gauges API call. |
||
563 | * |
||
564 | * @param string $method [GET|POST|PUT|DELETE] |
||
565 | * @param string $path |
||
566 | * @param array $params |
||
567 | * |
||
568 | * @return GuzzleHttp\Psr7\Response |
||
569 | */ |
||
570 | protected function makeApiCall($method, $path, array $params = array()) |
||
585 | } |
||
586 |
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.