Completed
Push — development ( 381f0e...33ac70 )
by
unknown
05:34
created

Complex_Field::load_values_from_datastore()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 7
rs 9.4285
c 0
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
	protected $collapsed = false;
30
31
	public $labels = array(
32
		'singular_name' => 'Entry',
33
		'plural_name' => 'Entries',
34
	);
35
36
	/**
37
	 * Initialization tasks.
38
	 */
39
	public function init() {
40
		$this->labels = array(
41
			'singular_name' => __( 'Entry', 'carbon-fields' ),
42
			'plural_name' => __( 'Entries', 'carbon-fields' ),
43
		);
44
45
		// Include the complex group Underscore templates
46
		$this->add_template( 'Complex-Group', array( $this, 'template_group' ) );
47
		$this->add_template( 'Complex-Group-Tab-Item', array( $this, 'template_group_tab_item' ) );
48
49
		parent::init();
50
	}
51
52
	/**
53
	 * Add a set/group of fields.
54
	 *
55
	 * @return $this
56
	 */
57
	public function add_fields() {
58
		$argv = func_get_args();
59
		$argc = count( $argv );
60
61
		if ( $argc == 1 ) {
62
			$fields = $argv[0];
63
			$name = '';
64
			$label = null;
65
		} else if ( $argc == 2 ) {
66 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...
67
				list( $fields, $name ) = $argv;
68
			} else {
69
				list( $name, $fields ) = $argv;
70
			}
71
			$label = null;
72
		} else if ( $argc == 3 ) {
73 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...
74
				list( $fields, $name, $label ) = $argv;
75
			} else {
76
				list( $name, $label, $fields ) = $argv;
77
			}
78
		}
79
80
		if ( array_key_exists( '_' . $name, $this->groups ) ) {
81
			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...
82
		}
83
84
		$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...
85
86
		$this->groups[ $group->get_name() ] = $group;
87
88
		return $this;
89
	}
90
91
	/**
92
	 * Set the group label Underscore template.
93
	 *
94
	 * @param  string|callable $template
95
	 * @return $this
96
	 */
97
	public function set_header_template( $template ) {
98
		if ( count( $this->groups ) === 0 ) {
99
			Incorrect_Syntax_Exception::raise( "Can't set group label template. There are no present groups for Complex Field " . $this->get_label() . '.' );
100
		}
101
102
		$template = is_callable( $template ) ? call_user_func( $template ) : $template;
103
104
		// Assign the template to the group that was added last
105
		$values = array_values( $this->groups );
106
		$group = end( $values );
107
		$group->set_label_template( $template );
108
109
		// Include the group label Underscore template
110
		$this->add_template( $group->get_group_id(), array( $group, 'template_label' ) );
111
112
		$this->groups[ $group->get_name() ] = $group;
113
114
		return $this;
115
	}
116
117
	/**
118
	 * Retrieve all groups of fields.
119
	 *
120
	 * @return array $fields
121
	 */
122
	public function get_fields() {
123
		$fields = array();
124
125
		foreach ( $this->groups as $group ) {
126
			$group_fields = $group->get_fields();
127
128
			$fields = array_merge( $fields, $group_fields );
129
		}
130
131
		return $fields;
132
	}
133
134
	/**
135
	 * Set the field labels.
136
	 * Currently supported values:
137
	 *  - singular_name - the singular entry label
138
	 *  - plural_name - the plural entries label
139
	 *
140
	 * @param  array $labels Labels
141
	 */
142
	public function setup_labels( $labels ) {
143
		$this->labels = array_merge( $this->labels, $labels );
144
		return $this;
145
	}
146
147
	/**
148
	 * Set the datastore of this field.
149
	 *
150
	 * @param Datastore_Interface $datastore
151
	 */
152 View Code Duplication
	public function set_datastore( Datastore_Interface $datastore, $set_as_default = false ) {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in 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...
153
		if ( $set_as_default && !$this->has_default_datastore() ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
154
			return $this; // datastore has been overriden with a custom one - abort changing to a default one
155
		}
156
		$this->datastore = $datastore;
157
		$this->has_default_datastore = $set_as_default;
0 ignored issues
show
Documentation Bug introduced by
It seems like $set_as_default of type boolean is incompatible with the declared type object of property $has_default_datastore.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
158
159
		foreach ( $this->groups as $group ) {
160
			$group->set_datastore( $this->get_datastore(), true );
161
		}
162
		return $this;
163
	}
