Complex classes like Give_CMB2_Settings_Loader 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 Give_CMB2_Settings_Loader, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
19 | Class Give_CMB2_Settings_Loader { |
||
20 | |||
21 | /** |
||
22 | * @since 1.8 |
||
23 | * @var Give_Plugin_Settings $prev_settings Previous setting class object. |
||
24 | */ |
||
25 | private $id; |
||
26 | |||
27 | /** |
||
28 | * @since 1.8 |
||
29 | * @var Give_Plugin_Settings $prev_settings Previous setting class object. |
||
30 | */ |
||
31 | private $prev_settings; |
||
32 | |||
33 | /** |
||
34 | * @since 1.8 |
||
35 | * @var string $current_tab Current setting section. |
||
36 | */ |
||
37 | protected $current_tab; |
||
38 | |||
39 | /** |
||
40 | * @since 1.8 |
||
41 | * @var string $current_tab Current setting section. |
||
42 | */ |
||
43 | private $current_section; |
||
44 | |||
45 | |||
46 | /** |
||
47 | * Give_CMB2_Settings_Loader constructor. |
||
48 | */ |
||
49 | function __construct() { |
||
82 | |||
83 | /** |
||
84 | * Default setting tab. |
||
85 | * |
||
86 | * @since 1.8 |
||
87 | * |
||
88 | * @param $setting_tab |
||
89 | * |
||
90 | * @return string |
||
91 | */ |
||
92 | function set_default_setting_tab( $setting_tab ) { |
||
102 | |||
103 | /** |
||
104 | * Add addon setting pages. |
||
105 | * |
||
106 | * @since 1.8 |
||
107 | * |
||
108 | * @param $pages |
||
109 | * |
||
110 | * @return mixed |
||
111 | */ |
||
112 | function add_addon_settings_page( $pages ) { |
||
139 | |||
140 | |||
141 | /** |
||
142 | * Setup save addon data hook. |
||
143 | * |
||
144 | * @since 1.8 |
||
145 | * |
||
146 | * @param $pages |
||
147 | * |
||
148 | * @return mixed |
||
149 | */ |
||
150 | function setup_addon_save_hook( $pages ) { |
||
177 | |||
178 | /** |
||
179 | * Get section name from section title |
||
180 | * |
||
181 | * @since 1.8 |
||
182 | * |
||
183 | * @param $field_name |
||
184 | * |
||
185 | * @return string |
||
186 | */ |
||
187 | function get_section_name( $field_name ) { |
||
198 | |||
199 | |||
200 | /** |
||
201 | * Get addon sections. |
||
202 | * |
||
203 | * @since 1.8 |
||
204 | * |
||
205 | * @param array $sections Array of setting fields (Optional). |
||
206 | * |
||
207 | * @return mixed |
||
208 | */ |
||
209 | function get_filtered_addon_sections( $sections = array() ) { |
||
246 | |||
247 | |||
248 | /** |
||
249 | * Get setting fields. |
||
250 | * |
||
251 | * @since 1.8 |
||
252 | * |
||
253 | * @param array $settings List of settings. |
||
254 | * @param array $setting_fields Main tab settings data. |
||
255 | * |
||
256 | * @return array |
||
257 | */ |
||
258 | function get_filtered_addon_settings( $settings, $setting_fields = array() ) { |
||
259 | global $wp_filter; |
||
260 | |||
261 | $new_setting_fields = array(); |
||
262 | |||
263 | if ( ! empty( $settings ) ) { |
||
264 | // Bailout: If setting array contain first element of type title then it means it is already created with new setting api (skip this section ). |
||
265 | if ( isset( $settings[0]['type'] ) && 'title' == $settings[0]['type'] ) { |
||
266 | foreach ( $settings as $setting ) { |
||
267 | $new_setting_fields[] = $setting; |
||
268 | |||
269 | // We need setting only till first section end. |
||
270 | if ( 'sectionend' === $setting['type'] ) { |
||
271 | break; |
||
272 | } |
||
273 | } |
||
274 | |||
275 | return $new_setting_fields; |
||
276 | } |
||
277 | |||
278 | // Store title field id. |
||
279 | $prev_title_field_id = ''; |
||
280 | |||
281 | // Create new setting fields. |
||
282 | foreach ( $settings as $index => $field ) { |
||
283 | |||
284 | // Bailout: Must need field type to process. |
||
285 | if ( ! isset( $field['type'] ) ) { |
||
286 | continue; |
||
287 | } |
||
288 | |||
289 | // Set wrapper class if any. |
||
290 | if ( ! empty( $field['row_classes'] ) ) { |
||
291 | $field['wrapper_class'] = $field['row_classes']; |
||
292 | unset( $field['row_classes'] ); |
||
293 | } |
||
294 | |||
295 | $field['name'] = ! isset( $field['name'] ) ? '' : $field['name']; |
||
296 | $field['desc'] = ! isset( $field['desc'] ) ? '' : $field['desc']; |
||
297 | |||
298 | // Modify cmb2 setting fields. |
||
299 | switch ( $field['type'] ) { |
||
300 | case 'text' : |
||
301 | case 'file' : |
||
302 | $field['css'] = 'width:25em;'; |
||
303 | break; |
||
304 | |||
305 | case 'text_small' : |
||
306 | $field['type'] = 'text'; |
||
307 | break; |
||
308 | |||
309 | case 'text_email' : |
||
310 | $field['type'] = 'email'; |
||
311 | $field['css'] = 'width:25em;'; |
||
312 | break; |
||
313 | |||
314 | case 'radio_inline' : |
||
315 | $field['type'] = 'radio'; |
||
316 | $field['class'] = 'give-radio-inline'; |
||
317 | break; |
||
318 | |||
319 | case 'give_title' : |
||
320 | $field['type'] = 'title'; |
||
321 | break; |
||
322 | } |
||
323 | |||
324 | if ( 'title' === $field['type'] ) { |
||
325 | |||
326 | // If we do not have first element as title then these field will be skip from frontend |
||
327 | // because there are not belong to any section, so put all abandon fields under first section. |
||
328 | if ( $index && empty( $prev_title_field_id ) ) { |
||
329 | array_unshift( |
||
330 | $new_setting_fields, |
||
331 | array( |
||
332 | 'title' => $field['name'], |
||
333 | 'type' => $field['type'], |
||
334 | 'desc' => $field['desc'], |
||
335 | 'id' => $field['id'] |
||
336 | ) |
||
337 | ); |
||
338 | |||
339 | $prev_title_field_id = $field['id']; |
||
340 | |||
341 | continue; |
||
342 | } elseif ( $index ) { |
||
343 | // Section end. |
||
344 | $new_setting_fields[] = array( |
||
345 | 'type' => 'sectionend', |
||
346 | 'id' => $prev_title_field_id |
||
347 | ); |
||
348 | } |
||
349 | |||
350 | // Section start. |
||
351 | $new_setting_fields[] = array( |
||
352 | 'title' => $field['name'], |
||
353 | 'type' => $field['type'], |
||
354 | 'desc' => $field['desc'], |
||
355 | 'id' => $field['id'] |
||
356 | ); |
||
357 | |||
358 | $prev_title_field_id = $field['id']; |
||
359 | } else { |
||
360 | |||
361 | // setting fields |
||
362 | $new_setting_fields[] = $field; |
||
363 | } |
||
364 | } |
||
365 | |||
366 | // Section end. |
||
367 | $new_setting_fields[] = array( |
||
368 | 'type' => 'sectionend', |
||
369 | 'id' => $prev_title_field_id |
||
370 | ); |
||
371 | |||
372 | // Check if setting page has title section or not. |
||
373 | // If setting page does not have title section then add title section to it and fix section end array id. |
||
374 | if ( 'title' !== $new_setting_fields[0]['type'] ) { |
||
375 | array_unshift( |
||
376 | $new_setting_fields, |
||
377 | array( |
||
378 | 'title' => ( isset( $settings['give_title'] ) ? $settings['give_title'] : '' ), |
||
379 | 'type' => 'title', |
||
380 | 'desc' => ! empty( $setting_fields['desc'] ) ? $setting_fields['desc'] : '', |
||
381 | 'id' => ( isset( $settings['id'] ) ? $settings['id'] : '' ) |
||
382 | ) |
||
383 | ); |
||
384 | |||
385 | // Update id in section end array if does not contain. |
||
386 | if ( empty( $new_setting_fields[ count( $new_setting_fields ) - 1 ]['id'] ) ) { |
||
387 | $new_setting_fields[ count( $new_setting_fields ) - 1 ]['id'] = ( isset( $settings['id'] ) ? $settings['id'] : '' ); |
||
388 | } |
||
389 | } |
||
390 | |||
391 | // Return only section related settings. |
||
392 | if ( $sections = $this->get_filtered_addon_sections() ) { |
||
393 | $new_setting_fields = $this->get_section_settings( $new_setting_fields ); |
||
394 | } |
||
395 | |||
396 | // Third party plugin backward compatibility. |
||
397 | $wp_filter_keys = array_keys( $wp_filter ); |
||
398 | foreach ( $new_setting_fields as $index => $field ) { |
||
399 | |||
400 | if ( in_array( $field['type'], array( 'title', 'sectionend' ) ) ) { |
||
401 | continue; |
||
402 | } |
||
403 | |||
404 | $cmb2_filter_name = "cmb2_render_{$field['type']}"; |
||
405 | |||
406 | if ( in_array( $cmb2_filter_name, $wp_filter_keys ) ) { |
||
407 | |||
408 | if( 0 >= version_compare( 4.7, get_bloginfo('version') ) && ! empty( $wp_filter[$cmb2_filter_name]->callbacks ) ) { |
||
409 | $cmb2_filter_arr = current( $wp_filter[$cmb2_filter_name]->callbacks ); |
||
410 | } else { |
||
411 | $cmb2_filter_arr = current( $wp_filter[ $cmb2_filter_name ] ); |
||
412 | } |
||
413 | |||
414 | if ( ! empty( $cmb2_filter_arr ) ) { |
||
415 | // Note: function can be called either globally or with class object, it depends on how developer invoke it. |
||
416 | $new_setting_fields[ $index ]['func'] = current( $cmb2_filter_arr ); |
||
417 | add_action( "give_admin_field_{$field['type']}", array( |
||
418 | $this, |
||
419 | 'addon_setting_field' |
||
420 | ), 10, 2 ); |
||
421 | } |
||
422 | } |
||
423 | } |
||
424 | |||
425 | return $new_setting_fields; |
||
426 | } |
||
427 | |||
428 | return $settings; |
||
429 | } |
||
430 | |||
431 | |||
432 | /** |
||
433 | * Get section related setting. |
||
434 | * |
||
435 | * @since 1.8 |
||
436 | * |
||
437 | * @param $tab_settings |
||
438 | * |
||
439 | * @return array |
||
440 | */ |
||
441 | function get_section_settings( $tab_settings ) { |
||
442 | $current_section = give_get_current_setting_section(); |
||
443 | |||
444 | // Note: If we are opening default tabe for addon setting then it is possible that we will get empty string as current section |
||
445 | // because default section filter added after save hook fire, so we will always get problem to save first section [default] or if there are only on section |
||
446 | // This is hack to fix this. |
||
447 | if ( empty( $current_section ) ) { |
||
448 | $current_section = $this->set_default_setting_tab( $current_section ); |
||
449 | } |
||
450 | |||
451 | $section_start = false; |
||
452 | $section_end = false; |
||
453 | $section_only_setting_fields = array(); |
||
454 | |||
455 | foreach ( $tab_settings as $field ) { |
||
456 | if ( 'title' == $field['type'] && $current_section == sanitize_title( $field['title'] ) ) { |
||
457 | $section_start = true; |
||
458 | } |
||
459 | |||
460 | if ( ! $section_start || $section_end ) { |
||
461 | continue; |
||
462 | } |
||
463 | |||
464 | if ( $section_start && ! $section_end ) { |
||
465 | if ( 'sectionend' == $field['type'] ) { |
||
466 | $section_end = true; |
||
467 | } |
||
468 | $section_only_setting_fields[] = $field; |
||
469 | } |
||
470 | } |
||
471 | |||
472 | // Remove title from setting, pevent it from render in setting tab. |
||
473 | $section_only_setting_fields[0]['title'] = ''; |
||
474 | |||
475 | return apply_filters( "give_get_settings_{$this->current_tab}_{$current_section}", $section_only_setting_fields, $tab_settings ); |
||
476 | } |
||
477 | |||
478 | |||
479 | /** |
||
480 | * CMB2 addon setting fields backward compatibility. |
||
481 | * |
||
482 | * @since 1.8 |
||
483 | * |
||
484 | * @param array $field |
||
485 | * @param mixed $saved_value |
||
486 | * |
||
487 | * @return void |
||
488 | */ |
||
489 | function addon_setting_field( $field, $saved_value ) { |
||
490 | // Create object for cmb2 function callback backward compatibility. |
||
491 | // Note: Do not call any cmb2 function on these objects |
||
492 | $field_obj = (object) array( 'args' => $field ); |
||
493 | $field_type_obj = (object) array( 'field' => $field_obj ); |
||
494 | |||
495 | switch ( $this->current_tab ) : |
||
496 | case 'licenses': |
||
497 | ?> |
||
498 | <div class="give-settings-wrap give-settings-wrap-<?php echo $this->current_tab; ?>"> |
||
499 | <?php $field['func']['function']( $field_obj, $saved_value, '', '', $field_type_obj ); ?> |
||
500 | </div> |
||
501 | <?php break; |
||
502 | |||
503 | default : |
||
504 | $colspan = "colspan=\"2\""; |
||
505 | ?> |
||
506 | <tr valign="top"> |
||
507 | <?php if ( ! empty( $field['name'] ) && ! in_array( $field['name'], array( ' ' ) ) ) : ?> |
||
508 | <th scope="row" class="titledesc"> |
||
509 | <label |
||
510 | for="<?php echo esc_attr( $field['name'] ); ?>"><?php echo $field['title']; ?></label> |
||
511 | </th> |
||
512 | <?php $colspan = ''; ?> |
||
513 | <?php endif; ?> |
||
514 | <td class="give-forminp" <?php echo $colspan; ?>> |
||
515 | <?php |
||
516 | if ( is_array( $field['func']['function'] ) ) { |
||
517 | $field['func']['function'][0]->$field['func']['function'][1]( $field_obj, $saved_value, '', '', $field_type_obj ); |
||
518 | } else { |
||
519 | $field['func']['function']( $field_obj, $saved_value, '', '', $field_type_obj ); |
||
520 | } |
||
521 | ?> |
||
522 | </td> |
||
523 | </tr> |
||
524 | <?php |
||
525 | endswitch; |
||
526 | } |
||
527 | |||
528 | /** |
||
529 | * Get sections. |
||
530 | * |
||
531 | * @since 1.8 |
||
532 | * @return array |
||
533 | */ |
||
534 | public function get_sections() { |
||
547 | |||
548 | |||
549 | /** |
||
550 | * Get setting fields. |
||
551 | * |
||
552 | * @since 1.8 |
||
553 | * @return array |
||
554 | */ |
||
555 | function get_settings() { |
||
575 | |||
576 | /** |
||
577 | * Output sections. |
||
578 | * |
||
579 | * @since 1.8 |
||
580 | * @return void |
||
581 | */ |
||
582 | public function output_sections() { |
||
599 | |||
600 | /** |
||
601 | * Output the settings. |
||
602 | * |
||
603 | * @since 1.8 |
||
604 | * @return void |
||
605 | */ |
||
606 | public function output() { |
||
611 | |||
612 | /** |
||
613 | * Save settings. |
||
614 | * |
||
615 | * @since 1.8 |
||
616 | * @return void |
||
617 | */ |
||
618 | public function save() { |
||
623 | } |
||
624 | endif; |
||
625 | |||
626 | new Give_CMB2_Settings_Loader(); |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.