Complex classes like HtmlElement 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 HtmlElement, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 9 | class HtmlElement implements HtmlElementInterface |
||
| 10 | { |
||
| 11 | /** @var array */ |
||
| 12 | private $map; |
||
| 13 | |||
| 14 | /** @var EscaperInterface */ |
||
| 15 | private $escaper; |
||
| 16 | |||
| 17 | /** @var array The already resolved elements */ |
||
| 18 | private $resolved = array(); |
||
| 19 | |||
| 20 | /** @var array The default values of element options */ |
||
| 21 | private $defaults = array( |
||
| 22 | 'parent' => null, |
||
| 23 | 'children' => array(), |
||
| 24 | 'extends' => array(), |
||
| 25 | 'attr' => array(), |
||
| 26 | 'text' => null, |
||
| 27 | 'type' => null, |
||
| 28 | 'class' => Element::class |
||
| 29 | ); |
||
| 30 | |||
| 31 | /** @var array The options to check to valid a branch */ |
||
| 32 | private $checks = array('parent', 'extends', 'children'); |
||
| 33 | |||
| 34 | /** @var array The mergeable attributes */ |
||
| 35 | private $mergeableAttributes = array('class', 'style'); |
||
| 36 | |||
| 37 | /** @var array The special escaping types */ |
||
| 38 | private $specialEscapingTypes = array('script', 'style'); |
||
| 39 | |||
| 40 | /** @var bool Determine if html is escaped or not */ |
||
| 41 | private $escapeHtml = true; |
||
| 42 | |||
| 43 | /** @var bool Determine if html attributes are escaped or not */ |
||
| 44 | private $escapeHtmlAttr = true; |
||
| 45 | |||
| 46 | /** @var bool Determine if javascript is escaped or not */ |
||
| 47 | private $escapeJs = true; |
||
| 48 | |||
| 49 | /** @var bool Determine if css is escaped or not */ |
||
| 50 | private $escapeCss = true; |
||
| 51 | |||
| 52 | /** @var bool Determine if urls are escaped or not */ |
||
| 53 | private $escapeUrl = true; |
||
| 54 | |||
| 55 | /** |
||
| 56 | * HtmlElement constructor. |
||
| 57 | * |
||
| 58 | * @param array $map The elements map |
||
| 59 | * @param EscaperInterface|null $escaper The escaper, by default ZendFramework/Escaper is used |
||
| 60 | * @param string $encoding The encoding used for escaping, by default utf-8 is used |
||
| 61 | */ |
||
| 62 | public function __construct(array $map = array(), EscaperInterface $escaper = null, $encoding = 'utf-8') |
||
| 67 | |||
| 68 | /** |
||
| 69 | * Create element on static calls. |
||
| 70 | * |
||
| 71 | * @param string $type The element type |
||
| 72 | * @param array $arguments The arguments array to set: |
||
| 73 | * [0] = text (string) |
||
| 74 | * [1] = attributes (array) |
||
| 75 | * [2] = children (array) |
||
| 76 | * |
||
| 77 | * @return ElementInterface |
||
| 78 | * |
||
| 79 | * @throws InvalidArgumentsNumberException If the arguments length is more than 3 |
||
| 80 | */ |
||
| 81 | public static function __callStatic($type, $arguments) |
||
| 100 | |||
| 101 | /** |
||
| 102 | * {@inheritdoc} |
||
| 103 | */ |
||
| 104 | public static function create($type = null, $text = null, array $attributes = array(), array $children = array()) |
||
| 116 | |||
| 117 | /** |
||
| 118 | * {@inheritdoc} |
||
| 119 | */ |
||
| 120 | public function escapeAttributes(array $attributes) |
||
| 140 | |||
| 141 | /** |
||
| 142 | * {@inheritdoc} |
||
| 143 | */ |
||
| 144 | public function escape(ElementInterface $element) |
||
| 162 | |||
| 163 | /** |
||
| 164 | * {@inheritdoc} |
||
| 165 | */ |
||
| 166 | public function getMap() |
||
| 170 | |||
| 171 | /** |
||
| 172 | * {@inheritdoc} |
||
| 173 | */ |
||
| 174 | public function setMap(array $map) |
||
| 180 | |||
| 181 | /** |
||
| 182 | * {@inheritdoc} |
||
| 183 | */ |
||
| 184 | public function addManyToMap(array $elements) |
||
| 192 | |||
| 193 | /** |
||
| 194 | * {@inheritdoc} |
||
| 195 | */ |
||
| 196 | public function addOneToMap($name, array $element) |
||
| 202 | |||
| 203 | /** |
||
| 204 | * {@inheritdoc} |
||
| 205 | */ |
||
| 206 | public function getEscaper() |
||
| 210 | |||
| 211 | /** |
||
| 212 | * {@inheritdoc} |
||
| 213 | */ |
||
| 214 | public function setEscaper(EscaperInterface $escaper) |
||
| 220 | |||
| 221 | /** |
||
| 222 | * {@inheritdoc} |
||
| 223 | */ |
||
| 224 | public function isEscapeHtml() |
||
| 228 | |||
| 229 | /** |
||
| 230 | * {@inheritdoc} |
||
| 231 | */ |
||
| 232 | public function setEscapeHtml($escapeHtml = true) |
||
| 238 | |||
| 239 | /** |
||
| 240 | * {@inheritdoc} |
||
| 241 | */ |
||
| 242 | public function isEscapeHtmlAttr() |
||
| 246 | |||
| 247 | /** |
||
| 248 | * {@inheritdoc} |
||
| 249 | */ |
||
| 250 | public function setEscapeHtmlAttr($escapeHtmlAttr = true) |
||
| 256 | |||
| 257 | /** |
||
| 258 | * {@inheritdoc} |
||
| 259 | */ |
||
| 260 | public function isEscapeJs() |
||
| 264 | |||
| 265 | /** |
||
| 266 | * {@inheritdoc} |
||
| 267 | */ |
||
| 268 | public function setEscapeJs($escapeJs = true) |
||
| 274 | |||
| 275 | /** |
||
| 276 | * {@inheritdoc} |
||
| 277 | */ |
||
| 278 | public function isEscapeCss() |
||
| 282 | |||
| 283 | /** |
||
| 284 | * {@inheritdoc} |
||
| 285 | */ |
||
| 286 | public function setEscapeCss($escapeCss = true) |
||
| 292 | |||
| 293 | /** |
||
| 294 | * {@inheritdoc} |
||
| 295 | */ |
||
| 296 | public function isEscapeUrl() |
||
| 300 | |||
| 301 | /** |
||
| 302 | * {@inheritdoc} |
||
| 303 | */ |
||
| 304 | public function setEscapeUrl($escapeUrl = true) |
||
| 310 | |||
| 311 | /** |
||
| 312 | * {@inheritdoc} |
||
| 313 | */ |
||
| 314 | public function load($name, array $parameters = array(), array $attributes = array(), array $children = array()) |
||
| 326 | |||
| 327 | /** |
||
| 328 | * Get the element instance. |
||
| 329 | * |
||
| 330 | * @param string $name The element name |
||
| 331 | * @param array $parameters The parameters to replace in element |
||
| 332 | * @param bool $mainCall Determine if it's the main(first) call of the method |
||
| 333 | * |
||
| 334 | * @return ElementInterface |
||
| 335 | * |
||
| 336 | * @throws InvalidElementException If the current instance doesn't implement ElementInterface |
||
| 337 | */ |
||
| 338 | private function getInstance($name, array $parameters, $mainCall = false) |
||
| 372 | |||
| 373 | /** |
||
| 374 | * Get the resolved element representation. |
||
| 375 | * |
||
| 376 | * @param string $name The current element name |
||
| 377 | * @param array $parameters The parameters to replace in element |
||
| 378 | * @param bool $mainCall Determine if it's the main(first) call of the method |
||
| 379 | * |
||
| 380 | * @return array |
||
| 381 | */ |
||
| 382 | private function resolveElement($name, array $parameters, $mainCall = false) |
||
| 413 | |||
| 414 | /** |
||
| 415 | * Check if an element has been already resolved. |
||
| 416 | * |
||
| 417 | * @param string $name |
||
| 418 | * |
||
| 419 | * @return bool |
||
| 420 | */ |
||
| 421 | private function alreadyResolved($name) |
||
| 425 | |||
| 426 | /** |
||
| 427 | * {@inheritdoc} |
||
| 428 | */ |
||
| 429 | public function exists($name) |
||
| 433 | |||
| 434 | /** |
||
| 435 | * Valid the current map branch. |
||
| 436 | * |
||
| 437 | * @param string $name The current element name |
||
| 438 | * @param array $circular The array of elements names called in the current branch of map |
||
| 439 | */ |
||
| 440 | private function validBranch($name, array $circular = array()) |
||
| 461 | |||
| 462 | /** |
||
| 463 | * Validate the current element class. |
||
| 464 | * |
||
| 465 | * @param array $current The current element |
||
| 466 | * |
||
| 467 | * @throws InvalidElementException If the current element defines a class which doesn't exist |
||
| 468 | */ |
||
| 469 | private function validClass(array $current) |
||
| 478 | |||
| 479 | /** |
||
| 480 | * Validate himself references. |
||
| 481 | * |
||
| 482 | * @param string $name The current element name |
||
| 483 | * @param array $currentCheck The current check context |
||
| 484 | * @param string $check The current check name |
||
| 485 | * |
||
| 486 | * @throws InvalidElementException If the current element defines himself as parent, children or extends |
||
| 487 | */ |
||
| 488 | private function validDefineHimself($name, array $currentCheck, $check) |
||
| 498 | |||
| 499 | /** |
||
| 500 | * Validate circular references. |
||
| 501 | * |
||
| 502 | * @param string $name The current element name |
||
| 503 | * @param string|array $currentCheck The current check context |
||
| 504 | * @param string $check The current check name |
||
| 505 | * @param array $circular The names of the previous elements called |
||
| 506 | * |
||
| 507 | * @throws InvalidElementException If the current element defines a parent, child or extends which creates circular |
||
| 508 | * reference |
||
| 509 | */ |
||
| 510 | private function validCircularReferences($name, $currentCheck, $check, array $circular) |
||
| 524 | |||
| 525 | /** |
||
| 526 | * Get the current element representation. |
||
| 527 | * |
||
| 528 | * @param string $name The element name |
||
| 529 | * |
||
| 530 | * @return array |
||
| 531 | * |
||
| 532 | * @throws InvalidElementException If the current element is defined dynamically and doesn't define a name |
||
| 533 | * @throws UndefinedElementException If the current element doesn't exist |
||
| 534 | */ |
||
| 535 | private function getCurrentElement($name) |
||
| 556 | |||
| 557 | /** |
||
| 558 | * Replace the parameters of the element. |
||
| 559 | * |
||
| 560 | * @param array $element The element with the parameters to replace |
||
| 561 | * @param array $parameters The array of parameters values |
||
| 562 | * |
||
| 563 | * @return array |
||
| 564 | */ |
||
| 565 | private function replaceParameters(array $element, array $parameters) |
||
| 583 | |||
| 584 | /** |
||
| 585 | * Extend element from another one. |
||
| 586 | * |
||
| 587 | * @param array $extend The array of the element to extend |
||
| 588 | * @param array $current The current element which extends |
||
| 589 | * |
||
| 590 | * @return array |
||
| 591 | */ |
||
| 592 | private function extendElement($extend, $current) |
||
| 600 | |||
| 601 | /** |
||
| 602 | * Extend attributes from another element. |
||
| 603 | * |
||
| 604 | * @param array $from The array of attributes to extend |
||
| 605 | * @param array $to The array of attributes which extends |
||
| 606 | * |
||
| 607 | * @return array |
||
| 608 | */ |
||
| 609 | private function extendAttributes(array $from, array $to) |
||
| 623 | } |
||
| 624 |