164
165
	/**
166
	 * Load the field value from an input array based on it's name.
167
	 *
168
	 * @param array $input (optional) Array of field names and values. Defaults to $_POST
169
	 **/
170
	public function set_value_from_input( $input = null ) {
171
		$this->values = array();
172
173
		if ( is_null( $input ) ) {
174
			$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...
175
		}
176
177
		if ( ! isset( $input[ $this->get_name() ] ) ) {
178
			return;
179
		}
180
181
		$input_groups = $input[ $this->get_name() ];
182
		$index = 0;
183
184
		foreach ( $input_groups as $values ) {
185
			if ( ! isset( $values['group'] ) || ! isset( $this->groups[ $values['group'] ] ) ) {
186
				continue;
187
			}
188
189
			$value_group = array( 'type' => $values['group'] );
190
			$group = $this->groups[ $values['group'] ];
191
			unset( $values['group'] );
192
193
			$group_fields = $group->get_fields();
194
195
			// trim input values to those used by the field
196
			$group_field_names = array_flip( $group->get_field_names() );
197
			$values = array_intersect_key( $values, $group_field_names );
198
199
			foreach ( $group_fields as $field ) {
200
				// set value from the group
201
				$tmp_field = clone $field;
202
				if ( is_a( $tmp_field, __NAMESPACE__ . '\\Complex_Field' ) ) {
203
					if ( ! isset( $values[ $tmp_field->get_name() ] ) ) {
204
						continue; // bail if the complex field is empty
205
					}
206
207
					$new_name = $this->get_name() . $group->get_name() . '-' . $field->get_name() . '_' . $index;
208
					$new_values = array( $new_name => $values[ $tmp_field->get_name() ] );
209
210
					$tmp_field->set_name( $new_name );
211
					$tmp_field->set_value_from_input( $new_values );
212
				} else {
213
					$tmp_field->set_value_from_input( $values );
214
				}
215
216
				// update name to group name
217
				$tmp_field->set_name( $this->get_name() . $group->get_name() . '-' . $field->get_name() . '_' . $index );
218
				$value_group[] = $tmp_field;
219
			}
220
221
			$this->values[] = $value_group;
222
			$index++;
223
		}
224
	}
225
226
	/**
227
	 * Load all groups of fields and their data.
228
	 */
229
	public function load() {
230
		// load existing groups
231
		$this->load_values();
232
	}
233
234
	/**
235
	 * Save all contained groups of fields.
236
	 */
237
	public function save() {
238
		$this->delete();
239
240
		foreach ( $this->values as $value ) {
241
			foreach ( $value as $field ) {
242
				if ( !is_a( $field, 'Carbon_Fields\\Field\\Field' ) ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
243
					continue;
244
				}
245
				$field->save();
246
			}
247
		}
248
	}
249
250
	/**
251
	 * Delete the values of all contained fields.
252
	 */
253
	public function delete() {
254
		return $this->get_datastore()->delete_values( $this );
255
	}
256
257
	/**
258
	 * Load and parse the field data.
259
	 */
260
	public function load_values() {
261
		return $this->load_values_from_datastore();
262
	}
263
264
	/**
265
	 * Load and parse the field data from the database.
266
	 */
267
	public function load_values_from_datastore() {
268
		$this->values = array();
269
270
		$group_rows = $this->get_datastore()->load_values( $this );
271
272
		return $this->process_loaded_values( $group_rows );
273
	}
274
275
	/**
276
	 * Load and parse a raw set of field data.
277
	 *
278
	 * @param  array $values Raw data entries
279
	 * @return array 		 Processed data entries
280
	 */
281
	public function load_values_from_array( $values ) {
282
		$this->values = array();
283
284
		$group_rows = array();
285
286
		$meta_key = $this->get_name();
287
288
		foreach ( $values as $key => $value ) {
289
			if ( strpos( $key, $meta_key ) !== 0 ) {
290
				continue;
291
			}
292
293
			$group_rows[] = array(
294
				'field_key' => preg_replace( '~^(' . preg_quote( $this->get_name(), '~' ) . ')_\d+_~', '$1_', $key ),
295
				'field_value' => $value,
296
			);
297
		}
298
299
		return $this->process_loaded_values( $group_rows );
300
	}
