Completed
Push — milestone/2_0/react-ui ( 75a435...d33541 )
by
unknown
03:48
created

Container::get_id()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 0
cts 2
cp 0
crap 2
1
<?php
2
3
namespace Carbon_Fields\Container;
4
5
use Carbon_Fields\Carbon_Fields;
6
use Carbon_Fields\Helper\Helper;
7
use Carbon_Fields\Field\Field;
8
use Carbon_Fields\Field\Group_Field;
9
use Carbon_Fields\Container\Fulfillable\Fulfillable_Collection;
10
use Carbon_Fields\Datastore\Datastore_Interface;
11
use Carbon_Fields\Datastore\Datastore_Holder_Interface;
12
use Carbon_Fields\Exception\Incorrect_Syntax_Exception;
13
14
/**
15
 * Base container class.
16
 * Defines the key container methods and their default implementations.
17
 */
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
	 * Title of the container
68
	 *
69
	 * @var string
70
	 */
71
	public $title = '';
72
73
	/**
74
	 * List of notification messages to be displayed on the front-end
75
	 *
76
	 * @var array
77
	 */
78
	protected $notifications = array();
79
80
	/**
81
	 * List of error messages to be displayed on the front-end
82
	 *
83
	 * @var array
84
	 */
85
	protected $errors = array();
86
87
	/**
88
	 * List of container fields
89
	 *
90
	 * @see add_fields()
91
	 * @var array
92
	 */
93
	protected $fields = array();
94
95
	/**
96
	 * Array of custom CSS classes.
97
	 *
98
	 * @see set_classes()
99
	 * @see get_classes()
100
	 * @var array<string>
101
	 */
102
	protected $classes = array();
103
104
	/**
105
	 * Container datastores. Propagated to all container fields
106
	 *
107
	 * @see set_datastore()
108
	 * @see get_datastore()
109
	 * @var object
110
	 */
111
	protected $datastore;
112
113
	/**
114
	 * Flag whether the datastore is the default one or replaced with a custom one
115
	 *
116
	 * @see set_datastore()
117
	 * @see get_datastore()
118
	 * @var boolean
119
	 */
120
	protected $has_default_datastore = true;
121
122
	/**
123
	 * Fulfillable_Collection to use when checking attachment/saving conditions
124
	 *
125
	 * @var Fulfillable_Collection
126
	 */
127
	protected $condition_collection;
128
129
	/**
130
	 * Translator to use when translating conditions to json
131
	 *
132
	 * @var Carbon_Fields\Container\Fulfillable\Translator\Translator
133
	 */
134
	protected $condition_translator;
135
136
	/**
137
	 * Create a new container of type $type and name $name.
138
	 *
139
	 * @param  string $raw_type
140
	 * @param  string $id        Unique id for the container. Optional
141
	 * @param  string $name      Human-readable name of the container
142
	 * @return object $container
143
	 */
144 8
	public static function factory( $raw_type, $id, $name = '' ) {
145
		// no name provided - switch input around as the id is optionally generated based on the name
146 8
		if ( $name === '' ) {
147 8
			$name = $id;
148 8
			$id = '';
149 8
		}
150
151 8
		$type = Helper::normalize_type( $raw_type );
152 8
		$repository = Carbon_Fields::resolve( 'container_repository' );
153 8
		$container = null;
1 ignored issue
show
Unused Code introduced by
$container is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
154
155 8
		if ( $id === '' ) {
156 8
			$id = $repository->get_unique_container_id( $name );
157 8
		}
158
159 8 View Code Duplication
		if ( ! preg_match( '/\A[a-z0-9_]+\z/', $id ) ) {
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...
160
			Incorrect_Syntax_Exception::raise( 'Container IDs can only contain lowercase alphanumeric characters and underscores ("' . $id . '" passed).' );
161
			return null;
162
		}
163
164 8
		if ( ! $repository->is_unique_container_id( $id ) ) {
165
			Incorrect_Syntax_Exception::raise( 'The passed container id is already taken ("' . $id . '" passed).' );
166
			return null;
167
		}
168
169 8
		if ( Carbon_Fields::has( $type, 'containers' ) ) {
170
			$container = Carbon_Fields::resolve_with_arguments( $type, array(
171
				'id' => $id,
172
				'name' => $name,
173
				'type' => $type,
174
			), 'containers' );
175
		} else {
176
			// Fallback to class name-based resolution
177 8
			$class = Helper::type_to_class( $type, __NAMESPACE__, '_Container' );
178
179 8 View Code Duplication
			if ( ! class_exists( $class ) ) {
180 3
				Incorrect_Syntax_Exception::raise( 'Unknown container "' . $raw_type . '".' );
181 1
				$class = __NAMESPACE__ . '\\Broken_Container';
182 1
			}
183
184 6
			$fulfillable_collection = Carbon_Fields::resolve( 'container_condition_fulfillable_collection' );
185 6
			$condition_translator = Carbon_Fields::resolve( 'container_condition_translator_json' );
186 6
			$container = new $class( $id, $name, $type, $fulfillable_collection, $condition_translator );
187
		}
188
189 6
		$repository->register_container( $container );
190
191 6
		return $container;
192
	}
