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 Container 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 Container, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
18 | abstract class Container implements Datastore_Holder_Interface { |
||
19 | /** |
||
20 | * Where to put a particular tab -- at the head or the tail. Tail by default |
||
21 | */ |
||
22 | const TABS_TAIL = 1; |
||
23 | const TABS_HEAD = 2; |
||
24 | |||
25 | /** |
||
26 | * Separator signifying field hierarchy relation |
||
27 | * Used when searching for fields in a specific complex field |
||
28 | */ |
||
29 | const HIERARCHY_FIELD_SEPARATOR = '/'; |
||
30 | |||
31 | /** |
||
32 | * Separator signifying complex_field->group relation |
||
33 | * Used when searching for fields in a specific complex field group |
||
34 | */ |
||
35 | const HIERARCHY_GROUP_SEPARATOR = ':'; |
||
36 | |||
37 | /** |
||
38 | * Stores if the container is active on the current page |
||
39 | * |
||
40 | * @see activate() |
||
41 | * @var bool |
||
42 | */ |
||
43 | protected $active = false; |
||
44 | |||
45 | /** |
||
46 | * List of registered unique field names for this container instance |
||
47 | * |
||
48 | * @see register_field_name() |
||
49 | * @var array |
||
50 | */ |
||
51 | protected $registered_field_names = array(); |
||
52 | |||
53 | /** |
||
54 | * Tabs available |
||
55 | */ |
||
56 | protected $tabs = array(); |
||
57 | |||
58 | /** |
||
59 | * List of default container settings |
||
60 | * |
||
61 | * @see init() |
||
62 | * @var array |
||
63 | */ |
||
64 | public $settings = array(); |
||
65 | |||
66 | /** |
||
67 | * Unique ID of the container |
||
68 | * |
||
69 | * @var string |
||
70 | */ |
||
71 | public $id; |
||
72 | |||
73 | /** |
||
74 | * Title of the container |
||
75 | * |
||
76 | * @var string |
||
77 | */ |
||
78 | public $title = ''; |
||
79 | |||
80 | /** |
||
81 | * Type of the container |
||
82 | * |
||
83 | * @var string |
||
84 | */ |
||
85 | public $type; |
||
86 | |||
87 | /** |
||
88 | * List of notification messages to be displayed on the front-end |
||
89 | * |
||
90 | * @var array |
||
91 | */ |
||
92 | protected $notifications = array(); |
||
93 | |||
94 | /** |
||
95 | * List of error messages to be displayed on the front-end |
||
96 | * |
||
97 | * @var array |
||
98 | */ |
||
99 | protected $errors = array(); |
||
100 | |||
101 | /** |
||
102 | * List of container fields |
||
103 | * |
||
104 | * @see add_fields() |
||
105 | * @var array |
||
106 | */ |
||
107 | protected $fields = array(); |
||
108 | |||
109 | /** |
||
110 | * Array of custom CSS classes. |
||
111 | * |
||
112 | * @see set_classes() |
||
113 | * @see get_classes() |
||
114 | * @var array<string> |
||
115 | */ |
||
116 | protected $classes = array(); |
||
117 | |||
118 | /** |
||
119 | * Container datastores. Propagated to all container fields |
||
120 | * |
||
121 | * @see set_datastore() |
||
122 | * @see get_datastore() |
||
123 | * @var Datastore_Interface |
||
124 | */ |
||
125 | protected $datastore; |
||
126 | |||
127 | /** |
||
128 | * Flag whether the datastore is the default one or replaced with a custom one |
||
129 | * |
||
130 | * @see set_datastore() |
||
131 | * @see get_datastore() |
||
132 | * @var boolean |
||
133 | */ |
||
134 | protected $has_default_datastore = true; |
||
135 | |||
136 | /** |
||
137 | * Fulfillable_Collection to use when checking attachment/saving conditions |
||
138 | * |
||
139 | * @var Fulfillable_Collection |
||
140 | */ |
||
141 | protected $condition_collection; |
||
142 | |||
143 | /** |
||
144 | * Translator to use when translating conditions to json |
||
145 | * |
||
146 | * @var \Carbon_Fields\Container\Fulfillable\Translator\Translator |
||
147 | */ |
||
148 | protected $condition_translator; |
||
149 | |||
150 | /** |
||
151 | * Create a new container of type $type and name $name. |
||
152 | * |
||
153 | * @param string $raw_type |
||
154 | * @param string $id Unique id for the container. Optional |
||
155 | * @param string $name Human-readable name of the container |
||
156 | * @return Container $container |
||
157 | */ |
||
158 | 8 | public static function factory( $raw_type, $id, $name = '' ) { |
|
159 | // no name provided - switch input around as the id is optionally generated based on the name |
||
160 | 8 | if ( $name === '' ) { |
|
161 | 8 | $name = $id; |
|
162 | 8 | $id = ''; |
|
163 | 8 | } |
|
164 | |||
165 | 8 | $type = Helper::normalize_type( $raw_type ); |
|
166 | 8 | $repository = Carbon_Fields::resolve( 'container_repository' ); |
|
167 | 8 | $id = $repository->get_unique_container_id( ( $id !== '' ) ? $id : $name ); |
|
168 | |||
169 | 8 | if ( ! Helper::is_valid_entity_id( $id ) ) { |
|
170 | Incorrect_Syntax_Exception::raise( 'Container IDs can only contain lowercase alphanumeric characters, dashes and underscores ("' . $id . '" passed).' ); |
||
171 | return null; |
||
172 | } |
||
173 | |||
174 | 8 | if ( ! $repository->is_unique_container_id( $id ) ) { |
|
175 | Incorrect_Syntax_Exception::raise( 'The passed container id is already taken ("' . $id . '" passed).' ); |
||
176 | return null; |
||
177 | } |
||
178 | |||
179 | 8 | $container = null; |
|
180 | 8 | if ( Carbon_Fields::has( $type, 'containers' ) ) { |
|
181 | $container = Carbon_Fields::resolve_with_arguments( $type, array( |
||
182 | 'id' => $id, |
||
183 | 'name' => $name, |
||
184 | 'type' => $type, |
||
185 | ), 'containers' ); |
||
186 | } else { |
||
187 | // Fallback to class name-based resolution |
||
188 | 8 | $class = Helper::type_to_class( $type, __NAMESPACE__, '_Container' ); |
|
189 | |||
190 | 8 | View Code Duplication | if ( ! class_exists( $class ) ) { |
191 | 3 | Incorrect_Syntax_Exception::raise( 'Unknown container "' . $raw_type . '".' ); |
|
192 | 1 | $class = __NAMESPACE__ . '\\Broken_Container'; |
|
193 | 1 | } |
|
194 | |||
195 | 6 | $fulfillable_collection = Carbon_Fields::resolve( 'container_condition_fulfillable_collection' ); |
|
196 | 6 | $condition_translator = Carbon_Fields::resolve( 'container_condition_translator_json' ); |
|
197 | 6 | $container = new $class( $id, $name, $type, $fulfillable_collection, $condition_translator ); |
|
198 | } |
||
199 | |||
200 | 6 | $repository->register_container( $container ); |
|
201 | |||
202 | 6 | return $container; |
|
203 | } |
||
204 | |||
205 | /** |
||
206 | * An alias of factory(). |
||
207 | * |
||
208 | * @see Container::factory() |
||
209 | * @return Container |
||
210 | */ |
||
211 | public static function make() { |
||
214 | |||
215 | /** |
||
216 | * Create a new container |
||
217 | * |
||
218 | * @param string $id Unique id of the container |
||
219 | * @param string $title Title of the container |
||
220 | * @param string $type Type of the container |
||
221 | * @param Fulfillable_Collection $condition_collection |
||
222 | * @param \Carbon_Fields\Container\Fulfillable\Translator\Translator $condition_translator |
||
223 | */ |
||
224 | 2 | public function __construct( $id, $title, $type, $condition_collection, $condition_translator ) { |
|
225 | 2 | Carbon_Fields::verify_boot(); |
|
226 | |||
227 | 2 | if ( empty( $title ) ) { |
|
228 | 1 | Incorrect_Syntax_Exception::raise( 'Empty container title is not supported' ); |
|
229 | } |
||
230 | |||
231 | 1 | $this->id = $id; |
|
232 | 1 | $this->title = $title; |
|
233 | 1 | $this->type = $type; |
|
234 | 1 | $this->condition_collection = $condition_collection; |
|
235 | 1 | $this->condition_collection->set_condition_type_list( |
|
236 | 1 | array_merge( $this->get_condition_types( true ), $this->get_condition_types( false ) ), |
|
237 | true |
||
238 | 1 | ); |
|
239 | 1 | $this->condition_translator = $condition_translator; |
|
240 | 1 | } |
|
241 | |||
242 | /** |
||
243 | * Return the container id |
||
244 | * |
||
245 | * @return string |
||
246 | */ |
||
247 | public function get_id() { |
||
250 | |||
251 | /** |
||
252 | * Get array of all static condition types |
||
253 | * |
||
254 | * @param boolean $static |
||
255 | * @return array<string> |
||
256 | */ |
||
257 | protected function get_condition_types( $static ) { |
||
267 | |||
268 | /** |
||
269 | * Return whether the container is active |
||
270 | */ |
||
271 | public function is_active() { |
||
274 | |||
275 | /** |
||
276 | * Activate the container and trigger an action |
||
277 | */ |
||
278 | protected function activate() { |
||
279 | $this->active = true; |
||
280 | $this->boot(); |
||
281 | do_action( 'carbon_fields_container_activated', $this ); |
||
282 | |||
283 | $fields = $this->get_fields(); |
||
284 | foreach ( $fields as $field ) { |
||
285 | $field->activate(); |
||
286 | } |
||
287 | } |
||
288 | |||
289 | /** |
||
290 | * Perform instance initialization |
||
291 | */ |
||
292 | abstract public function init(); |
||
293 | |||
294 | /** |
||
295 | * Boot the container once it's attached. |
||
296 | */ |
||
297 | protected function boot() { |
||
300 | |||
301 | /** |
||
302 | * Load the value for each field in the container. |
||
303 | * Could be used internally during container rendering |
||
304 | */ |
||
305 | public function load() { |
||
306 | foreach ( $this->fields as $field ) { |
||
307 | $field->load(); |
||
308 | } |
||
309 | } |
||
310 | |||
311 | /** |
||
312 | * Called first as part of the container save procedure. |
||
313 | * Responsible for checking the request validity and |
||
314 | * calling the container-specific save() method |
||
315 | * |
||
316 | * @see save() |
||
317 | * @see is_valid_save() |
||
318 | */ |
||
319 | public function _save() { |
||
320 | $param = func_get_args(); |
||
321 | if ( call_user_func_array( array( $this, '_is_valid_save' ), $param ) ) { |
||
322 | call_user_func_array( array( $this, 'save' ), $param ); |
||
323 | } |
||
324 | } |
||
325 | |||
326 | /** |
||
327 | * Load submitted data and save each field in the container |
||
328 | * |
||
329 | * @see is_valid_save() |
||
330 | */ |
||
331 | public function save( $data = null ) { |
||
332 | foreach ( $this->fields as $field ) { |
||
333 | $field->set_value_from_input( Helper::input() ); |
||
334 | $field->save(); |
||
335 | } |
||
336 | } |
||
337 | |||
338 | /** |
||
339 | * Checks whether the current save request is valid |
||
340 | * |
||
341 | * @return bool |
||
342 | */ |
||
343 | final protected function _is_valid_save() { |
||
348 | |||
349 | /** |
||
350 | * Checks whether the current save request is valid |
||
351 | * |
||
352 | * @return bool |
||
353 | */ |
||
354 | abstract protected function is_valid_save(); |
||
355 | |||
356 | /** |
||
357 | * Called first as part of the container attachment procedure. |
||
358 | * Responsible for checking it's OK to attach the container |
||
359 | * and if it is, calling the container-specific attach() method |
||
360 | * |
||
361 | * @see attach() |
||
362 | * @see is_valid_attach() |
||
363 | */ |
||
364 | public function _attach() { |
||
365 | if ( ! $this->is_valid_attach() ) { |
||
366 | return; |
||
367 | } |
||
368 | |||
369 | $param = func_get_args(); |
||
370 | call_user_func_array( array( $this, 'attach' ), $param ); |
||
371 | |||
372 | // Allow containers to initialize but not activate (useful in cases such as theme options) |
||
373 | if ( $this->should_activate() ) { |
||
374 | $this->activate(); |
||
375 | } |
||
376 | } |
||
377 | |||
378 | /** |
||
379 | * Attach the container rendering and helping methods |
||
380 | * to concrete WordPress Action hooks |
||
381 | */ |
||
382 | public function attach() {} |
||
383 | |||
384 | /** |
||
385 | * Perform checks whether the container should be attached during the current request |
||
386 | * |
||
387 | * @return bool True if the container is allowed to be attached |
||
388 | */ |
||
389 | final public function is_valid_attach() { |
||
393 | |||
394 | /** |
||
395 | * Get environment array for page request (in admin) |
||
396 | * |
||
397 | * @return array |
||
398 | */ |
||
399 | abstract protected function get_environment_for_request(); |
||
400 | |||
401 | /** |
||
402 | * Check container attachment rules against current page request (in admin) |
||
403 | * |
||
404 | * @return bool |
||
405 | */ |
||
406 | abstract protected function is_valid_attach_for_request(); |
||
407 | |||
408 | /** |
||
409 | * Check if conditions pass for request |
||
410 | * |
||
411 | * @return bool |
||
412 | */ |
||
413 | protected function static_conditions_pass() { |
||
421 | |||
422 | /** |
||
423 | * Get environment array for object id |
||
424 | * |
||
425 | * @param integer $object_id |
||
426 | * @return array |
||
427 | */ |
||
428 | abstract protected function get_environment_for_object( $object_id ); |
||
429 | |||
430 | /** |
||
431 | * Check container attachment rules against object id |
||
432 | * |
||
433 | * @param int $object_id |
||
434 | * @return bool |
||
435 | */ |
||
436 | abstract public function is_valid_attach_for_object( $object_id ); |
||
437 | |||
438 | /** |
||
439 | * Check if all conditions pass for object |
||
440 | * |
||
441 | * @param integer $object_id |
||
442 | * @return bool |
||
443 | */ |
||
444 | protected function all_conditions_pass( $object_id ) { |
||
448 | |||
449 | /** |
||
450 | * Whether this container is currently viewed. |
||
451 | */ |
||
452 | public function should_activate() { |
||
455 | |||
456 | /** |
||
457 | * Perform a check whether the current container has fields |
||
458 | * |
||
459 | * @return bool |
||
460 | */ |
||
461 | public function has_fields() { |
||
464 | |||
465 | /** |
||
466 | * Returns the private container array of fields. |
||
467 | * Use only if you are completely aware of what you are doing. |
||
468 | * |
||
469 | * @return Field[] |
||
470 | */ |
||
471 | public function get_fields() { |
||
474 | |||
475 | /** |
||
476 | * Return root field from container with specified name |
||
477 | * |
||
478 | * @example crb_complex |
||
479 | * |
||
480 | * @param string $field_name |
||
481 | * @return Field |
||
482 | */ |
||
483 | public function get_root_field_by_name( $field_name ) { |
||
484 | $fields = $this->get_fields(); |
||
485 | foreach ( $fields as $field ) { |
||
486 | if ( $field->get_base_name() === $field_name ) { |
||
487 | return $field; |
||
488 | } |
||
489 | } |
||
490 | return null; |
||
491 | } |
||
492 | |||
493 | /** |
||
494 | * Get a regex to match field name patterns used to fetch specific fields |
||
495 | * |
||
496 | * @return string |
||
497 | */ |
||
498 | protected function get_field_pattern_regex() { |
||
499 | $field_name_characters = Helper::get_field_name_characters_pattern(); |
||
500 | |||
501 | // matches: |
||
502 | // field_name |
||
503 | // field_name[0] |
||
504 | // field_name[0]:group_name |
||
505 | // field_name:group_name |
||
506 | $regex = '/ |
||
507 | \A |
||
508 | (?P<field_name>[' . $field_name_characters . ']+) |
||
509 | (?:\[(?P<group_index>\d+)\])? |
||
510 | (?:' . preg_quote( static::HIERARCHY_GROUP_SEPARATOR, '/' ). '(?P<group_name>[' . $field_name_characters . ']+))? |
||
511 | \z |
||
512 | /x'; |
||
513 | return $regex; |
||
514 | } |
||
515 | |||
516 | /** |
||
517 | * Return field from container with specified name |
||
518 | * |
||
519 | * @example $field_name = 'crb_complex/text_field' |
||
520 | * @example $field_name = 'crb_complex/complex_2' |
||
521 | * @example $field_name = 'crb_complex/complex_2:text_group/text_field' |
||
522 | * @example $field_name = 'crb_complex[3]/complex_2[1]:text_group/text_field' |
||
523 | * |
||
524 | * @param string $field_name |
||
525 | * @return Field |
||
526 | */ |
||
527 | public function get_field_by_name( $field_name ) { |
||
528 | $hierarchy = array_filter( explode( static::HIERARCHY_FIELD_SEPARATOR, $field_name ) ); |
||
529 | $field = null; |
||
530 | |||
531 | $field_group = $this->get_fields(); |
||
532 | $hierarchy_left = $hierarchy; |
||
533 | $field_pattern_regex = $this->get_field_pattern_regex(); |
||
534 | $hierarchy_index = array(); |
||
535 | |||
536 | while ( ! empty( $hierarchy_left ) ) { |
||
537 | $segment = array_shift( $hierarchy_left ); |
||
538 | $segment_pieces = array(); |
||
539 | if ( ! preg_match( $field_pattern_regex, $segment, $segment_pieces ) ) { |
||
540 | return null; |
||
541 | } |
||
542 | |||
543 | $segment_field_name = $segment_pieces['field_name']; |
||
544 | $segment_group_index = isset( $segment_pieces['group_index'] ) ? $segment_pieces['group_index'] : 0; |
||
545 | $segment_group_name = isset( $segment_pieces['group_name'] ) ? $segment_pieces['group_name'] : Group_Field::DEFAULT_GROUP_NAME; |
||
546 | |||
547 | foreach ( $field_group as $f ) { |
||
548 | if ( $f->get_base_name() !== $segment_field_name ) { |
||
549 | continue; |
||
550 | } |
||
551 | |||
552 | if ( empty( $hierarchy_left ) ) { |
||
553 | $field = clone $f; |
||
554 | $field->set_hierarchy_index( $hierarchy_index ); |
||
555 | } else { |
||
556 | if ( ! ( $f instanceof \Carbon_Fields\Field\Complex_Field ) ) { |
||
557 | return null; |
||
558 | } |
||
559 | |||
560 | $group = $f->get_group_by_name( $segment_group_name ); |
||
561 | if ( ! $group ) { |
||
562 | return null; |
||
563 | } |
||
564 | $field_group = $group->get_fields(); |
||
565 | $hierarchy_index[] = $segment_group_index; |
||
566 | } |
||
567 | break; |
||
568 | } |
||
569 | } |
||
570 | |||
571 | return $field; |
||
572 | } |
||
573 | |||
574 | /** |
||
575 | * Perform checks whether there is a field registered with the name $name. |
||
576 | * If not, the field name is recorded. |
||
577 | * |
||
578 | * @param string $name |
||
579 | * @return boolean |
||
580 | */ |
||
581 | View Code Duplication | protected function register_field_name( $name ) { |
|
590 | |||
591 | /** |
||
592 | * Return whether the datastore instance is the default one or has been overriden |
||
593 | * |
||
594 | * @return boolean |
||
595 | */ |
||
596 | 6 | public function has_default_datastore() { |
|
599 | |||
600 | /** |
||
601 | * Set datastore instance |
||
602 | * |
||
603 | * @param Datastore_Interface $datastore |
||
604 | * @param bool $set_as_default (optional) |
||
605 | * @return Container $this |
||
606 | */ |
||
607 | 6 | View Code Duplication | public function set_datastore( Datastore_Interface $datastore, $set_as_default = false ) { |
608 | 6 | if ( $set_as_default && ! $this->has_default_datastore() ) { |
|
609 | 1 | return $this; // datastore has been overriden with a custom one - abort changing to a default one |
|
610 | } |
||
611 | 6 | $this->datastore = $datastore; |
|
612 | 6 | $this->has_default_datastore = $set_as_default; |
|
613 | |||
614 | 6 | foreach ( $this->fields as $field ) { |
|
615 | $field->set_datastore( $this->get_datastore(), true ); |
||
616 | 6 | } |
|
617 | 6 | return $this; |
|
618 | } |
||
619 | |||
620 | /** |
||
621 | * Get the DataStore instance |
||
622 | * |
||
623 | * @return Datastore_Interface $datastore |
||
624 | */ |
||
625 | 6 | public function get_datastore() { |
|
628 | |||
629 | /** |
||
630 | * Return WordPress nonce name used to identify the current container instance |
||
631 | * |
||
632 | * @return string |
||
633 | */ |
||
634 | protected function get_nonce_name() { |
||
637 | |||
638 | /** |
||
639 | * Return WordPress nonce name used to identify the current container instance |
||
640 | * |
||
641 | * @return string |
||
642 | */ |
||
643 | protected function get_nonce_value() { |
||
646 | |||
647 | /** |
||
648 | * Check if the nonce is present in the request and that it is verified |
||
649 | * |
||
650 | * @return bool |
||
651 | */ |
||
652 | protected function verified_nonce_in_request() { |
||
658 | |||
659 | /** |
||
660 | * Internal function that creates the tab and associates it with particular field set |
||
661 | * |
||
662 | * @param string $tab_name |
||
663 | * @param array $fields |
||
664 | * @param int $queue_end |
||
665 | * @return object $this |
||
666 | */ |
||
667 | private function create_tab( $tab_name, $fields, $queue_end = self::TABS_TAIL ) { |
||
668 | if ( isset( $this->tabs[ $tab_name ] ) ) { |
||
669 | Incorrect_Syntax_Exception::raise( "Tab name duplication for $tab_name" ); |
||
670 | } |
||
671 | |||
672 | if ( $queue_end === static::TABS_TAIL ) { |
||
673 | $this->tabs[ $tab_name ] = array(); |
||
674 | } else if ( $queue_end === static::TABS_HEAD ) { |
||
675 | $this->tabs = array_merge( |
||
676 | array( $tab_name => array() ), |
||
677 | $this->tabs |
||
678 | ); |
||
679 | } |
||
680 | |||
681 | foreach ( $fields as $field ) { |
||
682 | $field_name = $field->get_name(); |
||
683 | $this->tabs[ $tab_name ][ $field_name ] = $field; |
||
684 | } |
||
685 | |||
686 | $this->settings['tabs'] = $this->get_tabs_json(); |
||
687 | } |
||
688 | |||
689 | /** |
||
690 | * Whether the container is tabbed or not |
||
691 | * |
||
692 | * @return bool |
||
693 | */ |
||
694 | public function is_tabbed() { |
||
697 | |||
698 | /** |
||
699 | * Retrieve all fields that are not defined under a specific tab |
||
700 | * |
||
701 | * @return array |
||
702 | */ |
||
703 | protected function get_untabbed_fields() { |
||
704 | $tabbed_fields_names = array(); |
||
705 | foreach ( $this->tabs as $tab_fields ) { |
||
706 | $tabbed_fields_names = array_merge( $tabbed_fields_names, array_keys( $tab_fields ) ); |
||
707 | } |
||
708 | |||
709 | $untabbed_fields = array_filter( $this->fields, function( $field ) use ( $tabbed_fields_names ) { |
||
710 | return ! in_array( $field->get_name(), $tabbed_fields_names ); |
||
711 | } ); |
||
712 | |||
713 | return $untabbed_fields; |
||
714 | } |
||
715 | |||
716 | /** |
||
717 | * Retrieve all tabs. |
||
718 | * Create a default tab if there are any untabbed fields. |
||
719 | * |
||
720 | * @return array |
||
721 | */ |
||
722 | protected function get_tabs() { |
||
723 | $untabbed_fields = $this->get_untabbed_fields(); |
||
724 | |||
725 | if ( ! empty( $untabbed_fields ) ) { |
||
726 | $this->create_tab( |
||
727 | apply_filters( 'carbon_fields_untabbed_fields_tab_title', __( 'General', 'carbon-fields' ), $this ), |
||
728 | $untabbed_fields, |
||
729 | static::TABS_HEAD |
||
730 | ); |
||
731 | } |
||
732 | |||
733 | return $this->tabs; |
||
734 | } |
||
735 | |||
736 | /** |
||
737 | * Build the tabs JSON |
||
738 | * |
||
739 | * @return array |
||
740 | */ |
||
741 | protected function get_tabs_json() { |
||
742 | $tabs_json = array(); |
||
743 | $tabs = $this->get_tabs(); |
||
744 | |||
745 | foreach ( $tabs as $tab_name => $fields ) { |
||
746 | foreach ( $fields as $field_name => $field ) { |
||
747 | $tabs_json[ $tab_name ][] = $field_name; |
||
748 | } |
||
749 | } |
||
750 | |||
751 | return $tabs_json; |
||
752 | } |
||
753 | |||
754 | /** |
||
755 | * Get custom CSS classes. |
||
756 | * |
||
757 | * @return array<string> |
||
758 | */ |
||
759 | public function get_classes() { |
||
762 | |||
763 | /** |
||
764 | * Set CSS classes that the container should use. |
||
765 | * |
||
766 | * @param string|array<string> $classes |
||
767 | * @return Container $this |
||
768 | */ |
||
769 | public function set_classes( $classes ) { |
||
773 | |||
774 | /** |
||
775 | * Returns an array that holds the container data, suitable for JSON representation. |
||
776 | * |
||
777 | * @param bool $load Should the value be loaded from the database or use the value from the current instance. |
||
778 | * @return array |
||
779 | */ |
||
780 | public function to_json( $load ) { |
||
781 | $conditions = $this->condition_collection->evaluate( $this->get_condition_types( true ), $this->get_environment_for_request(), array( 'CUSTOM' ) ); |
||
782 | $conditions = $this->condition_translator->fulfillable_to_foreign( $conditions ); |
||
783 | |||
784 | $container_data = array( |
||
785 | 'id' => $this->get_id(), |
||
786 | 'type' => $this->type, |
||
787 | 'title' => $this->title, |
||
788 | 'classes' => $this->get_classes(), |
||
789 | 'settings' => $this->settings, |
||
790 | 'conditions' => $conditions, |
||
791 | 'fields' => array(), |
||
792 | 'nonce' => array( |
||
793 | 'name' => $this->get_nonce_name(), |
||
794 | 'value' => $this->get_nonce_value(), |
||
795 | ), |
||
796 | ); |
||
797 | |||
798 | $fields = $this->get_fields(); |
||
799 | foreach ( $fields as $field ) { |
||
800 | $field_data = $field->to_json( $load ); |
||
801 | $container_data['fields'][] = $field_data; |
||
802 | } |
||
803 | |||
804 | return $container_data; |
||
805 | } |
||
806 | |||
807 | /** |
||
808 | * COMMON USAGE METHODS |
||
809 | */ |
||
810 | |||
811 | /** |
||
812 | * Append array of fields to the current fields set. All items of the array |
||
813 | * must be instances of Field and their names should be unique for all |
||
814 | * Carbon containers. |
||
815 | * If a field does not have DataStore already, the container datastore is |
||
816 | * assigned to them instead. |
||
817 | * |
||
818 | * @param array $fields |
||
819 | * @return Container $this |
||
820 | */ |
||
821 | public function add_fields( $fields ) { |
||
822 | foreach ( $fields as $field ) { |
||
823 | if ( ! ( $field instanceof Field ) ) { |
||
824 | Incorrect_Syntax_Exception::raise( 'Object must be of type Carbon_Fields\\Field\\Field' ); |
||
825 | return $this; |
||
826 | } |
||
827 | |||
828 | $unique = $this->register_field_name( $field->get_name() ); |
||
829 | if ( ! $unique ) { |
||
830 | return $this; |
||
831 | } |
||
832 | |||
833 | $field->set_context( $this->type ); |
||
834 | if ( ! $field->get_datastore() ) { |
||
835 | $field->set_datastore( $this->get_datastore(), $this->has_default_datastore() ); |
||
836 | } |
||
837 | } |
||
838 | |||
839 | $this->fields = array_merge( $this->fields, $fields ); |
||
840 | |||
841 | return $this; |
||
842 | } |
||
843 | |||
844 | /** |
||
845 | * Configuration function for adding tab with fields |
||
846 | * |
||
847 | * @param string $tab_name |
||
848 | * @param array $fields |
||
849 | * @return Container $this |
||
850 | */ |
||
851 | public function add_tab( $tab_name, $fields ) { |
||
856 | |||
857 | /** |
||
858 | * Proxy function to set attachment conditions |
||
859 | * |
||
860 | * @see Fulfillable_Collection::where() |
||
861 | * @return Container $this |
||
862 | */ |
||
863 | public function where() { |
||
867 | |||
868 | /** |
||
869 | * Proxy function to set attachment conditions |
||
870 | * |
||
871 | * @see Fulfillable_Collection::or_where() |
||
872 | * @return Container $this |
||
873 | */ |
||
874 | public function or_where() { |
||
878 | } |
||
879 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.