Complex classes like AbstractSubject 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 AbstractSubject, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 46 | abstract class AbstractSubject implements SubjectInterface |
||
| 47 | { |
||
| 48 | |||
| 49 | /** |
||
| 50 | * The trait that provides basic filesystem handling functionality. |
||
| 51 | * |
||
| 52 | * @var TechDivision\Import\Subjects\FilesystemTrait |
||
| 53 | */ |
||
| 54 | use FilesystemTrait; |
||
| 55 | |||
| 56 | /** |
||
| 57 | * The system configuration. |
||
| 58 | * |
||
| 59 | * @var \TechDivision\Import\Configuration\SubjectConfigurationInterface |
||
| 60 | */ |
||
| 61 | protected $configuration; |
||
| 62 | |||
| 63 | /** |
||
| 64 | * The system logger implementation. |
||
| 65 | * |
||
| 66 | * @var \Psr\Log\LoggerInterface |
||
| 67 | */ |
||
| 68 | protected $systemLogger; |
||
| 69 | |||
| 70 | /** |
||
| 71 | * The RegistryProcessor instance to handle running threads. |
||
| 72 | * |
||
| 73 | * @var \TechDivision\Import\Services\RegistryProcessorInterface |
||
| 74 | */ |
||
| 75 | protected $registryProcessor; |
||
| 76 | |||
| 77 | /** |
||
| 78 | * The actions unique serial. |
||
| 79 | * |
||
| 80 | * @var string |
||
| 81 | */ |
||
| 82 | protected $serial; |
||
| 83 | |||
| 84 | /** |
||
| 85 | * The name of the file to be imported. |
||
| 86 | * |
||
| 87 | * @var string |
||
| 88 | */ |
||
| 89 | protected $filename; |
||
| 90 | |||
| 91 | /** |
||
| 92 | * Array with the subject's observers. |
||
| 93 | * |
||
| 94 | * @var array |
||
| 95 | */ |
||
| 96 | protected $observers = array(); |
||
| 97 | |||
| 98 | /** |
||
| 99 | * Array with the subject's callbacks. |
||
| 100 | * |
||
| 101 | * @var array |
||
| 102 | */ |
||
| 103 | protected $callbacks = array(); |
||
| 104 | |||
| 105 | /** |
||
| 106 | * The subject's callback mappings. |
||
| 107 | * |
||
| 108 | * @var array |
||
| 109 | */ |
||
| 110 | protected $callbackMappings = array(); |
||
| 111 | |||
| 112 | /** |
||
| 113 | * Contain's the column names from the header line. |
||
| 114 | * |
||
| 115 | * @var array |
||
| 116 | */ |
||
| 117 | protected $headers = array(); |
||
| 118 | |||
| 119 | /** |
||
| 120 | * The actual line number. |
||
| 121 | * |
||
| 122 | * @var integer |
||
| 123 | */ |
||
| 124 | protected $lineNumber = 0; |
||
| 125 | |||
| 126 | /** |
||
| 127 | * The actual operation name. |
||
| 128 | * |
||
| 129 | * @var string |
||
| 130 | */ |
||
| 131 | protected $operationName ; |
||
| 132 | |||
| 133 | /** |
||
| 134 | * The flag that stop's overserver execution on the actual row. |
||
| 135 | * |
||
| 136 | * @var boolean |
||
| 137 | */ |
||
| 138 | protected $skipRow = false; |
||
| 139 | |||
| 140 | /** |
||
| 141 | * The available root categories. |
||
| 142 | * |
||
| 143 | * @var array |
||
| 144 | */ |
||
| 145 | protected $rootCategories = array(); |
||
| 146 | |||
| 147 | /** |
||
| 148 | * The default store. |
||
| 149 | * |
||
| 150 | * @var array |
||
| 151 | */ |
||
| 152 | protected $defaultStore; |
||
| 153 | |||
| 154 | /** |
||
| 155 | * The store view code the create the product/attributes for. |
||
| 156 | * |
||
| 157 | * @var string |
||
| 158 | */ |
||
| 159 | protected $storeViewCode; |
||
| 160 | |||
| 161 | /** |
||
| 162 | * Initialize the subject instance. |
||
| 163 | * |
||
| 164 | * @param \Psr\Log\LoggerInterface $systemLogger The system logger instance |
||
| 165 | * @param \TechDivision\Import\Configuration\SubjectConfigurationInterface $configuration The subject configuration instance |
||
| 166 | * @param \TechDivision\Import\Services\RegistryProcessorInterface $registryProcessor The registry processor instance |
||
| 167 | */ |
||
| 168 | public function __construct( |
||
| 177 | |||
| 178 | /** |
||
| 179 | * Return's the default callback mappings. |
||
| 180 | * |
||
| 181 | * @return array The default callback mappings |
||
| 182 | */ |
||
| 183 | public function getDefaultCallbackMappings() |
||
| 187 | |||
| 188 | /** |
||
| 189 | * Stop's observer execution on the actual row. |
||
| 190 | * |
||
| 191 | * @return void |
||
| 192 | */ |
||
| 193 | public function skipRow() |
||
| 197 | |||
| 198 | /** |
||
| 199 | * Return's the actual line number. |
||
| 200 | * |
||
| 201 | * @return integer The line number |
||
| 202 | */ |
||
| 203 | public function getLineNumber() |
||
| 207 | |||
| 208 | /** |
||
| 209 | * Return's the actual operation name. |
||
| 210 | * |
||
| 211 | * @return string |
||
| 212 | */ |
||
| 213 | public function getOperationName() |
||
| 217 | |||
| 218 | /** |
||
| 219 | * Set's the array containing header row. |
||
| 220 | * |
||
| 221 | * @param array $headers The array with the header row |
||
| 222 | * |
||
| 223 | * @return void |
||
| 224 | */ |
||
| 225 | public function setHeaders(array $headers) |
||
| 229 | |||
| 230 | /** |
||
| 231 | * Return's the array containing header row. |
||
| 232 | * |
||
| 233 | * @return array The array with the header row |
||
| 234 | */ |
||
| 235 | public function getHeaders() |
||
| 239 | |||
| 240 | /** |
||
| 241 | * Queries whether or not the header with the passed name is available. |
||
| 242 | * |
||
| 243 | * @param string $name The header name to query |
||
| 244 | * |
||
| 245 | * @return boolean TRUE if the header is available, else FALSE |
||
| 246 | */ |
||
| 247 | public function hasHeader($name) |
||
| 251 | |||
| 252 | /** |
||
| 253 | * Return's the header value for the passed name. |
||
| 254 | * |
||
| 255 | * @param string $name The name of the header to return the value for |
||
| 256 | * |
||
| 257 | * @return mixed The header value |
||
| 258 | * \InvalidArgumentException Is thrown, if the header with the passed name is NOT available |
||
| 259 | */ |
||
| 260 | public function getHeader($name) |
||
| 271 | |||
| 272 | /** |
||
| 273 | * Add's the header with the passed name and position, if not NULL. |
||
| 274 | * |
||
| 275 | * @param string $name The header name to add |
||
| 276 | * |
||
| 277 | * @return integer The new headers position |
||
| 278 | */ |
||
| 279 | public function addHeader($name) |
||
| 288 | |||
| 289 | /** |
||
| 290 | * Queries whether or not debug mode is enabled or not, default is TRUE. |
||
| 291 | * |
||
| 292 | * @return boolean TRUE if debug mode is enabled, else FALSE |
||
| 293 | */ |
||
| 294 | public function isDebugMode() |
||
| 298 | |||
| 299 | /** |
||
| 300 | * Return's the system configuration. |
||
| 301 | * |
||
| 302 | * @return \TechDivision\Import\Configuration\SubjectConfigurationInterface The system configuration |
||
| 303 | */ |
||
| 304 | public function getConfiguration() |
||
| 308 | |||
| 309 | /** |
||
| 310 | * Return's the system logger. |
||
| 311 | * |
||
| 312 | * @return \Psr\Log\LoggerInterface The system logger instance |
||
| 313 | */ |
||
| 314 | public function getSystemLogger() |
||
| 318 | |||
| 319 | /** |
||
| 320 | * Return's the RegistryProcessor instance to handle the running threads. |
||
| 321 | * |
||
| 322 | * @return \TechDivision\Import\Services\RegistryProcessorInterface The registry processor instance |
||
| 323 | */ |
||
| 324 | public function getRegistryProcessor() |
||
| 328 | |||
| 329 | /** |
||
| 330 | * Set's the unique serial for this import process. |
||
| 331 | * |
||
| 332 | * @param string $serial The unique serial |
||
| 333 | * |
||
| 334 | * @return void |
||
| 335 | */ |
||
| 336 | public function setSerial($serial) |
||
| 340 | |||
| 341 | /** |
||
| 342 | * Return's the unique serial for this import process. |
||
| 343 | * |
||
| 344 | * @return string The unique serial |
||
| 345 | */ |
||
| 346 | public function getSerial() |
||
| 350 | |||
| 351 | /** |
||
| 352 | * Set's the name of the file to import |
||
| 353 | * |
||
| 354 | * @param string $filename The filename |
||
| 355 | * |
||
| 356 | * @return void |
||
| 357 | */ |
||
| 358 | public function setFilename($filename) |
||
| 362 | |||
| 363 | /** |
||
| 364 | * Return's the name of the file to import. |
||
| 365 | * |
||
| 366 | * @return string The filename |
||
| 367 | */ |
||
| 368 | public function getFilename() |
||
| 372 | |||
| 373 | /** |
||
| 374 | * Return's the source date format to use. |
||
| 375 | * |
||
| 376 | * @return string The source date format |
||
| 377 | */ |
||
| 378 | public function getSourceDateFormat() |
||
| 382 | |||
| 383 | /** |
||
| 384 | * Return's the multiple field delimiter character to use, default value is comma (,). |
||
| 385 | * |
||
| 386 | * @return string The multiple field delimiter character |
||
| 387 | */ |
||
| 388 | public function getMultipleFieldDelimiter() |
||
| 392 | |||
| 393 | /** |
||
| 394 | * Return's the initialized PDO connection. |
||
| 395 | * |
||
| 396 | * @return \PDO The initialized PDO connection |
||
| 397 | */ |
||
| 398 | public function getConnection() |
||
| 402 | |||
| 403 | /** |
||
| 404 | * Intializes the previously loaded global data for exactly one bunch. |
||
| 405 | * |
||
| 406 | * @return void |
||
| 407 | * @see \Importer\Csv\Actions\ProductImportAction::prepare() |
||
| 408 | */ |
||
| 409 | public function setUp() |
||
| 445 | |||
| 446 | /** |
||
| 447 | * Clean up the global data after importing the variants. |
||
| 448 | * |
||
| 449 | * @return void |
||
| 450 | */ |
||
| 451 | public function tearDown() |
||
| 468 | |||
| 469 | /** |
||
| 470 | * Return's the next source directory, which will be the target directory |
||
| 471 | * of this subject, in most cases. |
||
| 472 | * |
||
| 473 | * @return string The new source directory |
||
| 474 | */ |
||
| 475 | protected function getNewSourceDir() |
||
| 479 | |||
| 480 | /** |
||
| 481 | * Register the passed observer with the specific type. |
||
| 482 | * |
||
| 483 | * @param \TechDivision\Import\Observers\ObserverInterface $observer The observer to register |
||
| 484 | * @param string $type The type to register the observer with |
||
| 485 | * |
||
| 486 | * @return void |
||
| 487 | */ |
||
| 488 | public function registerObserver(ObserverInterface $observer, $type) |
||
| 500 | |||
| 501 | /** |
||
| 502 | * Register the passed callback with the specific type. |
||
| 503 | * |
||
| 504 | * @param \TechDivision\Import\Callbacks\CallbackInterface $callback The subject to register the callbacks for |
||
| 505 | * @param string $type The type to register the callback with |
||
| 506 | * |
||
| 507 | * @return void |
||
| 508 | */ |
||
| 509 | public function registerCallback(CallbackInterface $callback, $type) |
||
| 521 | |||
| 522 | /** |
||
| 523 | * Return's the array with callbacks for the passed type. |
||
| 524 | * |
||
| 525 | * @param string $type The type of the callbacks to return |
||
| 526 | * |
||
| 527 | * @return array The callbacks |
||
| 528 | */ |
||
| 529 | public function getCallbacksByType($type) |
||
| 543 | |||
| 544 | /** |
||
| 545 | * Return's the array with the available observers. |
||
| 546 | * |
||
| 547 | * @return array The observers |
||
| 548 | */ |
||
| 549 | public function getObservers() |
||
| 553 | |||
| 554 | /** |
||
| 555 | * Return's the array with the available callbacks. |
||
| 556 | * |
||
| 557 | * @return array The callbacks |
||
| 558 | */ |
||
| 559 | public function getCallbacks() |
||
| 563 | |||
| 564 | /** |
||
| 565 | * Return's the callback mappings for this subject. |
||
| 566 | * |
||
| 567 | * @return array The array with the subject's callback mappings |
||
| 568 | */ |
||
| 569 | public function getCallbackMappings() |
||
| 573 | |||
| 574 | /** |
||
| 575 | * Imports the content of the file with the passed filename. |
||
| 576 | * |
||
| 577 | * @param string $serial The unique process serial |
||
| 578 | * @param string $filename The filename to process |
||
| 579 | * |
||
| 580 | * @return void |
||
| 581 | * @throws \Exception Is thrown, if the import can't be processed |
||
| 582 | */ |
||
| 583 | public function import($serial, $filename) |
||
| 668 | |||
| 669 | /** |
||
| 670 | * This method queries whether or not the passed filename matches |
||
| 671 | * the pattern, based on the subjects configured prefix. |
||
| 672 | * |
||
| 673 | * @param string $filename The filename to match |
||
| 674 | * |
||
| 675 | * @return boolean TRUE if the filename matches, else FALSE |
||
| 676 | */ |
||
| 677 | protected function match($filename) |
||
| 686 | |||
| 687 | /** |
||
| 688 | * Initialize and return the lexer configuration. |
||
| 689 | * |
||
| 690 | * @return \Goodby\CSV\Import\Standard\LexerConfig The lexer configuration |
||
| 691 | */ |
||
| 692 | protected function getLexerConfig() |
||
| 726 | |||
| 727 | /** |
||
| 728 | * Imports the passed row into the database. |
||
| 729 | * |
||
| 730 | * If the import failed, the exception will be catched and logged, |
||
| 731 | * but the import process will be continued. |
||
| 732 | * |
||
| 733 | * @param array $row The row with the data to be imported |
||
| 734 | * |
||
| 735 | * @return void |
||
| 736 | */ |
||
| 737 | public function importRow(array $row) |
||
| 777 | |||
| 778 | /** |
||
| 779 | * Map the passed attribute code, if a header mapping exists and return the |
||
| 780 | * mapped mapping. |
||
| 781 | * |
||
| 782 | * @param string $attributeCode The attribute code to map |
||
| 783 | * |
||
| 784 | * @return string The mapped attribute code, or the original one |
||
| 785 | */ |
||
| 786 | public function mapAttributeCodeByHeaderMapping($attributeCode) |
||
| 800 | |||
| 801 | /** |
||
| 802 | * Queries whether or not that the subject needs an OK file to be processed. |
||
| 803 | * |
||
| 804 | * @return boolean TRUE if the subject needs an OK file, else FALSE |
||
| 805 | */ |
||
| 806 | public function isOkFileNeeded() |
||
| 810 | |||
| 811 | /** |
||
| 812 | * Return's the default store. |
||
| 813 | * |
||
| 814 | * @return array The default store |
||
| 815 | */ |
||
| 816 | public function getDefaultStore() |
||
| 820 | |||
| 821 | /** |
||
| 822 | * Set's the store view code the create the product/attributes for. |
||
| 823 | * |
||
| 824 | * @param string $storeViewCode The store view code |
||
| 825 | * |
||
| 826 | * @return void |
||
| 827 | */ |
||
| 828 | public function setStoreViewCode($storeViewCode) |
||
| 832 | |||
| 833 | /** |
||
| 834 | * Return's the store view code the create the product/attributes for. |
||
| 835 | * |
||
| 836 | * @param string|null $default The default value to return, if the store view code has not been set |
||
| 837 | * |
||
| 838 | * @return string The store view code |
||
| 839 | */ |
||
| 840 | public function getStoreViewCode($default = null) |
||
| 854 | |||
| 855 | /** |
||
| 856 | * Return's the root category for the actual view store. |
||
| 857 | * |
||
| 858 | * @return array The store's root category |
||
| 859 | * @throws \Exception Is thrown if the root category for the passed store code is NOT available |
||
| 860 | */ |
||
| 861 | public function getRootCategory() |
||
| 878 | } |
||
| 879 |
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_functionexpects aPostobject, and outputs the author of the post. The base classPostreturns a simple string and outputting a simple string will work just fine. However, the child classBlogPostwhich is a sub-type ofPostinstead decided to return anobject, and is therefore violating the SOLID principles. If aBlogPostwere passed tomy_function, PHP would not complain, but ultimately fail when executing thestrtouppercall in its body.