193
194
	/**
195
	 * An alias of factory().
196
	 *
197
	 * @see Container::factory()
198
	 */
199
	public static function make( $type, $name ) {
200
		return static::factory( $type, $name );
201
	}
202
203
	/**
204
	 * Create a new container
205
	 *
206
	 * @param string                 $id                   Unique id of the container
207
	 * @param string                 $title                Title of the container
208
	 * @param string                 $type                 Type of the container
209
	 * @param Fulfillable_Collection $condition_collection
210
	 * @param Carbon_Fields\Container\Fulfillable\Translator\Translator $condition_translator
211
	 */
212 2
	public function __construct( $id, $title, $type, $condition_collection, $condition_translator ) {
213 2
		Carbon_Fields::verify_boot();
214
215 2
		if ( empty( $title ) ) {
216 1
			Incorrect_Syntax_Exception::raise( 'Empty container title is not supported' );
217
		}
218
219 1
		$this->id = $id;
220 1
		$this->title = $title;
221 1
		$this->type = $type;
222 1
		$this->condition_collection = $condition_collection;
223 1
		$this->condition_collection->set_condition_type_list(
224 1
			array_merge( $this->get_condition_types( true ), $this->get_condition_types( false ) ),
225
			true
226 1
		);
227 1
		$this->condition_translator = $condition_translator;
228 1
	}
229
230
	/**
231
	 * Return the container id
232
	 *
233
	 * @return string
234
	 */
235
	public function get_id() {
236
		return $this->id;
237
	}
238
239
	/**
240
	 * Get array of all static condition types
241
	 *
242
	 * @param  boolean       $static
243
	 * @return array<string>
244
	 */
245
	protected function get_condition_types( $static ) {
246
		$group = $static ? 'static' : 'dynamic';
247
		$container_type = Helper::class_to_type( get_class( $this ), '_Container' );
248
249
		$condition_types = array();
250
		$condition_types = apply_filters( 'carbon_fields_' . $container_type . '_container_' . $group . '_condition_types', $condition_types, $container_type, $this );
251
		$condition_types = apply_filters( 'carbon_fields_container_' . $group . '_condition_types', $condition_types, $container_type, $this );
252
253
		return $condition_types;
254
	}
255
256
	/**
257
	 * Return whether the container is active
258
	 */
259
	public function is_active() {
260
		return $this->active;
261
	}
262
263
	/**
264
	 * Activate the container and trigger an action
265
	 */
266
	protected function activate() {
267
		$this->active = true;
268
		$this->boot();
269
		do_action( 'carbon_fields_container_activated', $this );
270
271
		$fields = $this->get_fields();
272
		foreach ( $fields as $field ) {
273
			$field->activate();
274
		}
275
	}
276
277
	/**
278
	 * Perform instance initialization
279
	 */
280
	abstract public function init();
281
282
	/**
283
	 * Boot the container once it's attached.
284
	 */
285
	protected function boot() {
286
		
287
	}
288
289
	/**
290
	 * Load the value for each field in the container.
291
	 * Could be used internally during container rendering
292
	 */
293
	public function load() {
294
		foreach ( $this->fields as $field ) {
295
			$field->load();
296
		}
297
	}
298
299
	/**
300
	 * Called first as part of the container save procedure.
301
	 * Responsible for checking the request validity and
302
	 * calling the container-specific save() method
303
	 *
304
	 * @see save()
305
	 * @see is_valid_save()
306
	 */
307
	public function _save() {
308
		$param = func_get_args();
309
		if ( call_user_func_array( array( $this, '_is_valid_save' ), $param ) ) {
310
			call_user_func_array( array( $this, 'save' ), $param );
311
		}
312
	}
