Completed
Push — milestone/2.0 ( e0608a...f004ab )
by
unknown
04:47
created

Complex_Field   C

Complexity

Total Complexity 73

Size/Duplication

Total Lines 703
Duplicated Lines 1.71 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 0%

Importance

Changes 8
Bugs 0 Features 1
Metric Value
dl 12
loc 703
ccs 0
cts 269
cp 0
rs 5
c 8
b 0
f 1
wmc 73
lcom 1
cbo 5

30 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A set_hierarchy() 0 4 1
A update_child_hierarchy() 0 7 2
A activate() 0 7 2
A init() 0 12 1
C add_fields() 0 34 7
A set_header_template() 0 19 3
A get_fields() 0 11 2
A setup_labels() 0 4 1
A set_datastore() 12 12 4
A get_clone_under_field_in_hierarchy() 0 6 1
C set_value_from_input() 0 46 7
C get_prefilled_field_groups() 0 38 8
A load() 0 14 3
B save() 0 20 5
A get_value_tree() 0 3 1
A set_value_tree() 0 3 1
A get_formatted_value() 0 16 4
B to_json() 0 42 5
A template() 0 52 1
A template_group() 0 49 1
A template_group_tab_item() 0 15 1
A set_layout() 0 18 2
A set_min() 0 4 1
A get_min() 0 3 1
A set_max() 0 4 1
A get_max() 0 3 1
A set_collapsed() 0 5 1
A get_group_names() 0 3 1
A get_group_by_name() 0 11 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

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 Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Complex_Field 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 Complex_Field, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Carbon_Fields\Field;
4
5
use Carbon_Fields\Datastore\Datastore_Interface;
6
use Carbon_Fields\Helper\Helper;
7
use Carbon_Fields\Field\Field;
8
use Carbon_Fields\Field\Group_Field;
9
use Carbon_Fields\Value_Set\Value_Set;
10
use Carbon_Fields\Exception\Incorrect_Syntax_Exception;
11
12
/**
13
 * Complex field class.
14
 * Allows nested repeaters with multiple field groups to be created.
15
 */
