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 PENSRequest 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 PENSRequest, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 44 | abstract class PENSRequest extends PENSMessage { |
||
| 45 | |||
| 46 | /** |
||
| 47 | * PENS Version to be used. Currently, the only valid value is 1.0.0. Required. |
||
| 48 | * @var string |
||
| 49 | */ |
||
| 50 | protected $_pens_version = null; |
||
| 51 | |||
| 52 | /** |
||
| 53 | * Command being used. The only valid values are collect, alert and receipt.Required |
||
| 54 | * @var string |
||
| 55 | */ |
||
| 56 | protected $_command = null; |
||
| 57 | |||
| 58 | /** |
||
| 59 | * Package type being used. The only valid values are aicc-pkg, scorm-pif, ims-qti. Required |
||
| 60 | * @var string |
||
| 61 | */ |
||
| 62 | protected $_package_type = null; |
||
| 63 | |||
| 64 | /** |
||
| 65 | * Package type version. Required |
||
| 66 | * @var string |
||
| 67 | */ |
||
| 68 | protected $_package_type_version = null; |
||
| 69 | |||
| 70 | /** |
||
| 71 | * Package format. The only valid values are zip, url, jar, war and xml. Required |
||
| 72 | * @var string |
||
| 73 | */ |
||
| 74 | protected $_package_format = null; |
||
| 75 | |||
| 76 | /** |
||
| 77 | * Package id. Requires a valid URI according to RFC 2396. Required |
||
| 78 | * @var string |
||
| 79 | */ |
||
| 80 | protected $_package_id = null; |
||
| 81 | |||
| 82 | /** |
||
| 83 | * Package url. Requires a valid, fully qualified URL including transport protocol and filename extension. Required |
||
| 84 | * @var string |
||
| 85 | */ |
||
| 86 | protected $_package_url = null; |
||
| 87 | |||
| 88 | /** |
||
| 89 | * User id required for system to retrieve package from URL. Optional. |
||
| 90 | * @var string |
||
| 91 | */ |
||
| 92 | protected $_package_url_user_id = null; |
||
| 93 | |||
| 94 | /** |
||
| 95 | * Account required for system to retrieve package from URL. Optional. |
||
| 96 | * @var string |
||
| 97 | */ |
||
| 98 | protected $_package_url_account = null; |
||
| 99 | |||
| 100 | /** |
||
| 101 | * Password required for system to retrieve package from URL. Optional. |
||
| 102 | * @var string |
||
| 103 | */ |
||
| 104 | protected $_package_url_password = null; |
||
| 105 | |||
| 106 | /** |
||
| 107 | * Expiry date for package URL. ISO 8601 format expressed as UTC. Will be transformed into a PHP DateTime object during construction. Required |
||
| 108 | * @var DateTime |
||
| 109 | */ |
||
| 110 | protected $_package_url_expiry = null; |
||
| 111 | |||
| 112 | /** |
||
| 113 | * Name or ID for client submitting the content package to the target system. Required. |
||
| 114 | * @var string |
||
| 115 | */ |
||
| 116 | protected $_client = null; |
||
| 117 | |||
| 118 | /** |
||
| 119 | * User-id or sign-on for target system. Optional |
||
| 120 | * @var string |
||
| 121 | */ |
||
| 122 | protected $_system_user_id = null; |
||
| 123 | |||
| 124 | /** |
||
| 125 | * Either a URL-encoded password token or the null string. If the |
||
| 126 | * target system requires a password and the null string value is |
||
| 127 | * passed, then the target system is responsible for prompting for a |
||
| 128 | * password for target system. Optional |
||
| 129 | * @var string |
||
| 130 | */ |
||
| 131 | protected $_system_password = null; |
||
| 132 | |||
| 133 | /** |
||
| 134 | * URL to send acknowledgement receipt after collecting a package. Any URL, including mailto (as per RFC 2368 and RFC 2822). Required. |
||
| 135 | * @var string |
||
| 136 | */ |
||
| 137 | protected $_receipt = null; |
||
| 138 | |||
| 139 | /** |
||
| 140 | * URL to send alerts to while processing the package. Any URL, including mailto (as per RFC 2368 and RFC 2822). Optional. |
||
| 141 | * @var string |
||
| 142 | */ |
||
| 143 | protected $_alerts = null; |
||
| 144 | |||
| 145 | /** |
||
| 146 | * Unstructured character string that may be used to transfer vendor-specific data such as processing hints or deployment information. Optional. |
||
| 147 | * @var string |
||
| 148 | */ |
||
| 149 | protected $_vendor_data = null; |
||
| 150 | |||
| 151 | /** |
||
| 152 | * Constructor |
||
| 153 | * |
||
| 154 | * Constructs a PENSRequest based class using the arguments given |
||
| 155 | * |
||
| 156 | * @param array Arguments |
||
| 157 | */ |
||
| 158 | public function __construct($arguments) { |
||
| 159 | $this->setPensVersion($arguments["pens-version"]); |
||
| 160 | $this->setPackageType($arguments["package-type"]); |
||
| 161 | $this->setPackageTypeVersion($arguments["package-type-version"]); |
||
| 162 | $this->setPackageFormat($arguments["package-format"]); |
||
| 163 | $this->setPackageId($arguments["package-id"]); |
||
| 164 | $this->setPackageUrl($arguments["package-url"]); |
||
| 165 | $this->setPackageUrlUserId($arguments["package-url-user-id"]); |
||
| 166 | $this->setPackageUrlAccount($arguments["package-url-account"]); |
||
| 167 | $this->setPackageUrlPassword($arguments["package-url-password"]); |
||
| 168 | $this->setPackageUrlExpiry($arguments["package-url-expiry"]); |
||
| 169 | $this->setClient($arguments["client"]); |
||
| 170 | $this->setSystemUserId($arguments["system-user-id"]); |
||
| 171 | $this->setSystemPassword($arguments["system-password"]); |
||
| 172 | $this->setReceipt($arguments["receipt"]); |
||
| 173 | $this->setAlerts($arguments["alerts"]); |
||
| 174 | $this->setVendorData($arguments["vendor-data"]); |
||
| 175 | } |
||
| 176 | |||
| 177 | public function getPensVersion() { |
||
| 178 | return $this->_pens_version; |
||
| 179 | } |
||
| 180 | |||
| 181 | /** |
||
| 182 | * Sets the PENS version |
||
| 183 | * |
||
| 184 | * @param string PENS version |
||
| 185 | * |
||
| 186 | * @throws PENSException with code 2001 if invalid |
||
| 187 | */ |
||
| 188 | public function setPensVersion($pens_version) { |
||
| 189 | if($pens_version == PENSConfig::$version) { |
||
| 190 | $this->_pens_version = $pens_version; |
||
| 191 | } else { |
||
| 192 | throw new PENSException(2001); |
||
| 193 | } |
||
| 194 | } |
||
| 195 | |||
| 196 | public function getCommand() { |
||
| 197 | return $this->_command; |
||
| 198 | } |
||
| 199 | |||
| 200 | /** |
||
| 201 | * Sets the command |
||
| 202 | * |
||
| 203 | * @param string command |
||
| 204 | * |
||
| 205 | * @throws PENSException with code 2002 if invalid |
||
| 206 | */ |
||
| 207 | protected function setCommand($command) { |
||
| 208 | if(in_array($command, PENSConfig::$allowed_commands)) { |
||
| 209 | $this->_command = $command; |
||
| 210 | } else { |
||
| 211 | throw new PENSException(2002); |
||
| 212 | } |
||
| 213 | } |
||
| 214 | |||
| 215 | public function getPackageType() { |
||
| 216 | return $this->_package_type; |
||
| 217 | } |
||
| 218 | |||
| 219 | /** |
||
| 220 | * Sets the package type |
||
| 221 | * |
||
| 222 | * @param string package type |
||
| 223 | * |
||
| 224 | * @throws PENSException with code 2003 if invalid |
||
| 225 | */ |
||
| 226 | public function setPackageType($package_type) { |
||
| 227 | if(in_array($package_type, PENSConfig::$allowed_package_types)) { |
||
| 228 | $this->_package_type = $package_type; |
||
| 229 | } else { |
||
| 230 | throw new PENSException(2003); |
||
| 231 | } |
||
| 232 | } |
||
| 233 | |||
| 234 | public function getPackageTypeVersion() { |
||
| 235 | return $this->_package_type_version; |
||
| 236 | } |
||
| 237 | |||
| 238 | /** |
||
| 239 | * Sets the package type version |
||
| 240 | * |
||
| 241 | * @param string package type version |
||
| 242 | * |
||
| 243 | * @throws PENSException with code 2004 if invalid |
||
| 244 | */ |
||
| 245 | public function setPackageTypeVersion($package_type_version) { |
||
| 246 | if(empty($package_type_version)) { |
||
| 247 | throw new PENSException(2004); |
||
| 248 | } else { |
||
| 249 | $this->_package_type_version = $package_type_version; |
||
| 250 | } |
||
| 251 | } |
||
| 252 | |||
| 253 | public function getPackageFormat() { |
||
| 254 | return $this->_package_format; |
||
| 255 | } |
||
| 256 | |||
| 257 | /** |
||
| 258 | * Sets the package format |
||
| 259 | * |
||
| 260 | * @param string package format |
||
| 261 | * |
||
| 262 | * @throws PENSException with code 2005 if invalid |
||
| 263 | */ |
||
| 264 | public function setPackageFormat($package_format) { |
||
| 265 | if(in_array($package_format, PENSConfig::$allowed_package_formats)) { |
||
| 266 | $this->_package_format = $package_format; |
||
| 267 | } else { |
||
| 268 | throw new PENSException(2005); |
||
| 269 | } |
||
| 270 | } |
||
| 271 | |||
| 272 | public function getPackageId() { |
||
| 273 | return $this->_package_id; |
||
| 274 | } |
||
| 275 | |||
| 276 | /** |
||
| 277 | * Sets the package Id |
||
| 278 | * |
||
| 279 | * @param string package Id |
||
| 280 | * |
||
| 281 | * @throws PENSException with code 2007 if invalid |
||
| 282 | */ |
||
| 283 | public function setPackageId($package_id) { |
||
| 284 | if (preg_match('/'.ABSOLUTEURI_2396.'/', $package_id)) { |
||
| 285 | $this->_package_id = $package_id; |
||
| 286 | } else { |
||
| 287 | throw new PENSException(2007); |
||
| 288 | } |
||
| 289 | } |
||
| 290 | |||
| 291 | public function getPackageUrl() { |
||
| 292 | return $this->_package_url; |
||
| 293 | } |
||
| 294 | |||
| 295 | /** |
||
| 296 | * Sets the package url |
||
| 297 | * |
||
| 298 | * @param string package url |
||
| 299 | * |
||
| 300 | * @throws PENSException with code 2008 if invalid |
||
| 301 | */ |
||
| 302 | public function setPackageUrl($package_url) { |
||
| 303 | if (preg_match('/'.ABSOLUTEURI_2396.'/', $package_url) && substr($package_url, -4) == ".".$this->_package_format) { |
||
| 304 | $this->_package_url = $package_url; |
||
| 305 | } else { |
||
| 306 | throw new PENSException(2008); |
||
| 307 | } |
||
| 308 | } |
||
| 309 | |||
| 310 | public function getFilename() { |
||
| 311 | return substr(strrchr($this->_package_url, "/"), 1); |
||
| 312 | } |
||
| 313 | |||
| 314 | public function getPackageUrlUserId() { |
||
| 315 | return $this->_package_url_user_id; |
||
| 316 | } |
||
| 317 | |||
| 318 | public function setPackageUrlUserId($package_url_user_id) { |
||
| 319 | if(!empty($package_url_user_id)) { |
||
| 320 | $this->_package_url_user_id = $package_url_user_id; |
||
| 321 | } |
||
| 322 | } |
||
| 323 | |||
| 324 | public function getPackageUrlAccount() { |
||
| 325 | return $this->_package_url_account; |
||
| 326 | } |
||
| 327 | |||
| 328 | public function setPackageUrlAccount($package_url_account) { |
||
| 329 | if(!empty($package_url_account)) { |
||
| 330 | $this->_package_url_account = $package_url_account; |
||
| 331 | } |
||
| 332 | } |
||
| 333 | |||
| 334 | public function getPackageUrlPassword() { |
||
| 335 | return $this->_package_url_password; |
||
| 336 | } |
||
| 337 | |||
| 338 | public function setPackageUrlPassword($package_url_password) { |
||
| 339 | if(!empty($package_url_password)) { |
||
| 340 | $this->_package_url_password = $package_url_password; |
||
| 341 | } |
||
| 342 | } |
||
| 343 | |||
| 344 | public function getPackageUrlExpiry() { |
||
| 345 | return $this->_package_url_expiry; |
||
| 346 | } |
||
| 347 | |||
| 348 | /** |
||
| 349 | * Sets the package url expiry and transforms it into a php DateTime object |
||
| 350 | * |
||
| 351 | * @param string package url expiry |
||
| 352 | * |
||
| 353 | * @throws PENSException with code 2009 if invalid |
||
| 354 | * @todo Perform a better validation of the date |
||
| 355 | */ |
||
| 356 | public function setPackageUrlExpiry($package_url_expiry) { |
||
| 357 | if(empty($package_url_expiry)) { |
||
| 358 | throw new PENSException(2009); |
||
| 359 | } else { |
||
| 360 | try { |
||
| 361 | $expiry = new DateTime($package_url_expiry, new DateTimeZone('UTC')); |
||
| 362 | $this->_package_url_expiry = $expiry; |
||
| 363 | } catch(Exception $e) { |
||
| 364 | throw new PENSException(2009); |
||
| 365 | } |
||
| 366 | } |
||
| 367 | } |
||
| 368 | |||
| 369 | public function getClient() { |
||
| 370 | return $this->_client; |
||
| 371 | } |
||
| 372 | |||
| 373 | /** |
||
| 374 | * Sets the client |
||
| 375 | * |
||
| 376 | * @param string client |
||
| 377 | * |
||
| 378 | * @throws PENSException with code 2010 if invalid |
||
| 379 | */ |
||
| 380 | public function setClient($client) { |
||
| 381 | if(!empty($client)) { |
||
| 382 | $this->_client = $client; |
||
| 383 | } else { |
||
| 384 | throw new PENSException(2010); |
||
| 385 | } |
||
| 386 | } |
||
| 387 | |||
| 388 | public function getSystemUserId() { |
||
| 389 | return $this->_system_user_id; |
||
| 390 | } |
||
| 391 | |||
| 392 | public function setSystemUserId($system_user_id) { |
||
| 393 | if(!empty($system_user_id)) { |
||
| 394 | $this->_system_user_id = $system_user_id; |
||
| 395 | } |
||
| 396 | } |
||
| 397 | |||
| 398 | public function getSystemPassword() { |
||
| 399 | return $this->_system_password; |
||
| 400 | } |
||
| 401 | |||
| 402 | public function setSystemPassword($system_password) { |
||
| 403 | if(!empty($system_password)) { |
||
| 404 | $this->_system_password = $system_password; |
||
| 405 | } |
||
| 406 | } |
||
| 407 | |||
| 408 | public function getReceipt() { |
||
| 409 | return $this->_receipt; |
||
| 410 | } |
||
| 411 | |||
| 412 | /** |
||
| 413 | * Sets the receipt url |
||
| 414 | * |
||
| 415 | * @param string receipt url |
||
| 416 | * |
||
| 417 | * @throws PENSException with code 2011 if invalid |
||
| 418 | */ |
||
| 419 | public function setReceipt($receipt) { |
||
| 420 | if($this instanceof PENSRequestCollect) { |
||
| 421 | if (preg_match('/'.ABSOLUTEURI_2396.'/', $receipt)) { |
||
| 422 | $this->_receipt = $receipt; |
||
| 423 | } else { |
||
| 424 | throw new PENSException(2011); |
||
| 425 | } |
||
| 426 | } |
||
| 427 | } |
||
| 428 | |||
| 429 | public function getAlerts() { |
||
| 430 | return $this->_alerts; |
||
| 431 | } |
||
| 432 | |||
| 433 | public function setAlerts($alerts) { |
||
| 434 | if(!empty($alerts)) { |
||
| 435 | if(preg_match('/'.ABSOLUTEURI_2396.'/', $alerts)) { |
||
| 436 | $this->_alerts = $alerts; |
||
| 437 | } else { |
||
| 438 | throw new PENSException(1201); |
||
| 439 | } |
||
| 440 | } |
||
| 441 | } |
||
| 442 | |||
| 443 | public function getVendorData() { |
||
| 444 | return $this->_vendor_data; |
||
| 445 | } |
||
| 446 | |||
| 447 | public function setVendorData($vendor_data) { |
||
| 448 | if(!empty($vendor_data)) { |
||
| 449 | $this->_vendor_data = $vendor_data; |
||
| 450 | } |
||
| 451 | } |
||
| 452 | |||
| 453 | /** |
||
| 454 | * Returns an associative that contains all the fields needed to send a |
||
| 455 | * receipt or an alert to the client |
||
| 456 | * |
||
| 457 | * @return array Associative array |
||
| 458 | */ |
||
| 459 | protected function getSendReceiptAlertArray() { |
||
| 460 | return array("pens-version" => $this->getPensVersion(), |
||
| 461 | "package-type" => $this->getPackageType(), |
||
| 462 | "package-type-version" => $this->getPackageTypeVersion(), |
||
| 463 | "package-format" => $this->getPackageFormat(), |
||
| 464 | "package-id" => $this->getPackageId(), |
||
| 465 | "package-url" => $this->getPackageUrl(), |
||
| 466 | "package-url-expiry" => $this->getPackageUrlExpiry()->format(DateTime::ISO8601), |
||
| 467 | "client" => $this->getClient()); |
||
| 468 | } |
||
| 469 | |||
| 470 | /** |
||
| 471 | * Returns an associative that contains all the fields needed to send a |
||
| 472 | * receipt to the client |
||
| 473 | * |
||
| 474 | * @return array Associative array |
||
| 475 | */ |
||
| 476 | public function getSendReceiptArray() { |
||
| 477 | $receipt = $this->getSendReceiptAlertArray(); |
||
| 478 | $receipt["command"] = "receipt"; |
||
| 479 | return $receipt; |
||
| 480 | } |
||
| 481 | |||
| 482 | /** |
||
| 483 | * Returns an associative that contains all the fields needed to send an |
||
| 484 | * alert to the client |
||
| 485 | * |
||
| 486 | * @return array Associative array |
||
| 487 | */ |
||
| 488 | public function getSendAlertArray() { |
||
| 489 | $alert = $this->getSendReceiptAlertArray(); |
||
| 490 | $alert["command"] = "alert"; |
||
| 491 | return $alert; |
||
| 492 | } |
||
| 493 | |||
| 494 | |||
| 495 | } |
||
| 496 |