313
314
	/**
315
	 * Load submitted data and save each field in the container
316
	 *
317
	 * @see is_valid_save()
318
	 */
319
	public function save( $data = null ) {
320
		foreach ( $this->fields as $field ) {
321
			$field->set_value_from_input( stripslashes_deep( $_POST ) );
322
			$field->save();
323
		}
324
	}
325
326
	/**
327
	 * Checks whether the current save request is valid
328
	 *
329
	 * @return bool
330
	 */
331
	final protected function _is_valid_save() {
332
		$params = func_get_args();
333
		$is_valid_save = call_user_func_array( array( $this, 'is_valid_save' ), $params );
334
		return apply_filters( 'carbon_fields_container_is_valid_save', $is_valid_save, $this );
335
	}
336
337
	/**
338
	 * Checks whether the current save request is valid
339
	 *
340
	 * @return bool
341
	 */
342
	abstract protected function is_valid_save();
343
344
	/**
345
	 * Called first as part of the container attachment procedure.
346
	 * Responsible for checking it's OK to attach the container
347
	 * and if it is, calling the container-specific attach() method
348
	 *
349
	 * @see attach()
350
	 * @see is_valid_attach()
351
	 */
352
	public function _attach() {
353
		if ( ! $this->is_valid_attach() ) {
354
			return;
355
		}
356
		
357
		$param = func_get_args();
358
		call_user_func_array( array( $this, 'attach' ), $param );
359
360
		// Allow containers to activate but not load (useful in cases such as theme options)
361
		if ( $this->should_activate() ) {
362
			$this->activate();
363
		}
364
	}
365
366
	/**
367
	 * Attach the container rendering and helping methods
368
	 * to concrete WordPress Action hooks
369
	 */
370
	public function attach() {}
371
372
	/**
373
	 * Perform checks whether the container should be attached during the current request
374
	 *
375
	 * @return bool True if the container is allowed to be attached
376
	 */
377
	final public function is_valid_attach() {
378
		$is_valid_attach = $this->is_valid_attach_for_request();
379
		return apply_filters( 'carbon_fields_container_is_valid_attach', $is_valid_attach, $this );
380
	}
381
382
	/**
383
	 * Get environment array for page request (in admin)
384
	 *
385
	 * @return array
386
	 */
387
	abstract protected function get_environment_for_request();
388
389
	/**
390
	 * Check container attachment rules against current page request (in admin)
391
	 *
392
	 * @return bool
393
	 */
394
	abstract protected function is_valid_attach_for_request();
395
396
	/**
397
	 * Check if conditions pass for request
398
	 *
399
	 * @return bool
400
	 */
401
	protected function static_conditions_pass() {
402
		$environment = $this->get_environment_for_request();
403
		$static_condition_collection = $this->condition_collection->evaluate(
404
			$this->get_condition_types( false ),
405
			true
406
		);
407
		return $static_condition_collection->is_fulfilled( $environment );
408
	}
409
410
	/**
411
	 * Get environment array for object id
412
	 *
413
	 * @param integer $object_id
414
	 * @return array
415
	 */
416
	abstract protected function get_environment_for_object( $object_id );
417
418
	/**
419
	 * Check container attachment rules against object id
420
	 *
421
	 * @param int $object_id
422
	 * @return bool
423
	 */
424
	abstract public function is_valid_attach_for_object( $object_id );
425
426
	/**
427
	 * Check if all conditions pass for object
428
	 *
429
	 * @return bool
430
	 */
431
	protected function all_conditions_pass( $object_id ) {
432
		$environment = $this->get_environment_for_object( $object_id );
433
		return $this->condition_collection->is_fulfilled( $environment );
434
	}
435
436
	/**
437
	 * Whether this container is currently viewed.
438
	 */
439
	public function should_activate() {
440
		return $this->is_valid_attach();
441
	}
442
443
	/**
444
	 * Perform a check whether the current container has fields
445
	 *
446
	 * @return bool
447
	 */
448
	public function has_fields() {
449
		return (bool) $this->fields;
450
	}
451
452
	/**
453
	 * Returns the private container array of fields.
454
	 * Use only if you are completely aware of what you are doing.
455
	 *
456
	 * @return array
457
	 */
458
	public function get_fields() {
459
		return $this->fields;
460
	}
461
462
	/**
463
	 * Return root field from container with specified name
464
	 *
465
	 * @example crb_complex
466
	 *
467
	 * @param string $field_name
468
	 * @return Field
469
	 */