301
302
	/**
303
	 * Parse groups of raw field data into the actual field hierarchy.
304
	 *
305
	 * @param  array $group_rows Group rows
306
	 */
307
	public function process_loaded_values( $group_rows ) {
308
		$input_groups = array();
309
310
		// Set default values
311
		$field_names = array();
312
		foreach ( $this->groups as $group ) {
313
			$group_fields = $group->get_fields();
314
			foreach ( $group_fields as $field ) {
315
				$field_names[] = $field->get_name();
316
				$field->set_value( $field->get_default_value() );
317
			}
318
		}
319
320
		if ( empty( $group_rows ) ) {
321
			return;
322
		}
323
324
		// load and parse values and group type
325
		foreach ( $group_rows as $row ) {
326
			if ( ! preg_match( Helper::get_complex_field_regex( $this->get_name(), array_keys( $this->groups ), $field_names ), $row['field_key'], $field_name ) ) {
327
				continue;
328
			}
329
330
			$row['field_value'] = maybe_unserialize( $row['field_value'] );
331
			$input_groups[ $field_name['index'] ]['type'] = $field_name['group'];
332
333
			if ( ! empty( $field_name['trailing'] ) ) {
334
				$input_groups[ $field_name['index'] ][ $field_name['key'] . '_' . $field_name['sub'] . '-' . $field_name['trailing'] ] = $row['field_value'];
335 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...
336
				$input_groups[ $field_name['index'] ][ $field_name['key'] ][ $field_name['sub'] ] = $row['field_value'];
337
			} else {
338
				$input_groups[ $field_name['index'] ][ $field_name['key'] ] = $row['field_value'];
339
			}
340
		}
341
342
		// create groups list with loaded fields
343
		ksort( $input_groups );
344
345
		foreach ( $input_groups as $index => $values ) {
346
			$value_group = array( 'type' => $values['type'] );
347
			$group_fields = $this->groups[ $values['type'] ]->get_fields();
348
			unset( $values['type'] );
349
350
			foreach ( $group_fields as $field ) {
351
				// set value from the group
352
				$tmp_field = clone $field;
353
354
				if ( is_a( $field, __NAMESPACE__ . '\\Complex_Field' ) ) {
355
					$tmp_field->load_values_from_array( $values );
356
				} else {
357
					$tmp_field->set_value_from_input( $values );
358
				}
359
360
				$value_group[] = $tmp_field;
361
			}
362
363
			$this->values[] = $value_group;
364
		}
365
	}
366
367
	/**
368
	 * Retrieve the field values.
369
	 * @return array
370
	 */
371
	public function get_values() {
372
		return $this->values;
373
	}
374
375
	/**
376
	 * Generate and set the field prefix.
377
	 * @param string $prefix
378
	 */
379
	public function set_prefix( $prefix ) {
380
		parent::set_prefix( $prefix );
381
382
		foreach ( $this->groups as $group ) {
383
			$group->set_prefix( $prefix );
384
		}
385
	}
386
387
	/**
388
	 * Returns an array that holds the field data, suitable for JSON representation.
389
	 * This data will be available in the Underscore template and the Backbone Model.
390
	 *
391
	 * @param bool $load  Should the value be loaded from the database or use the value from the current instance.
392
	 * @return array
393
	 */
394
	public function to_json( $load ) {
395
		$complex_data = parent::to_json( $load );
396
397
		$groups_data = array();
398
		$values_data = array();
399
400
		foreach ( $this->groups as $group ) {
401
			$groups_data[] = $group->to_json( false );
402
		}
403
404
		foreach ( $this->values as $fields ) {
405
			$group = $this->get_group_by_name( $fields['type'] );
406
			unset( $fields['type'] );
407
408
			$data = array(
409
				'name' => $group->get_name(),
410
				'label' => $group->get_label(),
411
				'group_id' => $group->get_group_id(),
412
				'fields' => array(),
413
			);
414
415
			foreach ( $fields as $index => $field ) {
416
				$data['fields'][] = $field->to_json( false );
417
			}
418
419
			$values_data[] = $data;
420
		}
421
422
		$complex_data = array_merge( $complex_data, array(
423
			'layout' => $this->layout,
424
			'labels' => $this->labels,
425
			'min' => $this->get_min(),
426
			'max' => $this->get_max(),
427
			'multiple_groups' => count( $groups_data ) > 1,
428
			'groups' => $groups_data,
429
			'value' => $values_data,
430
			'collapsed' => $this->collapsed,
431
		) );
432
433
		return $complex_data;
434
	}
