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 Registry 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 Registry, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 23 | class Registry |
||
| 24 | { |
||
| 25 | |||
| 26 | /** |
||
| 27 | * @var EE_Template_Config $template_config |
||
| 28 | */ |
||
| 29 | protected $template_config; |
||
| 30 | |||
| 31 | /** |
||
| 32 | * @var EE_Currency_Config $currency_config |
||
| 33 | */ |
||
| 34 | protected $currency_config; |
||
| 35 | |||
| 36 | /** |
||
| 37 | * This holds the jsdata data object that will be exposed on pages that enqueue the `eejs-core` script. |
||
| 38 | * |
||
| 39 | * @var array |
||
| 40 | */ |
||
| 41 | protected $jsdata = array(); |
||
| 42 | |||
| 43 | |||
| 44 | /** |
||
| 45 | * This keeps track of all scripts with registered data. It is used to prevent duplicate data objects setup in the |
||
| 46 | * page source. |
||
| 47 | * @var array |
||
| 48 | */ |
||
| 49 | protected $script_handles_with_data = array(); |
||
| 50 | |||
| 51 | |||
| 52 | |||
| 53 | /** |
||
| 54 | * Registry constructor. |
||
| 55 | * Hooking into WP actions for script registry. |
||
| 56 | * |
||
| 57 | * @param EE_Template_Config $template_config |
||
| 58 | * @param EE_Currency_Config $currency_config |
||
| 59 | */ |
||
| 60 | public function __construct(EE_Template_Config $template_config, EE_Currency_Config $currency_config) |
||
| 61 | { |
||
| 62 | $this->template_config = $template_config; |
||
| 63 | $this->currency_config = $currency_config; |
||
| 64 | add_action('wp_enqueue_scripts', array($this, 'scripts'), 1); |
||
| 65 | add_action('admin_enqueue_scripts', array($this, 'scripts'), 1); |
||
| 66 | add_action('wp_enqueue_scripts', array($this, 'enqueueData'), 2); |
||
| 67 | add_action('admin_enqueue_scripts', array($this, 'enqueueData'), 2); |
||
| 68 | add_action('wp_print_footer_scripts', array($this, 'enqueueData'), 1); |
||
| 69 | add_action('admin_print_footer_scripts', array($this, 'enqueueData'), 1); |
||
| 70 | } |
||
| 71 | |||
| 72 | |||
| 73 | |||
| 74 | /** |
||
| 75 | * Callback for the WP script actions. |
||
| 76 | * Used to register globally accessible core scripts. |
||
| 77 | * Also used to add the eejs.data object to the source for any js having eejs-core as a dependency. |
||
| 78 | */ |
||
| 79 | public function scripts() |
||
| 110 | |||
| 111 | |||
| 112 | |||
| 113 | /** |
||
| 114 | * Call back for the script print in frontend and backend. |
||
| 115 | * Used to call wp_localize_scripts so that data can be added throughout the runtime until this later hook point. |
||
| 116 | * |
||
| 117 | * @since 4.9.31.rc.015 |
||
| 118 | */ |
||
| 119 | public function enqueueData() |
||
| 120 | { |
||
| 121 | $this->removeAlreadyRegisteredDataForScriptHandles(); |
||
| 122 | wp_localize_script('eejs-core', 'eejs', array('data' => $this->jsdata)); |
||
| 123 | wp_localize_script('espresso_core', 'eei18n', EE_Registry::$i18n_js_strings); |
||
| 124 | $this->localizeAccountingJs(); |
||
| 125 | $this->addRegisteredScriptHandlesWithData('eejs-core'); |
||
| 126 | $this->addRegisteredScriptHandlesWithData('espresso_core'); |
||
| 127 | } |
||
| 128 | |||
| 129 | |||
| 130 | |||
| 131 | /** |
||
| 132 | * Used to add data to eejs.data object. |
||
| 133 | * Note: Overriding existing data is not allowed. |
||
| 134 | * Data will be accessible as a javascript object when you list `eejs-core` as a dependency for your javascript. |
||
| 135 | * If the data you add is something like this: |
||
| 136 | * $this->addData( 'my_plugin_data', array( 'foo' => 'gar' ) ); |
||
| 137 | * It will be exposed in the page source as: |
||
| 138 | * eejs.data.my_plugin_data.foo == gar |
||
| 139 | * |
||
| 140 | * @param string $key Key used to access your data |
||
| 141 | * @param string|array $value Value to attach to key |
||
| 142 | * @throws InvalidArgumentException |
||
| 143 | */ |
||
| 144 | public function addData($key, $value) |
||
| 150 | |||
| 151 | |||
| 152 | |||
| 153 | /** |
||
| 154 | * Similar to addData except this allows for users to push values to an existing key where the values on key are |
||
| 155 | * elements in an array. |
||
| 156 | * When you use this method, the value you include will be appended to the end of an array on $key. |
||
| 157 | * So if the $key was 'test' and you added a value of 'my_data' then it would be represented in the javascript |
||
| 158 | * object like this, eejs.data.test = [ my_data, |
||
| 159 | * ] |
||
| 160 | * If there has already been a scalar value attached to the data object given key, then |
||
| 161 | * this will throw an exception. |
||
| 162 | * |
||
| 163 | * @param string $key Key to attach data to. |
||
| 164 | * @param string|array $value Value being registered. |
||
| 165 | * @throws InvalidArgumentException |
||
| 166 | */ |
||
| 167 | public function pushData($key, $value) |
||
| 186 | |||
| 187 | |||
| 188 | |||
| 189 | /** |
||
| 190 | * Used to set content used by javascript for a template. |
||
| 191 | * Note: Overrides of existing registered templates are not allowed. |
||
| 192 | * |
||
| 193 | * @param string $template_reference |
||
| 194 | * @param string $template_content |
||
| 195 | * @throws InvalidArgumentException |
||
| 196 | */ |
||
| 197 | public function addTemplate($template_reference, $template_content) |
||
| 216 | |||
| 217 | |||
| 218 | |||
| 219 | /** |
||
| 220 | * Retrieve the template content already registered for the given reference. |
||
| 221 | * |
||
| 222 | * @param string $template_reference |
||
| 223 | * @return string |
||
| 224 | */ |
||
| 225 | public function getTemplate($template_reference) |
||
| 231 | |||
| 232 | |||
| 233 | |||
| 234 | /** |
||
| 235 | * Retrieve registered data. |
||
| 236 | * |
||
| 237 | * @param string $key Name of key to attach data to. |
||
| 238 | * @return mixed If there is no for the given key, then false is returned. |
||
| 239 | */ |
||
| 240 | public function getData($key) |
||
| 246 | |||
| 247 | |||
| 248 | |||
| 249 | /** |
||
| 250 | * Verifies whether the given data exists already on the jsdata array. |
||
| 251 | * Overriding data is not allowed. |
||
| 252 | * |
||
| 253 | * @param string $key Index for data. |
||
| 254 | * @return bool If valid then return true. |
||
| 255 | * @throws InvalidArgumentException if data already exists. |
||
| 256 | */ |
||
| 257 | protected function verifyDataNotExisting($key) |
||
| 287 | |||
| 288 | |||
| 289 | |||
| 290 | /** |
||
| 291 | * registers core default stylesheets |
||
| 292 | */ |
||
| 293 | private function loadCoreCss() |
||
| 316 | |||
| 317 | |||
| 318 | |||
| 319 | /** |
||
| 320 | * registers core default javascript |
||
| 321 | */ |
||
| 322 | private function loadCoreJs() |
||
| 333 | |||
| 334 | |||
| 335 | |||
| 336 | /** |
||
| 337 | * registers jQuery Validate for form validation |
||
| 338 | */ |
||
| 339 | private function loadJqueryValidate() |
||
| 357 | |||
| 358 | |||
| 359 | |||
| 360 | /** |
||
| 361 | * registers accounting.js for performing client-side calculations |
||
| 362 | */ |
||
| 363 | private function loadAccountingJs() |
||
| 382 | |||
| 383 | |||
| 384 | |||
| 385 | /** |
||
| 386 | * registers accounting.js for performing client-side calculations |
||
| 387 | */ |
||
| 388 | private function localizeAccountingJs() |
||
| 389 | { |
||
| 390 | wp_localize_script( |
||
| 391 | 'ee-accounting', |
||
| 392 | 'EE_ACCOUNTING_CFG', |
||
| 393 | array( |
||
| 394 | 'currency' => array( |
||
| 395 | 'symbol' => $this->currency_config->sign, |
||
| 396 | 'format' => array( |
||
| 397 | 'pos' => $this->currency_config->sign_b4 ? '%s%v' : '%v%s', |
||
| 398 | 'neg' => $this->currency_config->sign_b4 ? '- %s%v' : '- %v%s', |
||
| 399 | 'zero' => $this->currency_config->sign_b4 ? '%s--' : '--%s', |
||
| 400 | ), |
||
| 401 | 'decimal' => $this->currency_config->dec_mrk, |
||
| 402 | 'thousand' => $this->currency_config->thsnds, |
||
| 403 | 'precision' => $this->currency_config->dec_plc, |
||
| 404 | ), |
||
| 405 | 'number' => array( |
||
| 406 | 'precision' => $this->currency_config->dec_plc, |
||
| 407 | 'thousand' => $this->currency_config->thsnds, |
||
| 408 | 'decimal' => $this->currency_config->dec_mrk, |
||
| 409 | ), |
||
| 410 | ) |
||
| 411 | ); |
||
| 412 | $this->addRegisteredScriptHandlesWithData('ee-accounting'); |
||
| 413 | } |
||
| 414 | |||
| 415 | |||
| 416 | |||
| 417 | /** |
||
| 418 | * registers assets for cleaning your ears |
||
| 419 | */ |
||
| 420 | private function loadQtipJs() |
||
| 428 | |||
| 429 | |||
| 430 | /** |
||
| 431 | * This is used to set registered script handles that have data. |
||
| 432 | * @param string $script_handle |
||
| 433 | */ |
||
| 434 | private function addRegisteredScriptHandlesWithData($script_handle) |
||
| 438 | |||
| 439 | |||
| 440 | /** |
||
| 441 | * Checks WP_Scripts for all of each script handle registered internally as having data and unsets from the |
||
| 442 | * Dependency stored in WP_Scripts if its set. |
||
| 443 | */ |
||
| 444 | private function removeAlreadyRegisteredDataForScriptHandles() |
||
| 453 | |||
| 454 | |||
| 455 | /** |
||
| 456 | * Removes any data dependency registered in WP_Scripts if its set. |
||
| 457 | * @param string $script_handle |
||
| 458 | */ |
||
| 459 | private function removeAlreadyRegisteredDataForScriptHandle($script_handle) |
||
| 469 | |||
| 470 | |||
| 471 | } |
||
| 472 |