470
	public function get_root_field_by_name( $field_name ) {
471
		$fields = $this->get_fields();
472
		foreach ( $fields as $field ) {
473
			if ( $field->get_base_name() === $field_name ) {
474
				return $field;
475
			}
476
		}
477
		return null;
478
	}
479
480
	/**
481
	 * Get a regex to match field name patterns used to fetch specific fields
482
	 *
483
	 * @return string
484
	 */
485
	protected function get_field_pattern_regex() {
486
		// matches:
487
		// field_name
488
		// field_name[0]
489
		// field_name[0]:group_name
490
		// field_name:group_name
491
		$regex = '/
492
			\A
493
			(?P<field_name>[a-z0-9_]+)
494
			(?:\[(?P<group_index>\d+)\])?
495
			(?:' .  preg_quote( static::HIERARCHY_GROUP_SEPARATOR, '/' ). '(?P<group_name>[a-z0-9_]+))?
496
			\z
497
		/x';
498
		return $regex;
499
	}
500
501
	/**
502
	 * Return field from container with specified name
503
	 *
504
	 * @example $field_name = 'crb_complex/text_field'
505
	 * @example $field_name = 'crb_complex/complex_2'
506
	 * @example $field_name = 'crb_complex/complex_2:text_group/text_field'
507
	 * @example $field_name = 'crb_complex[3]/complex_2[1]:text_group/text_field'
508
	 *
509
	 * @param string $field_name
510
	 * @return Field
511
	 */
512
	public function get_field_by_name( $field_name ) {
513
		$hierarchy = array_filter( explode( static::HIERARCHY_FIELD_SEPARATOR, $field_name ) );
514
		$field = null;
515
516
		$field_group = $this->get_fields();
517
		$hierarchy_left = $hierarchy;
518
		$field_pattern_regex = $this->get_field_pattern_regex();
519
		$hierarchy_index = array();
520
521
		while ( ! empty( $hierarchy_left ) ) {
522
			$segment = array_shift( $hierarchy_left );
523
			$segment_pieces = array();
524
			if ( ! preg_match( $field_pattern_regex, $segment, $segment_pieces ) ) {
525
				return null;
526
			}
527
528
			$segment_field_name = $segment_pieces['field_name'];
529
			$segment_group_index = isset( $segment_pieces['group_index'] ) ? $segment_pieces['group_index'] : 0;
530
			$segment_group_name = isset( $segment_pieces['group_name'] ) ? $segment_pieces['group_name'] : Group_Field::DEFAULT_GROUP_NAME;
531
532
			foreach ( $field_group as $f ) {
533
				if ( $f->get_base_name() !== $segment_field_name ) {
534
					continue;
535
				}
536
537
				if ( empty( $hierarchy_left ) ) {
538
					$field = clone $f;
539
					$field->set_hierarchy_index( $hierarchy_index );
540
				} else {
541
					if ( ! is_a( $f, 'Carbon_Fields\\Field\\Complex_Field' ) ) {
542
						return null;
543
					}
544
545
					$group = $f->get_group_by_name( $segment_group_name );
546
					if ( ! $group ) {
547
						return null;
548
					}
549
					$field_group = $group->get_fields();
550
					$hierarchy_index[] = $segment_group_index;
551
				}
552
				break;
553
			}
554
		}
555
556
		return $field;
557
	}
558
559
	/**
560
	 * Perform checks whether there is a field registered with the name $name.
561
	 * If not, the field name is recorded.
562
	 *
563
	 * @param string $name
564
	 * @return boolean
565
	 */
566 View Code Duplication
	protected function register_field_name( $name ) {
0 ignored issues
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...
567
		if ( in_array( $name, $this->registered_field_names ) ) {
568
			Incorrect_Syntax_Exception::raise( 'Field name "' . $name . '" already registered' );
569
			return false;
570
		}
571
572
		$this->registered_field_names[] = $name;
573
		return true;
574
	}
575
576
	/**
577
	 * Return whether the datastore instance is the default one or has been overriden
578
	 *
579
	 * @return boolean
580
	 */
581 6
	public function has_default_datastore() {
582 6
		return $this->has_default_datastore;
583
	}
584
585
	/**
586
	 * Set datastore instance
587
	 *
588
	 * @param Datastore_Interface $datastore
589
	 * @return object $this
590
	 */