16
class Complex_Field extends Field {
17
18
	const LAYOUT_GRID = 'grid'; // default
19
20
	const LAYOUT_TABBED_HORIZONTAL = 'tabbed-horizontal';
21
22
	const LAYOUT_TABBED_VERTICAL = 'tabbed-vertical';
23
24
	const GROUP_TYPE_KEY = '_type';
25
26
	/**
27
	 * Default field value
28
	 *
29
	 * @var array
30
	 */
31
	protected $default_value = array();
32
33
	protected $layout = self::LAYOUT_GRID;
34
35
	protected $value_tree = array();
36
37
	protected $fields = array();
38
39
	protected $groups = array();
40
41
	protected $values_min = -1;
42
43
	protected $values_max = -1;
44
45
	protected $collapsed = false;
46
47
	public $labels = array(
48
		'singular_name' => 'Entry',
49
		'plural_name' => 'Entries',
50
	);
51
52
	/**
53
	 * Create a field from a certain type with the specified label.
54
	 * 
55
	 * @param string $type  Field type
56
	 * @param string $name  Field name
57
	 * @param string $label Field label
58
	 */
59
	protected function __construct( $type, $name, $label ) {
60
		$this->set_value_set( new Value_Set( Value_Set::TYPE_MULTIPLE_VALUES ) );
61
		parent::__construct( $type, $name, $label );
62
	}
63
64
	/**
65
	 * Set array of hierarchy field names
66
	 **/
67
	public function set_hierarchy( $hierarchy ) {
68
		parent::set_hierarchy( $hierarchy );
69
		$this->update_child_hierarchy();
70
	}
71
	
72
	/**
73
	 * Propagate hierarchy to child fields
74
	 **/
75
	public function update_child_hierarchy() {
76
		$hierarchy = array_merge( $this->get_hierarchy(), array( $this->get_base_name() ) );
77
		$fields = $this->get_fields();
78
		foreach ( $fields as $field ) {
79
			$field->set_hierarchy( $hierarchy );
80
		}
81
	}
82
83
	/**
84
	 * Activate the field once the container is attached.
85
	 */
86
	public function activate() {
87
		parent::activate();
88
		$fields = $this->get_fields();
89
		foreach ( $fields as $field ) {
90
			$field->activate();
91
		}
92
	}
93
94
	/**
95
	 * Initialization tasks.
96
	 */
97
	public function init() {
98
		$this->labels = array(
99
			'singular_name' => __( 'Entry', \Carbon_Fields\TEXT_DOMAIN ),
100
			'plural_name' => __( 'Entries', \Carbon_Fields\TEXT_DOMAIN ),
101
		);
102
103
		// Include the complex group Underscore templates
104
		$this->add_template( 'Complex-Group', array( $this, 'template_group' ) );
105
		$this->add_template( 'Complex-Group-Tab-Item', array( $this, 'template_group_tab_item' ) );
106
107
		parent::init();
108
	}
109
110
	/**
111
	 * Add a set/group of fields.
112
	 *
113
	 * Accepted param variations:
114
	 *   - array<Field> $fields
115
	 *   - string $group_name, array<Field> $fields
116
	 *   - string $group_name, string $group_label, array<Field> $fields
117
	 * 
118
	 * @return $this
119
	 */
120
	public function add_fields() {
121
		$argv = func_get_args();
122
		$argc = count( $argv );
123
		$fields = $argv[ $argc - 1 ];
124
		$name = '';
125
		$label = null;
126
127
		if ( $argc >= 2 ) {
128
			$name = $argv[0];
129
		}
130
		
131
		if ( $argc >= 3 ) {
132
			$label = $argv[1];
133
		}
134
135
		$name = ! empty( $name ) ? $name : Group_Field::DEFAULT_GROUP_NAME;
136
137
		if ( array_key_exists( $name, $this->groups ) ) {
138
			Incorrect_Syntax_Exception::raise( 'Group with name "' . $name . '" in Complex Field "' . $this->get_label() . '" already exists.' );
139
		}
140
141
		foreach ( $fields as $field ) {
142
			if ( $field->get_base_name() === static::GROUP_TYPE_KEY ) {
143
				Incorrect_Syntax_Exception::raise( '"' . static::GROUP_TYPE_KEY . '" is a reserved keyword for Complex fields and cannot be used for a field name.' );
144
			}
145
		}
146
147
		$group = new Group_Field( $name, $label, $fields );
148
149
		$this->groups[ $group->get_name() ] = $group;
150
		$this->update_child_hierarchy();
151
152
		return $this;
153
	}
154
155
	/**
156
	 * Set the group label Underscore template.
157
	 *
158
	 * @param  string|callable $template
159
	 * @return $this
160
	 */
161
	public function set_header_template( $template ) {
162
		if ( count( $this->groups ) === 0 ) {
163
			Incorrect_Syntax_Exception::raise( "Can't set group label template. There are no present groups for Complex Field " . $this->get_label() . '.' );
164
		}
165
166
		$template = is_callable( $template ) ? call_user_func( $template ) : $template;
167
168
		// Assign the template to the group that was added last
169
		$values = array_values( $this->groups );
170
		$group = end( $values );
171
		$group->set_label_template( $template );
172
173
		// Include the group label Underscore template
174
		$this->add_template( $group->get_group_id(), array( $group, 'template_label' ) );
175
176
		$this->groups[ $group->get_name() ] = $group;
177
178
		return $this;
179
	}
180
181
	/**
182
	 * Retrieve all groups of fields.
183
	 *
184
	 * @return array $fields
185
	 */
186
	public function get_fields() {
187
		$fields = array();
188
189
		foreach ( $this->groups as $group ) {
190
			$group_fields = $group->get_fields();
191
192
			$fields = array_merge( $fields, $group_fields );
193
		}
194
195
		return $fields;
196
	}
197
198
	/**
199
	 * Set the field labels.
200
	 * Currently supported values:
201
	 *  - singular_name - the singular entry label
202
	 *  - plural_name - the plural entries label
203
	 *
204
	 * @param  array $labels Labels
205
	 */
206
	public function setup_labels( $labels ) {
207
		$this->labels = array_merge( $this->labels, $labels );
208
		return $this;
209
	}
210
211
	/**
212
	 * Set the datastore of this field.
213
	 *
214
	 * @param Datastore_Interface $datastore
215
	 */
216 View Code Duplication
	public function set_datastore( Datastore_Interface $datastore, $set_as_default = false ) {
217
		if ( $set_as_default && ! $this->has_default_datastore() ) {
218
			return $this; // datastore has been overriden with a custom one - abort changing to a default one
219
		}
220
		$this->datastore = $datastore;
221
		$this->has_default_datastore = $set_as_default;
222
223
		foreach ( $this->groups as $group ) {
224
			$group->set_datastore( $this->get_datastore(), true );
225
		}
226
		return $this;
227
	}
228
229
	/**
230
	 * Return a clone of a field with hierarchy settings applied
231
	 *
232
	 * @param Field $field
233
	 * @param Field $parent_field
234
	 * @param int $entry_index
235
	 * @return Field
236
	 **/
237
	public function get_clone_under_field_in_hierarchy( $field, $parent_field, $entry_index = 0 ) {
238
		$clone = clone $field;
239
		$clone->set_hierarchy( array_merge( $parent_field->get_hierarchy(), array( $parent_field->get_base_name() ) ) );
240
		$clone->set_hierarchy_index( array_merge( $parent_field->get_hierarchy_index(), array( $entry_index ) ) );
241
		return $clone;
242
	}
243
244
	/**
245
	 * Load the field value from an input array based on it's name.
246
	 *
247
	 * @param array $input Array of field names and values.
248
	 **/
249
	public function set_value_from_input( $input ) {
250
		if ( ! isset( $input[ $this->get_name() ] ) ) {
251
			return;
252
		}
253
254
		$value_tree = array();
255
		$input_groups = $input[ $this->get_name() ];
256
		$input_group_index = 0;
257
		foreach ( $input_groups as $values ) {
258
			if ( ! isset( $values[ static::GROUP_TYPE_KEY ] ) || ! isset( $this->groups[ $values[ static::GROUP_TYPE_KEY ] ] ) ) {
259
				continue;
260
			}
261
262
			$group = $this->get_group_by_name( $values[ static::GROUP_TYPE_KEY ] );
263
			$value_group = array( static::GROUP_TYPE_KEY => $values[ static::GROUP_TYPE_KEY ] );
264
			unset( $values[ static::GROUP_TYPE_KEY ] );
265
266
			$group_fields = $group->get_fields();
267
268
			// trim input values to those used by the field
269
			$group_field_names = array_flip( $group->get_field_names() );
270
			$values = array_intersect_key( $values, $group_field_names );
271
			
272
			foreach ( $group_fields as $field ) {
273
				$tmp_field = $this->get_clone_under_field_in_hierarchy( $field, $this, $input_group_index );
274
275
				$tmp_field->set_value_from_input( $values );
276
				if ( is_a( $tmp_field, get_class() ) ) {
277
					$value_group[ $tmp_field->get_base_name() ] = $tmp_field->get_value_tree();
278
				} else {
279
					$value_group[ $tmp_field->get_base_name() ] = array(
280
						'value_set' => $tmp_field->get_value_set()->get_set(),
281
					);
282
				}
283
			}
284
285
			$value_tree['groups'][] = $value_group;
286
			$value_tree['value_set'][] = array(
287
				Value_Set::VALUE_PROPERTY => $group->get_name(),
288
			);
289
			$input_group_index++;
290
		}
291
292
		$this->set_value( $value_tree['value_set'] );
293
		$this->set_value_tree( $value_tree );
294
	}
295
296
	protected function get_prefilled_field_groups( $value_tree ) {
297
		$fields = array();
298
299
		if ( empty( $value_tree ) ) {
300
			return $fields;
301
		}
302
303
		foreach ( $value_tree['value_set'] as $entry_index => $value ) {
304
			$group_name = $value[ Value_Set::VALUE_PROPERTY ];
305
			$group = $this->get_group_by_name( $group_name );
306
			$group_fields = $group->get_fields();
307
			$fields[ $entry_index ] = array(
308
				static::GROUP_TYPE_KEY => $group->get_name(),
309
			);
310
			$group_values = array();
311
			if ( isset( $value_tree['groups'][ $entry_index ] ) ) {
312
				$group_values = $value_tree['groups'][ $entry_index ];
313
			}
314
315
			foreach ( $group_fields as $field ) {
316
				$clone = $this->get_clone_under_field_in_hierarchy( $field, $this, $entry_index );
317
				if ( isset( $group_values[ $clone->get_base_name() ] ) ) {
318
					$group_value = $group_values[ $clone->get_base_name() ];
319
					
320
					if ( isset( $group_value['value_set'] ) ) {
321
						$clone->set_value( $group_value['value_set'] );
322
					}
323
324
					if ( is_a( $clone, get_class() ) ) {
325
						$clone->set_value_tree( $group_value );
326
					}
327
				}
328
				$fields[ $entry_index ][] = $clone;
329
			}
330
		}
331
332
		return $fields;
333
	}
334
335
	/**
336
	 * Load all groups of fields and their data.
337
	 */
338
	public function load() {
339
		$raw_value_set_tree = $this->get_datastore()->load( $this );
340
		$value = null;
341
		if ( isset( $raw_value_set_tree[ $this->get_base_name() ] ) ) {
342
			$value = $raw_value_set_tree[ $this->get_base_name() ]['value_set'];
343
		}
344
		$this->set_value( $value );
345
346
		if ( $this->get_value() === null ) {
347
			$this->set_value( $this->get_default_value() );
348
		} else {
349
			$this->set_value_tree( $raw_value_set_tree[ $this->get_base_name() ] );
350
		}
351
	}
352
353
	/**
354
	 * Save all contained groups of fields.
355
	 */
356
	public function save() {
357
		// Only delete root field values as nested field values should be deleted in a cascading manner by the datastore
358
		$hierarchy = $this->get_hierarchy();
359
		if ( empty( $hierarchy ) ) {
360
			$this->delete();
361
		}
362
		
363
		$this->get_datastore()->save( $this );
364
365
		$field_groups = $this->get_prefilled_field_groups( $this->get_value_tree() );
366
367
		foreach ( $field_groups as $entry_index => $fields ) {
368
			foreach ( $fields as $field ) {
369
				if ( ! is_a( $field, __NAMESPACE__ . '\\Field' ) ) {
370
					continue;
371
				}
372
				$field->save();
373
			}
374
		}
375
	}
376
377
	/**
378
	 * Return the full value tree of all groups and their fields
379
	 *
380
	 * @return mixed
381
	 **/
382
	public function get_value_tree() {
383
		return (array) $this->value_tree;
384
	}
385
386
	/**
387
	 * Set the full value tree of all groups and their fields
388
	 *
389
	 * Tree Schema
390
	 * 'value_set' => array(
391
	 * 		array(
392
	 * 			'value' => '_',
393
	 * 		),
394
	 * 		...
395
	 * ),
396
	 * 'groups' => array(
397
	 * 		array(
398
	 * 			'field1' => array(
399
	 * 				'value_set'=>array(
400
	 * 					array(
401
	 * 						'value' => ...,
402
	 * 						...
403
	 * 					),
404
	 * 					...
405
	 * 				),
406
	 * 			),
407
	 * 			...
408
	 * 		),
409
	 * 		...
410
	 * ),
411
	 * 
412
	 * @return mixed
413
	 **/
414
	public function set_value_tree( $value_tree ) {
415
		return $this->value_tree = $value_tree;
416
	}
417
418
	/**
419
	 * Return a differently formatted value for end-users
420
	 *
421
	 * @return mixed
422
	 **/
423
	public function get_formatted_value() {
424
		$field_groups = $this->get_prefilled_field_groups( $this->get_value_tree() );
425
		
426
		$value = array();
427
		foreach ( $field_groups as $entry_index => $field_group ) {
428
			$value[ $entry_index ] = array();
429
			foreach ( $field_group as $key => $field ) {
430
				if ( is_a( $field, __NAMESPACE__ . '\\Field' ) ) {
431
					$value[ $entry_index ][ $field->get_base_name() ] = $field->get_formatted_value(); 
432
				} else {
433
					$value[ $entry_index ][ $key ] = $field;
434
				}
435
			}
436
		}
437
		return $value;
438
	}
439
440
	/**
441
	 * Returns an array that holds the field data, suitable for JSON representation.
442
	 * This data will be available in the Underscore template and the Backbone Model.
443
	 *
444
	 * @param bool $load  Should the value be loaded from the database or use the value from the current instance.
445
	 * @return array
446
	 */
447
	public function to_json( $load ) {
448
		$complex_data = parent::to_json( $load );
449
450
		$groups_data = array();
451
		foreach ( $this->groups as $group ) {
452
			$groups_data[] = $group->to_json( false );
453
		}
454
455
		$field_groups = $this->get_prefilled_field_groups( $this->get_value_tree() );
456
		$value_data = array();
457
		foreach ( $field_groups as $entry_index => $fields ) {
458
			$group = $this->get_group_by_name( $fields[ static::GROUP_TYPE_KEY ] );
459
460
			$data = array(
461
				'name' => $group->get_name(),
462
				'label' => $group->get_label(),
463
				'group_id' => $group->get_group_id(),
464
				'fields' => array(),
465
			);
466
467
			foreach ( $fields as $field ) {
468
				if ( ! is_a( $field, __NAMESPACE__ . '\\Field' ) ) {
469
					continue;
470
				}
471
				$data['fields'][] = $field->to_json( false );
472
			}
473
474
			$value_data[] = $data;
475
		}
476
477
		$complex_data = array_merge( $complex_data, array(
478
			'layout' => $this->layout,
479
			'labels' => $this->labels,
480
			'min' => $this->get_min(),
481
			'max' => $this->get_max(),
482
			'multiple_groups' => count( $groups_data ) > 1,
483
			'groups' => $groups_data,
484
			'value' => $value_data,
485
			'collapsed' => $this->collapsed,
486
		) );
487
		return $complex_data;
488
	}
489
490
	/**
491
	 * The main Underscore template.
492
	 */
493
	public function template() {
494
		?>
495
		<div class="carbon-subcontainer carbon-grid {{ multiple_groups ? 'multiple-groups' : '' }}">
496
			<div class="carbon-empty-row carbon-empty-row-visible">
497
				{{{ crbl10n.complex_no_rows.replace('%s', labels.plural_name) }}}
498
			</div>
499
500
			<div class="groups-wrapper layout-{{ layout }}">
501
				<# if (layout === '<?php echo static::LAYOUT_TABBED_HORIZONTAL ?>' || layout === '<?php echo static::LAYOUT_TABBED_VERTICAL ?>' ) { #>
502
					<div class="group-tabs-nav-holder">
503
						<ul class="group-tabs-nav"></ul>
504
505
						<div class="carbon-actions">
506
							<div class="carbon-button">
507
								<a href="#" class="button" data-group="{{{ multiple_groups ? '' : groups[0].name }}}">
508
									+
509
								</a>
510
511
								<# if (multiple_groups) { #>
512
									<ul>
513
										<# _.each(groups, function(group) { #>
514
											<li><a href="#" data-group="{{{ group.name }}}">{{{ group.label }}}</a></li>
515
										<# }); #>
516
									</ul>
517
								<# } #>
518
							</div>
519
						</div>
520
					</div><!-- /.group-tabs-nav-holder -->
521
				<# } #>
522
523
				<div class="carbon-groups-holder"></div>
524
				<div class="clear"></div>
525
			</div>
526
527
			<div class="carbon-actions">
528
				<div class="carbon-button">
529
					<a href="#" class="button" data-group="{{{ multiple_groups ? '' : groups[0].name }}}">
530
						{{{ crbl10n.complex_add_button.replace('%s', labels.singular_name) }}}
531
					</a>
532
533
					<# if (multiple_groups) { #>
534
						<ul>
535
							<# _.each(groups, function(group) { #>
536
								<li><a href="#" data-group="{{{ group.name }}}">{{{ group.label }}}</a></li>
537
							<# }); #>
538
						</ul>
539
					<# } #>
540
				</div>
541
			</div>
542
		</div>
543
		<?php
544
	}
545
546
	/**
547
	 * The Underscore template for the complex field group.
548
	 */
549
	public function template_group() {
550
		?>
551
		<div id="carbon-{{{ complex_name }}}-complex-container" class="carbon-row carbon-group-row" data-group-id="{{ id }}">
552
			<input type="hidden" name="{{{ complex_name + '[' + index + ']' }}}[_type]" value="{{ name }}" />
553
554
			<div class="carbon-drag-handle">
555
				<span class="group-number">{{{ order + 1 }}}</span><span class="group-name">{{{ label_template || label }}}</span>
556
			</div>
557
558
			<div class="carbon-group-actions carbon-group-actions-{{ layout }}">
559
				<a class="carbon-btn-duplicate dashicons-before dashicons-admin-page" href="#" title="<?php esc_attr_e( 'Clone', \Carbon_Fields\TEXT_DOMAIN ); ?>">
560
					<?php _e( 'Clone', \Carbon_Fields\TEXT_DOMAIN ); ?>
561
				</a>
562
563
				<a class="carbon-btn-remove dashicons-before dashicons-trash" href="#" title="<?php esc_attr_e( 'Remove', \Carbon_Fields\TEXT_DOMAIN ); ?>">
564
					<?php _e( 'Remove', \Carbon_Fields\TEXT_DOMAIN ); ?>
565
				</a>
566
567
				<a class="carbon-btn-collapse dashicons-before dashicons-arrow-up" href="#" title="<?php esc_attr_e( 'Collapse/Expand', \Carbon_Fields\TEXT_DOMAIN ); ?>">
568
					<?php _e( 'Collapse/Expand', \Carbon_Fields\TEXT_DOMAIN ); ?>
569
				</a>
570
			</div>
571
572
			<div class="fields-container">
573
				<# _.each(fields, function(field) { #>
574
					<div class="carbon-row carbon-subrow subrow-{{{ field.type }}} {{{ field.classes.join(' ') }}}">
575
						<label for="{{{ complex_id + '-' + field.id + '-' + index }}}">
576
							{{ field.label }}
577
578
							<# if (field.required) { #>
579
								 <span class="carbon-required">*</span>
580
							<# } #>
581
						</label>
582
583
						<div class="field-holder {{{ complex_id + '-' + field.id + '-' + index }}}"></div>
584
585
						<# if (field.help_text) { #>
586
							<em class="help-text">
587
								{{{ field.help_text }}}
588
							</em>
589
						<# } #>
590
591
						<em class="carbon-error"></em>
592
					</div>
593
				<# }) #>
594
			</div>
595
		</div>
596
		<?php
597
	}
598
599
	 /**
600
	 * The Underscore template for the group item tab.
601
	 */
602
	public function template_group_tab_item() {
603
		?>
604
		<li class="group-tab-item" data-group-id="{{ id }}">
605
			<a href="#">
606
				<span class="group-handle"></span>
607
608
				<# if (label_template || label) { #>
609
					<span class="group-name">{{{ label_template || label }}}</span>
610
				<# } #>
611
				<span class="group-number">{{{ order + 1 }}}</span>
612
				<span class="dashicons dashicons-warning carbon-complex-group-error-badge" ></span>
613
			</a>
614
		</li>
615
		<?php
616
	}
617
618
	/**
619
	 * Modify the layout of this field.
620
	 *
621
	 * @param string $layout
622
	 */
623
	public function set_layout( $layout ) {
624
		$available_layouts = array(
625
			static::LAYOUT_GRID,
626
			static::LAYOUT_TABBED_HORIZONTAL,
627
			static::LAYOUT_TABBED_VERTICAL,
628
		);
629
630
		if ( ! in_array( $layout,  $available_layouts ) ) {
631
			$error_message = 'Incorrect layout ``' . $layout . '" specified. ' .
632
				'Available layouts: ' . implode( ', ', $available_layouts );
633
634
			Incorrect_Syntax_Exception::raise( $error_message );
635
		}
636
637
		$this->layout = $layout;
638
639
		return $this;
640
	}
641
642
	/**
643
	 * Set the minimum number of entries.
644
	 *
645
	 * @param int $min
646
	 */
647
	public function set_min( $min ) {
648
		$this->values_min = intval( $min );
649
		return $this;
650
	}
651
652
	/**
653
	 * Get the minimum number of entries.
654
	 *
655
	 * @return int $min
656
	 */
657
	public function get_min() {
658
		return $this->values_min;
659
	}
660
661
	/**
662
	 * Set the maximum number of entries.
663
	 *
664
	 * @param int $max
665
	 */
666
	public function set_max( $max ) {
667
		$this->values_max = intval( $max );
668
		return $this;
669
	}
670
671
	/**
672
	 * Get the maximum number of entries.
673
	 *
674
	 * @return int $max
675
	 */
676
	public function get_max() {
677
		return $this->values_max;
678
	}
679
680
	/**
681
	 * Change the groups initial collapse state.
682
	 * This state relates to the state of which the groups are rendered.
683
	 *
684
	 * @param bool $collapsed
685
	 */
686
	public function set_collapsed( $collapsed = true ) {
687
		$this->collapsed = $collapsed;
688
689
		return $this;
690
	}
691
692
	/**
693
	 * Retrieve the groups of this field.
694
	 *
695
	 * @return array
696
	 */
697
	public function get_group_names() {
698
		return array_keys( $this->groups );
699
	}
700
701
	/**
702
	 * Retrieve a group by its name.
703
	 *
704
	 * @param  string $group_name        Group name
705
	 * @return Group_Field $group_object Group object
706
	 */
707
	public function get_group_by_name( $group_name ) {
708
		$group_object = null;
709
710
		foreach ( $this->groups as $group ) {
711
			if ( $group->get_name() == $group_name ) {
712
				$group_object = $group;
713
			}
714
		}
715
716
		return $group_object;
717
	}
718
}
719