435
436
	/**
437
	 * The main Underscore template.
438
	 */
439
	public function template() {
440
		?>
441
		<div class="carbon-subcontainer carbon-grid {{ multiple_groups ? 'multiple-groups' : '' }}">
442
			<div class="carbon-empty-row carbon-empty-row-visible">
443
				{{{ crbl10n.complex_no_rows.replace('%s', labels.plural_name) }}}
444
			</div>
445
446
			<div class="groups-wrapper layout-{{ layout }}">
447
				<# 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...
448
					<div class="group-tabs-nav-holder">
449
						<ul class="group-tabs-nav"></ul>
450
451
						<div class="carbon-actions">
452
							<div class="carbon-button">
453
								<a href="#" class="button" data-group="{{{ multiple_groups ? '' : groups[0].name }}}">
454
									+
455
								</a>
456
457
								<# if (multiple_groups) { #>
458
									<ul>
459
										<# _.each(groups, function(group) { #>
460
											<li><a href="#" data-group="{{{ group.name }}}">{{{ group.label }}}</a></li>
461
										<# }); #>
462
									</ul>
463
								<# } #>
464
							</div>
465
						</div>
466
					</div><!-- /.group-tabs-nav-holder -->
467
				<# } #>
468
469
				<div class="carbon-groups-holder"></div>
470
				<div class="clear"></div>
471
			</div>
472
473
			<div class="carbon-actions">
474
				<div class="carbon-button">
475
					<a href="#" class="button" data-group="{{{ multiple_groups ? '' : groups[0].name }}}">
476
						{{{ crbl10n.complex_add_button.replace('%s', labels.singular_name) }}}
477
					</a>
478
479
					<# if (multiple_groups) { #>
480
						<ul>
481
							<# _.each(groups, function(group) { #>
482
								<li><a href="#" data-group="{{{ group.name }}}">{{{ group.label }}}</a></li>
483
							<# }); #>
484
						</ul>
485
					<# } #>
486
				</div>
487
			</div>
488
		</div>
489
		<?php
490
	}
491
492
	/**
493
	 * The Underscore template for the complex field group.
494
	 */
495
	public function template_group() {
496
		?>
497
		<div id="carbon-{{{ complex_name }}}-complex-container" class="carbon-row carbon-group-row" data-group-id="{{ id }}">
498
			<input type="hidden" name="{{{ complex_name + '[' + index + ']' }}}[group]" value="{{ name }}" />
499
500
			<div class="carbon-drag-handle">
501
				<span class="group-number">{{{ order + 1 }}}</span><span class="group-name">{{{ label_template || label }}}</span>
502
			</div>
503
504
			<div class="carbon-group-actions carbon-group-actions-{{ layout }}">
505
				<a class="carbon-btn-duplicate dashicons-before dashicons-admin-page" href="#" title="<?php esc_attr_e( 'Clone', 'carbon-fields' ); ?>">
506
					<?php _e( 'Clone', 'carbon-fields' ); ?>
507
				</a>
508
509
				<a class="carbon-btn-remove dashicons-before dashicons-trash" href="#" title="<?php esc_attr_e( 'Remove', 'carbon-fields' ); ?>">
510
					<?php _e( 'Remove', 'carbon-fields' ); ?>
511
				</a>
512
513
				<a class="carbon-btn-collapse dashicons-before dashicons-arrow-up" href="#" title="<?php esc_attr_e( 'Collapse/Expand', 'carbon-fields' ); ?>">
514
					<?php _e( 'Collapse/Expand', 'carbon-fields' ); ?>
515
				</a>
516
			</div>
517
518
			<div class="fields-container">
519
				<# _.each(fields, function(field) { #>
520
					<div class="carbon-row carbon-subrow subrow-{{{ field.type }}} {{{ field.classes.join(' ') }}}">
521
						<label for="{{{ complex_id + '-' + field.id + '-' + index }}}">
522
							{{ field.label }}
523
524
							<# if (field.required) { #>
525
								 <span class="carbon-required">*</span>
526
							<# } #>
527
						</label>
528
529
						<div class="field-holder {{{ complex_id + '-' + field.id + '-' + index }}}"></div>
530
531
						<# if (field.help_text) { #>
532
							<em class="help-text">
533
								{{{ field.help_text }}}
534
							</em>
535
						<# } #>
536
537
						<em class="carbon-error"></em>
538
					</div>
539
				<# }) #>
540
			</div>
541
		</div>
542
		<?php
543
	}