591 6 View Code Duplication
	public function set_datastore( Datastore_Interface $datastore, $set_as_default = false ) {
592 6
		if ( $set_as_default && ! $this->has_default_datastore() ) {
593 1
			return $this; // datastore has been overriden with a custom one - abort changing to a default one
594
		}
595 6
		$this->datastore = $datastore;
596 6
		$this->has_default_datastore = $set_as_default;
597
598 6
		foreach ( $this->fields as $field ) {
599
			$field->set_datastore( $this->get_datastore(), true );
600 6
		}
601 6
		return $this;
602
	}
603
604
	/**
605
	 * Get the DataStore instance
606
	 *
607
	 * @return Datastore_Interface $datastore
608
	 */
609 6
	public function get_datastore() {
610 6
		return $this->datastore;
611
	}
612
613
	/**
614
	 * Return WordPress nonce name used to identify the current container instance
615
	 *
616
	 * @return string
617
	 */
618
	protected function get_nonce_name() {
619
		return 'carbon_fields_container_' . $this->id . '_nonce';
620
	}
621
622
	/**
623
	 * Return WordPress nonce name used to identify the current container instance
624
	 *
625
	 * @return string
626
	 */
627
	protected function get_nonce_value() {
628
		return wp_create_nonce( $this->get_nonce_name() );
629
	}
630
631
	/**
632
	 * Check if the nonce is present in the request and that it is verified
633
	 *
634
	 * @return bool
635
	 */
636
	protected function verified_nonce_in_request() {
637
		$input = stripslashes_deep( $_REQUEST );
638
		$nonce_name = $this->get_nonce_name();
639
		$nonce_value = isset( $input[ $nonce_name ] ) ? $input[ $nonce_name ] : '';
640
		return wp_verify_nonce( $nonce_value, $nonce_name );
641
	}
642
643
	/**
644
	 * Internal function that creates the tab and associates it with particular field set
645
	 *
646
	 * @param string $tab_name
647
	 * @param array $fields
648
	 * @param int $queue_end
649
	 * @return object $this
650
	 */
651
	private function create_tab( $tab_name, $fields, $queue_end = self::TABS_TAIL ) {
652
		if ( isset( $this->tabs[ $tab_name ] ) ) {
653
			Incorrect_Syntax_Exception::raise( "Tab name duplication for $tab_name" );
654
		}
655
656
		if ( $queue_end === static::TABS_TAIL ) {
657
			$this->tabs[ $tab_name ] = array();
658
		} else if ( $queue_end === static::TABS_HEAD ) {
659
			$this->tabs = array_merge(
660
				array( $tab_name => array() ),
661
				$this->tabs
662
			);
663
		}
664
665
		foreach ( $fields as $field ) {
666
			$field_name = $field->get_name();
667
			$this->tabs[ $tab_name ][ $field_name ] = $field;
668
		}
669
670
		$this->settings['tabs'] = $this->get_tabs_json();
671
	}
672
673
	/**
674
	 * Whether the container is tabbed or not
675
	 *
676
	 * @return bool
677
	 */
678
	public function is_tabbed() {
679
		return (bool) $this->tabs;
680
	}
681
682
	/**
683
	 * Retrieve all fields that are not defined under a specific tab
684
	 *
685
	 * @return array
686
	 */
687
	protected function get_untabbed_fields() {
688
		$tabbed_fields_names = array();
689
		foreach ( $this->tabs as $tab_fields ) {
690
			$tabbed_fields_names = array_merge( $tabbed_fields_names, array_keys( $tab_fields ) );
691
		}
692
693
		$untabbed_fields = array_filter( $this->fields, function( $field ) use ( $tabbed_fields_names ) {
694
			return ! in_array( $field->get_name(), $tabbed_fields_names );
695
		} );
696
697
		return $untabbed_fields;
698
	}
699
700
	/**
701
	 * Retrieve all tabs.
702
	 * Create a default tab if there are any untabbed fields.
703
	 *
704
	 * @return array
705
	 */
706
	protected function get_tabs() {
707
		$untabbed_fields = $this->get_untabbed_fields();
708
709
		if ( ! empty( $untabbed_fields ) ) {
710
			$this->create_tab( __( 'General', 'carbon-fields' ), $untabbed_fields, static::TABS_HEAD );
711
		}
712
713
		return $this->tabs;
714
	}
715
716
	/**
717
	 * Build the tabs JSON
718
	 *
719
	 * @return array
720
	 */
