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 ExchangeAutodiscover 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 ExchangeAutodiscover, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 9 | class ExchangeAutodiscover |
||
| 10 | { |
||
| 11 | protected $autodiscoverPath = '/autodiscover/autodiscover.xml'; |
||
| 12 | |||
| 13 | /** |
||
| 14 | * @var Client |
||
| 15 | */ |
||
| 16 | protected $httpPlayback; |
||
| 17 | |||
| 18 | 2 | protected function __construct() |
|
| 21 | |||
| 22 | /** |
||
| 23 | * Parse the hex ServerVersion value and return a valid |
||
| 24 | * ExchangeWebServices::VERSION_* constant. |
||
| 25 | * |
||
| 26 | * @param $versionHex |
||
| 27 | * @return string|boolean A known version constant, or FALSE if it could not |
||
| 28 | * be determined. |
||
| 29 | * |
||
| 30 | * @link http://msdn.microsoft.com/en-us/library/bb204122(v=exchg.140).aspx |
||
| 31 | * @link http://blogs.msdn.com/b/pcreehan/archive/2009/09/21/parsing-serverversion-when-an-int-is-really-5-ints.aspx |
||
| 32 | */ |
||
| 33 | 5 | protected function parseServerVersion($versionHex) |
|
| 69 | |||
| 70 | /** |
||
| 71 | * @param string $email |
||
| 72 | * @param string $password |
||
| 73 | * @param string $username |
||
| 74 | * @param array $options |
||
| 75 | * |
||
| 76 | * @return API |
||
| 77 | * @throws AutodiscoverFailed |
||
| 78 | */ |
||
| 79 | 2 | protected function newAPI($email, $password, $username = null, $options = []) |
|
| 101 | |||
| 102 | 1 | protected function getServerVersionFromResponse($response) |
|
| 115 | |||
| 116 | 1 | protected function getServerFromResponse($response) |
|
| 126 | |||
| 127 | /** |
||
| 128 | * Static method may fail if there are issues surrounding SSL certificates. |
||
| 129 | * In such cases, set up the object as needed, and then call newEWS(). |
||
| 130 | * |
||
| 131 | * @param string $email |
||
| 132 | * @param string $password |
||
| 133 | * @param string $username If left blank, the email provided will be used. |
||
| 134 | * @throws AutodiscoverFailed |
||
| 135 | * @return API |
||
| 136 | */ |
||
| 137 | 2 | public static function getAPI($email, $password, $username = null, $options = []) |
|
| 143 | |||
| 144 | /** |
||
| 145 | * Execute the full discovery chain of events in the correct sequence |
||
| 146 | * until a valid response is received, or all methods have failed. |
||
| 147 | * |
||
| 148 | * @param string $email |
||
| 149 | * @param string $password |
||
| 150 | * @param string $username |
||
| 151 | * @return string The discovered settings |
||
| 152 | * @throws AutodiscoverFailed |
||
| 153 | */ |
||
| 154 | 2 | protected function discover($email, $password, $username) |
|
| 176 | |||
| 177 | /** |
||
| 178 | * Perform an NTLM authenticated HTTPS POST to the top-level |
||
| 179 | * domain of the email address. |
||
| 180 | * |
||
| 181 | * @param string $email |
||
| 182 | * @param string $password |
||
| 183 | * @param string $username |
||
| 184 | * |
||
| 185 | * @return string The discovered settings |
||
| 186 | */ |
||
| 187 | 2 | View Code Duplication | protected function tryTopLevelDomain($email, $password, $username) |
| 194 | |||
| 195 | /** |
||
| 196 | * Perform an NTLM authenticated HTTPS POST to the 'autodiscover' |
||
| 197 | * subdomain of the email address' TLD. |
||
| 198 | * |
||
| 199 | * @param string $email |
||
| 200 | * @param string $password |
||
| 201 | * @param string $username |
||
| 202 | * |
||
| 203 | * @return string The discovered settings |
||
| 204 | */ |
||
| 205 | 2 | View Code Duplication | protected function tryAutoDiscoverSubDomain($email, $password, $username) |
| 212 | |||
| 213 | /** |
||
| 214 | * Perform an unauthenticated HTTP GET in an attempt to get redirected |
||
| 215 | * via 302 to the correct location to perform the HTTPS POST. |
||
| 216 | * |
||
| 217 | * @param string $email |
||
| 218 | * @param string $password |
||
| 219 | * @param string $username |
||
| 220 | * |
||
| 221 | * @return string The discovered settings |
||
| 222 | */ |
||
| 223 | 2 | protected function trySubdomainUnauthenticatedGet($email, $password, $username) |
|
| 249 | |||
| 250 | /** |
||
| 251 | * Attempt to retrieve the autodiscover host from an SRV DNS record. |
||
| 252 | * |
||
| 253 | * @link http://support.microsoft.com/kb/940881 |
||
| 254 | * |
||
| 255 | * @param string $email |
||
| 256 | * @param string $password |
||
| 257 | * @param string $username |
||
| 258 | * |
||
| 259 | * @return string The discovered settings |
||
| 260 | */ |
||
| 261 | 1 | protected function trySRVRecord($email, $password, $username) |
|
| 275 | |||
| 276 | /** |
||
| 277 | * Perform the NTLM authenticated post against one of the chosen |
||
| 278 | * endpoints. |
||
| 279 | * |
||
| 280 | * @param string $url URL to try posting to |
||
| 281 | * @param string $email |
||
| 282 | * @param string $password |
||
| 283 | * @param string $username |
||
| 284 | * |
||
| 285 | * @return string The discovered settings |
||
| 286 | */ |
||
| 287 | 2 | protected function doNTLMPost($url, $email, $password, $username) |
|
| 319 | |||
| 320 | /** |
||
| 321 | * Parse the Autoresponse Payload, particularly to determine if an |
||
| 322 | * additional request is necessary. |
||
| 323 | * |
||
| 324 | * @param $response |
||
| 325 | * @return array|bool |
||
| 326 | * @throws AutodiscoverFailed |
||
| 327 | */ |
||
| 328 | 1 | protected function parseAutodiscoverResponse($response) |
|
| 348 | |||
| 349 | /** |
||
| 350 | * Get a top level domain based on an email address |
||
| 351 | * |
||
| 352 | * @param string $email |
||
| 353 | * @return string|false |
||
| 354 | */ |
||
| 355 | 2 | protected function getTopLevelDomainFromEmail($email) |
|
| 364 | |||
| 365 | /** |
||
| 366 | * Utility function to parse XML payloads from the response into easier |
||
| 367 | * to manage associative arrays. |
||
| 368 | * |
||
| 369 | * @param string $xml XML to parse |
||
| 370 | * @return array |
||
| 371 | */ |
||
| 372 | 1 | protected function responseToArray($xml) |
|
| 378 | } |
||
| 379 |