544
545
	 /**
546
	 * The Underscore template for the group item tab.
547
	 */
548
	public function template_group_tab_item() {
549
		?>
550
		<li class="group-tab-item" data-group-id="{{ id }}">
551
			<a href="#">
552
				<span class="group-handle"></span>
553
554
				<# if (label_template || label) { #>
555
					<span class="group-name">{{{ label_template || label }}}</span>
556
				<# } #>
557
				<span class="group-number">{{{ order + 1 }}}</span>
558
				<span class="dashicons dashicons-warning carbon-complex-group-error-badge" ></span>
559
			</a>
560
		</li>
561
		<?php
562
	}
563
564
	/**
565
	 * Modify the layout of this field.
566
	 *
567
	 * @param string $layout
568
	 */
569
	public function set_layout( $layout ) {
570
		$available_layouts = array(
571
			self::LAYOUT_GRID,
572
			self::LAYOUT_TABBED_HORIZONTAL,
573
			self::LAYOUT_TABBED_VERTICAL,
574
			self::LAYOUT_LIST,
575
		);
576
577
		if ( $layout === self::LAYOUT_TABBED ) {
578
			// The library used to provide just one kind of tabs -- horizontal ones. Later vertical tabs were added.
579
			// So the "tabbed" name was renamed to "tabbed-horizontal" and "tabbed-vertical" layout was introduced.
580
			_doing_it_wrong( __METHOD__, sprintf( __( 'Complex field "%1$s" layout is deprecated, please use "%2$s" or "%3$s" instead.', 'carbon-fields' ), self::LAYOUT_TABBED, self::LAYOUT_TABBED_HORIZONTAL, self::LAYOUT_TABBED_VERTICAL ), null );
581
582
			$layout = self::LAYOUT_TABBED_HORIZONTAL;
583
		}
584
585
		if ( ! in_array( $layout,  $available_layouts ) ) {
586
			$error_message = 'Incorrect layout ``' . $layout . '" specified. ' .
587
				'Available layouts: ' . implode( ', ', $available_layouts );
588
589
			Incorrect_Syntax_Exception::raise( $error_message );
590
		}
591
592
		if ( $layout === self::LAYOUT_LIST ) {
593
			_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...
594
		}
595
596
		$this->layout = $layout;
597
598
		return $this;
599
	}
600
601
	/**
602
	 * Set the minimum number of entries.
603
	 *
604
	 * @param int $min
605
	 */
606
	public function set_min( $min ) {
607
		$this->values_min = intval( $min );
608
		return $this;
609
	}
610
611
	/**
612
	 * Get the minimum number of entries.
613
	 *
614
	 * @return int $min
615
	 */
616
	public function get_min() {
617
		return $this->values_min;
618
	}
619
620
	/**
621
	 * Set the maximum number of entries.
622
	 *
623
	 * @param int $max
624
	 */
625
	public function set_max( $max ) {
626
		$this->values_max = intval( $max );
627
		return $this;
628
	}
629
630
	/**
631
	 * Get the maximum number of entries.
632
	 *
633
	 * @return int $max
634
	 */
635
	public function get_max() {
636
		return $this->values_max;
637
	}
638
639
	/**
640
	 * Change the groups initial collapse state.
641
	 * This state relates to the state of which the groups are rendered.
642
	 *
643
	 * @param bool $collapsed
644
	 */
645
	public function set_collapsed( $collapsed = true ) {
646
		$this->collapsed = $collapsed;
647
648
		return $this;
649
	}
650
651
	/**
652
	 * Retrieve the groups of this field.
653
	 *
654
	 * @return array
655
	 */
656
	public function get_group_names() {
657
		return array_keys( $this->groups );
658
	}
659
660
	/**
661
	 * Retrieve a group by its name.
662
	 *
663
	 * @param  string $group_name        Group name
664
	 * @return Group_Field $group_object Group object
665
	 */
666
	public function get_group_by_name( $group_name ) {
667
		$group_object = null;
668
669
		foreach ( $this->groups as $group ) {
670
			if ( $group->get_name() == $group_name ) {
671
				$group_object = $group;
672
			}
673
		}
674
675
		return $group_object;
676
	}
677
}
678