721
	protected function get_tabs_json() {
722
		$tabs_json = array();
723
		$tabs = $this->get_tabs();
724
725
		foreach ( $tabs as $tab_name => $fields ) {
726
			foreach ( $fields as $field_name => $field ) {
727
				$tabs_json[ $tab_name ][] = $field_name;
728
			}
729
		}
730
731
		return $tabs_json;
732
	}
733
734
	/**
735
	 * Get custom CSS classes.
736
	 *
737
	 * @return array<string>
738
	 */
739
	public function get_classes() {
740
		return $this->classes;
741
	}
742
743
	/**
744
	 * Set CSS classes that the container should use.
745
	 *
746
	 * @param string|array<string> $classes
747
	 * @return object $this
748
	 */
749
	public function set_classes( $classes ) {
750
		$this->classes = Helper::sanitize_classes( $classes );
751
		return $this;
752
	}
753
754
	/**
755
	 * Returns an array that holds the container data, suitable for JSON representation.
756
	 *
757
	 * @param bool $load  Should the value be loaded from the database or use the value from the current instance.
758
	 * @return array
759
	 */
760
	public function to_json( $load ) {
761
		$conditions = $this->condition_collection->evaluate( $this->get_condition_types( true ), $this->get_environment_for_request(), array( 'CUSTOM' ) );
762
		$conditions = $this->condition_translator->fulfillable_to_foreign( $conditions );
763
764
		$container_data = array(
765
			'id' => $this->id,
766
			'type' => $this->type,
767
			'title' => $this->title,
768
			'classes' => $this->get_classes(),
769
			'settings' => $this->settings,
770
			'conditions' => $conditions,
771
			'fields' => array(),
772
			'nonce' => array(
773
				'name' => $this->get_nonce_name(),
774
				'value' => $this->get_nonce_value(),
775
			),
776
		);
777
778
		$fields = $this->get_fields();
779
		foreach ( $fields as $field ) {
780
			$field_data = $field->to_json( $load );
781
			$container_data['fields'][] = $field_data;
782
		}
783
784
		return $container_data;
785
	}
786
787
	/**
788
	 * COMMON USAGE METHODS
789
	 */
790
791
	/**
792
	 * Append array of fields to the current fields set. All items of the array
793
	 * must be instances of Field and their names should be unique for all
794
	 * Carbon containers.
795
	 * If a field does not have DataStore already, the container datastore is
796
	 * assigned to them instead.
797
	 *
798
	 * @param array $fields
799
	 * @return object $this
800
	 */
801
	public function add_fields( $fields ) {
802
		foreach ( $fields as $field ) {
803
			if ( ! is_a( $field, 'Carbon_Fields\\Field\\Field' ) ) {
804
				Incorrect_Syntax_Exception::raise( 'Object must be of type Carbon_Fields\\Field\\Field' );
805
				return $this;
806
			}
807
808
			$unique = $this->register_field_name( $field->get_name() );
809
			if ( ! $unique ) {
810
				return $this;
811
			}
812
813
			$field->set_context( $this->type );
814
			if ( ! $field->get_datastore() ) {
815
				$field->set_datastore( $this->get_datastore(), $this->has_default_datastore() );
816
			}
817
		}
818
819
		$this->fields = array_merge( $this->fields, $fields );
820
821
		return $this;
822
	}
823
824
	/**
825
	 * Configuration function for adding tab with fields
826
	 *
827
	 * @param string $tab_name
828
	 * @param array $fields
829
	 * @return object $this
830
	 */
831
	public function add_tab( $tab_name, $fields ) {
832
		$this->add_fields( $fields );
833
		$this->create_tab( $tab_name, $fields );
834
		return $this;
835
	}
836
837
	/**
838
	 * Proxy function to set attachment conditions
839
	 *
840
	 * @see    Fulfillable_Collection::where()
841
	 * @return Container $this
842
	 */
843
	public function where() {
844
		call_user_func_array( array( $this->condition_collection, 'where' ), func_get_args() );
845
		return $this;
846
	}
847
848
	/**
849
	 * Proxy function to set attachment conditions
850
	 *
851
	 * @see    Fulfillable_Collection::or_where()
852
	 * @return Container $this
853
	 */
854
	public function or_where() {
855
		call_user_func_array( array( $this->condition_collection, 'or_where' ), func_get_args() );
856
		return $this;
857
	}
858
}
859