Completed
Push — master ( d802b6...c8177c )
by
unknown
08:06 queued 01:47
created

Complex_Field::set_layout()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 31
Code Lines 17

Duplication

Lines 6
Ratio 19.35 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 4
eloc 17
nc 8
nop 1
dl 6
loc 31
rs 8.5806
c 2
b 0
f 0
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\Exception\Incorrect_Syntax_Exception;
10
11
/**
12
 * Complex field class.
13
 * Allows nested repeaters with multiple field groups to be created.
14
 */
15
class Complex_Field extends Field {
16
	const LAYOUT_GRID = 'grid'; // default
17
	const LAYOUT_LIST = 'list'; // deprecated
18
	const LAYOUT_TABBED = 'tabbed'; // deprecated
19
	const LAYOUT_TABBED_HORIZONTAL = 'tabbed-horizontal';
20
	const LAYOUT_TABBED_VERTICAL = 'tabbed-vertical';
21
22
	protected $fields = array();
23
	protected $values = array();
24
	protected $groups = array();
25
26
	protected $layout = self::LAYOUT_GRID;
27
	protected $values_min = -1;
28
	protected $values_max = -1;
29
30
	public $labels = array(
31
		'singular_name' => 'Entry',
32
		'plural_name' => 'Entries',
33
	);
34
35
	/**
36
	 * Initialization tasks.
37
	 */
38
	public function init() {
39
		$this->labels = array(
40
			'singular_name' => __( 'Entry', 'carbon-fields' ),
41
			'plural_name' => __( 'Entries', 'carbon-fields' ),
42
		);
43
44
		// Include the complex group Underscore templates
45
		$this->add_template( 'Complex-Group', array( $this, 'template_group' ) );
46
		$this->add_template( 'Complex-Group-Tab-Item', array( $this, 'template_group_tab_item' ) );
47
48
		parent::init();
49
	}
50
51
	/**
52
	 * Add a set/group of fields.
53
	 *
54
	 * @return $this
55
	 */
56
	public function add_fields() {
57
		$argv = func_get_args();
58
		$argc = count( $argv );
59
60
		if ( $argc == 1 ) {
61
			$fields = $argv[0];
62
			$name = '';
63
			$label = null;
64
		} else if ( $argc == 2 ) {
65 View Code Duplication
			if ( is_array( $argv[0] ) ) {
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
66
				list( $fields, $name ) = $argv;
67
			} else {
68
				list( $name, $fields ) = $argv;
69
			}
70
			$label = null;
71
		} else if ( $argc == 3 ) {
72 View Code Duplication
			if ( is_array( $argv[0] ) ) {
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
73
				list( $fields, $name, $label ) = $argv;
74
			} else {
75
				list( $name, $label, $fields ) = $argv;
76
			}
77
		}
78
79
		if ( array_key_exists( '_' . $name, $this->groups ) ) {
80
			Incorrect_Syntax_Exception::raise( 'Group with name "' . $name . '" in Complex Field "' . $this->get_label() . '" already exists.' );
0 ignored issues
show
Bug introduced by
The variable $name does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
81
		}
82
83
		$group = new Group_Field($name, $label, $fields);
0 ignored issues
show
Bug introduced by
The variable $label does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $fields does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
84
85
		$this->groups[ $group->get_name() ] = $group;
86
87
		return $this;
88
	}
89
90
	/**
91
	 * Set the group label Underscore template.
92
	 *
93
	 * @param  string|callable $template
94
	 * @return $this
95
	 */
96
	public function set_header_template( $template ) {
97
		if ( count($this->groups) === 0 ) {
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
98
			Incorrect_Syntax_Exception::raise( "Can't set group label template. There are no present groups for Complex Field " . $this->get_label() . "." );
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal . does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
99
		}
100
101
		$template = is_callable( $template ) ? call_user_func( $template ) : $template;
102
103
		// Assign the template to the group that was added last
104
		$values = array_values( $this->groups );
105
		$group = end( $values );
106
		$group->set_label_template( $template );
107
108
		// Include the group label Underscore template
109
		$this->add_template( $group->get_group_id(), array( $group, 'template_label' ) );
110
111
		$this->groups[ $group->get_name() ] = $group;
112
113
		return $this;
114
	}
115
116
	/**
117
	 * Retrieve all groups of fields.
118
	 *
119
	 * @return array $fields
120
	 */
121
	public function get_fields() {
122
		$fields = array();
123
124
		foreach ( $this->groups as $group ) {
125
			$group_fields = $group->get_fields();
126
127
			$fields = array_merge( $fields, $group_fields );
128
		}
129
130
		return $fields;
131
	}
132
133
	/**
134
	 * Set the field labels.
135
	 * Currently supported values:
136
	 *  - singular_name - the singular entry label
137
	 *  - plural_name - the plural entries label
138
	 *
139
	 * @param  array $labels Labels
140
	 */
141
	public function setup_labels( $labels ) {
142
		$this->labels = array_merge( $this->labels, $labels );
143
		return $this;
144
	}
145
146
	/**
147
	 * Set the datastore of this field.
148
	 *
149
	 * @param Datastore_Interface $store
150
	 */
151
	public function set_datastore( Datastore_Interface $store ) {
152
		$this->store = $store;
153
154
		foreach ( $this->groups as $group ) {
155
			$group->set_datastore( $this->store );
156
		}
157
	}
158
159
	/**
160
	 * Load the field value from an input array based on it's name.
161
	 *
162
	 * @param array $input (optional) Array of field names and values. Defaults to $_POST
163
	 **/
164
	public function set_value_from_input( $input = null ) {
165
		$this->values = array();
166
167
		if ( is_null( $input ) ) {
168
			$input = $_POST;
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
169
		}
170
171
		if ( ! isset( $input[ $this->get_name() ] ) ) {
172
			return;
173
		}
174
175
		$input_groups = $input[ $this->get_name() ];
176
		$index = 0;
177
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
178
179
		foreach ( $input_groups as $values ) {
180
			$value_group = array();
181
			if ( ! isset( $values['group'] ) || ! isset( $this->groups[ $values['group'] ] ) ) {
182
				continue;
183
			}
184
185
			$group = $this->groups[ $values['group'] ];
186
			unset( $values['group'] );
187
188
			$group_fields = $group->get_fields();
189
190
			// trim input values to those used by the field
191
			$group_field_names = array_flip( $group->get_field_names() );
192
			$values = array_intersect_key( $values, $group_field_names );
193
194
			foreach ( $group_fields as $field ) {
195
				// set value from the group
196
				$tmp_field = clone $field;
197
				if ( is_a( $tmp_field, __NAMESPACE__ . '\\Complex_Field' ) ) {
198
					if ( ! isset( $values[ $tmp_field->get_name() ] ) ) {
199
						continue; // bail if the complex field is empty
200
					}
201
202
					$new_name = $this->get_name() . $group->get_name() . '-' . $field->get_name() . '_' . $index;
203
					$new_values = array( $new_name => $values[ $tmp_field->get_name() ] );
204
205
					$tmp_field->set_name( $new_name );
206
					$tmp_field->set_value_from_input( $new_values );
207
				} else {
208
					$tmp_field->set_value_from_input( $values );
209
				}
210
211
				// update name to group name
212
				$tmp_field->set_name( $this->get_name() . $group->get_name() . '-' . $field->get_name() . '_' . $index );
213
				$value_group[] = $tmp_field;
214
			}
215
216
			$this->values[] = $value_group;
217
			$index++;
218
		}
219
	}
220
221
	/**
222
	 * Load all groups of fields and their data.
223
	 */
224
	public function load() {
225
		// load existing groups
226
		$this->load_values();
227
	}
228
229
	/**
230
	 * Save all contained groups of fields.
231
	 */
232
	public function save() {
233
		$this->delete();
234
235
		foreach ( $this->values as $value ) {
236
			foreach ( $value as $field ) {
237
				$field->save();
238
			}
239
		}
240
	}
241
242
	/**
243
	 * Delete the values of all contained fields.
244
	 */
245
	public function delete() {
246
		return $this->store->delete_values( $this );
247
	}
248
249
	/**
250
	 * Load and parse the field data.
251
	 */
252
	public function load_values() {
253
		return $this->load_values_from_db();
254
	}
255
256
	/**
257
	 * Load and parse the field data from the database.
258
	 */
259
	public function load_values_from_db() {
260
		$this->values = array();
261
262
		$group_rows = $this->store->load_values( $this );
263
264
		return $this->process_loaded_values( $group_rows );
265
	}
266
267
	/**
268
	 * Load and parse a raw set of field data.
269
	 *
270
	 * @param  array $values Raw data entries
271
	 * @return array 		 Processed data entries
272
	 */
273
	public function load_values_from_array( $values ) {
274
		$this->values = array();
275
276
		$group_rows = array();
277
278
		$meta_key = $this->get_name();
279
280
		foreach ( $values as $key => $value ) {
281
			if ( strpos( $key, $meta_key ) !== 0 ) {
282
				continue;
283
			}
284
285
			$group_rows[] = array(
286
				'field_key' => preg_replace( '~^(' . preg_quote( $this->name, '~' ) . ')_\d+_~', '$1_', $key ),
287
				'field_value' => $value,
288
			);
289
		}
290
291
		return $this->process_loaded_values( $group_rows );
292
	}
293
294
	/**
295
	 * Parse groups of raw field data into the actual field hierarchy.
296
	 *
297
	 * @param  array $group_rows Group rows
298
	 */
299
	public function process_loaded_values( $group_rows ) {
300
		$input_groups = array();
301
302
		// Set default values
303
		$field_names = array();
304
		foreach ( $this->groups as $group ) {
305
			$group_fields = $group->get_fields();
306
			foreach ( $group_fields as $field ) {
307
				$field_names[] = $field->get_name();
308
				$field->set_value( $field->get_default_value() );
309
			}
310
		}
311
312
		if ( empty( $group_rows ) ) {
313
			return;
314
		}
315
316
		// load and parse values and group type
317
		foreach ( $group_rows as $row ) {
318
			if ( ! preg_match( Helper::get_complex_field_regex( $this->name, array_keys( $this->groups ), $field_names ), $row['field_key'], $field_name ) ) {
319
				continue;
320
			}
321
322
			$row['field_value'] = maybe_unserialize( $row['field_value'] );
323
			$input_groups[ $field_name['index'] ]['type'] = $field_name['group'];
324
325
			if ( ! empty( $field_name['trailing'] ) ) {
326
				$input_groups[ $field_name['index'] ][ $field_name['key'] . '_' . $field_name['sub'] . '-' . $field_name['trailing'] ] = $row['field_value'];
327 View Code Duplication
			} else if ( ! empty( $field_name['sub'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
328
				$input_groups[ $field_name['index'] ][ $field_name['key'] ][ $field_name['sub'] ] = $row['field_value'];
329
			} else {
330
				$input_groups[ $field_name['index'] ][ $field_name['key'] ] = $row['field_value'];
331
			}
332
		}
333
334
		// create groups list with loaded fields
335
		ksort( $input_groups );
336
337
		foreach ( $input_groups as $index => $values ) {
338
			$value_group = array( 'type' => $values['type'] );
339
			$group_fields = $this->groups[ $values['type'] ]->get_fields();
340
			unset( $values['type'] );
341
342
			foreach ( $group_fields as $field ) {
343
				// set value from the group
344
				$tmp_field = clone $field;
345
346
				if ( is_a( $field, __NAMESPACE__ . '\\Complex_Field' ) ) {
347
					$tmp_field->load_values_from_array( $values );
348
				} else {
349
					$tmp_field->set_value_from_input( $values );
350
				}
351
352
				$value_group[] = $tmp_field;
353
			}
354
355
			$this->values[] = $value_group;
356
		}
357
	}
358
359
	/**
360
	 * Retrieve the field values.
361
	 * @return array
362
	 */
363
	public function get_values() {
364
		return $this->values;
365
	}
366
367
	/**
368
	 * Generate and set the field prefix.
369
	 * @param string $prefix
370
	 */
371
	public function set_prefix( $prefix ) {
372
		parent::set_prefix( $prefix );
373
374
		foreach ( $this->groups as $group ) {
375
			$group->set_prefix( $prefix );
376
		}
377
	}
378
379
	/**
380
	 * Returns an array that holds the field data, suitable for JSON representation.
381
	 * This data will be available in the Underscore template and the Backbone Model.
382
	 *
383
	 * @param bool $load  Should the value be loaded from the database or use the value from the current instance.
384
	 * @return array
385
	 */
386
	public function to_json( $load ) {
387
		$complex_data = parent::to_json( $load );
388
389
		$groups_data = array();
390
		$values_data = array();
391
392
		foreach ( $this->groups as $group ) {
393
			$groups_data[] = $group->to_json( false );
394
		}
395
396
		foreach ( $this->values as $fields ) {
397
			$group = $this->get_group_by_name( $fields['type'] );
398
			unset( $fields['type'] );
399
400
			$data = array(
401
				'name' => $group->get_name(),
402
				'label' => $group->get_label(),
403
				'group_id' => $group->get_group_id(),
404
				'fields' => array(),
405
			);
406
407
			foreach ( $fields as $index => $field ) {
408
				$data['fields'][] = $field->to_json( false );
409
			}
410
411
			$values_data[] = $data;
412
		}
413
414
		$complex_data = array_merge( $complex_data, array(
415
			'layout' => $this->layout,
416
			'labels' => $this->labels,
417
			'min' => $this->get_min(),
418
			'max' => $this->get_max(),
419
			'multiple_groups' => count( $groups_data ) > 1,
420
			'groups' => $groups_data,
421
			'value' => $values_data,
422
		) );
423
424
		return $complex_data;
425
	}
426
427
	/**
428
	 * The main Underscore template.
429
	 */
430
	public function template() {
431
		?>
432
		<div class="carbon-subcontainer carbon-grid {{ multiple_groups ? 'multiple-groups' : '' }}">
433
			<div class="carbon-empty-row">
434
				{{{ crbl10n.complex_no_rows.replace('%s', labels.plural_name) }}}
435
			</div>
436
437
			<div class="groups-wrapper layout-{{ layout }}">
438
				<# if (layout === '<?php echo self::LAYOUT_TABBED_HORIZONTAL ?>' || layout === '<?php echo self::LAYOUT_TABBED_VERTICAL ?>' ) { #>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not 'self'
Loading history...
439
					<div class="group-tabs-nav-holder">
440
						<ul class="group-tabs-nav"></ul>
441
442
						<div class="carbon-actions">
443
							<div class="carbon-button">
444
								<a href="#" class="button" data-group="{{{ multiple_groups ? '' : groups[0].name }}}">
445
									+
446
								</a>
447
448
								<# if (multiple_groups) { #>
449
									<ul>
450
										<# _.each(groups, function(group) { #>
451
											<li><a href="#" data-group="{{{ group.name }}}">{{{ group.label }}}</a></li>
452
										<# }); #>
453
									</ul>
454
								<# } #>
455
							</div>
456
						</div>
457
					</div><!-- /.group-tabs-nav-holder -->
458
				<# } #>
459
460
				<div class="carbon-groups-holder"></div>
461
				<div class="clear"></div>
462
			</div>
463
464
			<div class="carbon-actions">
465
				<div class="carbon-button">
466
					<a href="#" class="button" data-group="{{{ multiple_groups ? '' : groups[0].name }}}">
467
						{{{ crbl10n.complex_add_button.replace('%s', labels.singular_name) }}}
468
						{{{ multiple_groups ? '&#8681;' : '' }}}
469
					</a>
470
471
					<# if (multiple_groups) { #>
472
						<ul>
473
							<# _.each(groups, function(group) { #>
474
								<li><a href="#" data-group="{{{ group.name }}}">{{{ group.label }}}</a></li>
475
							<# }); #>
476
						</ul>
477
					<# } #>
478
				</div>
479
			</div>
480
		</div>
481
		<?php
482
	}
483
484
	/**
485
	 * The Underscore template for the complex field group.
486
	 */
487
	public function template_group() {
488
		?>
489
		<div id="carbon-{{{ complex_name }}}-complex-container" class="carbon-row carbon-group-row" data-group-id="{{ id }}">
490
			<input type="hidden" name="{{{ complex_name + '[' + index + ']' }}}[group]" value="{{ name }}" />
491
492
			<div class="carbon-drag-handle">
493
				<span class="group-number">{{{ order + 1 }}}</span><span class="group-name">{{{ label_template || label }}}</span>
494
			</div>
495
496
			<div class="carbon-group-actions">
497
				<a class="carbon-btn-collapse" href="#" title="<?php esc_attr_e( 'Collapse/Expand', 'carbon_fields' ); ?>">
498
					<?php _e( 'Collapse/Expand', 'carbon_fields' ); ?>
499
				</a>
500
501
				<a class="carbon-btn-duplicate" href="#" title="<?php esc_attr_e( 'Clone', 'carbon_fields' ); ?>">
502
					<?php _e( 'Clone', 'carbon_fields' ); ?>
503
				</a>
504
505
				<a class="carbon-btn-remove" href="#" title="<?php esc_attr_e( 'Remove', 'carbon_fields' ); ?>">
506
					<?php _e( 'Remove', 'carbon_fields' ); ?>
507
				</a>
508
			</div>
509
510
			<div class="fields-container">
511
				<# _.each(fields, function(field) { #>
512
					<div class="carbon-row carbon-subrow subrow-{{{ field.type }}} {{{ field.classes.join(' ') }}}">
513
						<label for="{{{ complex_id + '-' + field.id + '-' + index }}}">
514
							{{ field.label }}
515
516
							<# if (field.required) { #>
517
								 <span class="carbon-required">*</span>
518
							<# } #>
519
						</label>
520
521
						<div class="field-holder {{{ complex_id + '-' + field.id + '-' + index }}}"></div>
522
523
						<# if (field.help_text) { #>
524
							<em class="help-text">
525
								{{{ field.help_text }}}
526
							</em>
527
						<# } #>
528
529
						<em class="carbon-error"></em>
530
					</div>
531
				<# }) #>
532
			</div>
533
		</div>
534
		<?php
535
	}
536
537
	 /**
538
	 * The Underscore template for the group item tab.
539
	 */
540
	public function template_group_tab_item() {
541
		?>
542
		<li class="group-tab-item" data-group-id="{{ id }}">
543
			<a href="#">
544
				<span class="group-handle"></span>
545
				
546
				<# if (label_template || label) { #>
547
					<span class="group-name">{{{ label_template || label }}}</span>
548
				<# } #>
549
				<span class="group-number">{{{ order + 1 }}}</span>
550
			</a>
551
		</li>
552
		<?php
553
	}
554
555
	/**
556
	 * Modify the layout of this field.
557
	 *
558
	 * @param string $layout
559
	 */
560
	public function set_layout( $layout ) {
561
		$available_layouts = array(
562
			self::LAYOUT_GRID,
563
			self::LAYOUT_TABBED_HORIZONTAL,
564
			self::LAYOUT_TABBED_VERTICAL,
565
			self::LAYOUT_LIST,
566
		);
567
568
		if ( $layout === self::LAYOUT_TABBED ) {
569
			// The library used to provide just one kind of tabs -- horizontal ones. Later vertical tabs were added.
570
			// So the "tabbed" name was renamed to "tabbed-horizontal" and "tabbed-vertical" layout was introduced.
571
			_doing_it_wrong( __METHOD__, __( 'Complex field "' . self::LAYOUT_TABBED . '" layout is deprecated, please use "' . self::LAYOUT_TABBED_HORIZONTAL . '" or "' . self::LAYOUT_TABBED_VERTICAL . '"  instead', 'carbon_fields' ), null );
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not 'self'
Loading history...
572
573
			$layout = self::LAYOUT_TABBED_HORIZONTAL;
574
		}
575
576 View Code Duplication
		if ( ! in_array( $layout,  $available_layouts ) ) {
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
577
			$error_message = 'Incorrect layout ``' . $layout . '" specified. ' .
578
				'Available layouts: ' . implode( ', ', $available_layouts );
579
580
			Incorrect_Syntax_Exception::raise( $error_message );
581
		}
582
583
		if ( $layout === self::LAYOUT_LIST ) {
584
			_doing_it_wrong( __METHOD__, __( 'Complex field <code>' . self::LAYOUT_LIST . '</code> layout is deprecated, please use <code>set_width()</code> instead.', 'carbon_fields' ), null );
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not 'self'
Loading history...
585
		}
586
587
		$this->layout = $layout;
588
589
		return $this;
590
	}
591
592
	/**
593
	 * Set the minimum number of entries.
594
	 *
595
	 * @param int $min
596
	 */
597
	public function set_min( $min ) {
598
		$this->values_min = intval( $min );
599
		return $this;
600
	}
601
602
	/**
603
	 * Get the minimum number of entries.
604
	 *
605
	 * @return int $min
606
	 */
607
	public function get_min() {
608
		return $this->values_min;
609
	}
610
611
	/**
612
	 * Set the maximum number of entries.
613
	 *
614
	 * @param int $max
615
	 */
616
	public function set_max( $max ) {
617
		$this->values_max = intval( $max );
618
		return $this;
619
	}
620
621
	/**
622
	 * Get the maximum number of entries.
623
	 *
624
	 * @return int $max
625
	 */
626
	public function get_max() {
627
		return $this->values_max;
628
	}
629
630
	/**
631
	 * Retrieve the groups of this field.
632
	 *
633
	 * @return array
634
	 */
635
	public function get_group_names() {
636
		return array_keys( $this->groups );
637
	}
638
639
	/**
640
	 * Retrieve a group by its name.
641
	 *
642
	 * @param  string $group_name        Group name
643
	 * @return Group_Field $group_object Group object
644
	 */
645
	public function get_group_by_name( $group_name ) {
646
		$group_object = null;
647
648
		foreach ( $this->groups as $group ) {
649
			if ( $group->get_name() == $group_name ) {
650
				$group_object = $group;
651
			}
652
		}
653
654
		return $group_object;
655
	}
656
}
657