Completed
Push — milestone/2.0 ( 9939d7...e0608a )
by
unknown
03:03
created

Field::get_conditional_logic()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

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 2
cts 2
cp 1
crap 1
1
<?php
2
3
namespace Carbon_Fields\Field;
4
5
use Carbon_Fields\App;
6
use Carbon_Fields\Datastore\Datastore_Interface;
7
use Carbon_Fields\Datastore\Datastore_Holder_Interface;
8
use Carbon_Fields\Value_Set\Value_Set;
9
use Carbon_Fields\Helper\Helper;
10
use Carbon_Fields\Exception\Incorrect_Syntax_Exception;
11
12
/**
13
 * Base field class.
14
 * Defines the key container methods and their default implementations.
15
 * Implements factory design pattern.
16
 **/
17
class Field implements Datastore_Holder_Interface {
18
	/**
19
	 * Stores all the field Backbone templates
20
	 *
21
	 * @see factory()
22
	 * @see add_template()
23
	 * @var array
24
	 */
25
	protected $templates = array();
26
27
	/**
28
	 * Globally unique field identificator. Generated randomly
29
	 *
30
	 * @var string
31
	 */
32
	protected $id;
33
34
	/**
35
	 * Stores the initial <kbd>$type</kbd> variable passed to the <code>factory()</code> method
36
	 *
37
	 * @see factory
38
	 * @var string
39
	 */
40
	public $type;
41
42
	/**
43
	 * Array of ancestor field names
44
	 *
45
	 * @var array
46
	 **/
47
	protected $hierarchy = array();
48
49
	/**
50
	 * Array of complex entry ids
51
	 *
52
	 * @var array
53
	 **/
54
	protected $hierarchy_index = array();
55
56
	/**
57
	 * Field value
58
	 *
59
	 * @var Value_Set
60
	 */
61
	protected $value_set;
62
63
	/**
64
	 * Default field value
65
	 *
66
	 * @var mixed
67
	 */
68
	protected $default_value;
69
70
	/**
71
	 * Sanitized field name used as input name attribute during field render
72
	 *
73
	 * @see factory()
74
	 * @see set_name()
75
	 * @var string
76
	 */
77
	protected $name;
78
79
	/**
80
	 * Field name prefix
81
	 *
82
	 * @see set_name()
83
	 * @var string
84
	 */
85
	protected $name_prefix = '_';
86
87
	/**
88
	 * The base field name which is used in the container.
89
	 *
90
	 * @see set_base_name()
91
	 * @var string
92
	 */
93
	protected $base_name;
94
95
	/**
96
	 * Field name used as label during field render
97
	 *
98
	 * @see factory()
99
	 * @see set_label()
100
	 * @var string
101
	 */
102
	protected $label;
103
104
	/**
105
	 * Additional text containing information and guidance for the user
106
	 *
107
	 * @see help_text()
108
	 * @var string
109
	 */
110
	protected $help_text;
111
112
	/**
113
	 * Field DataStore instance to which save, load and delete calls are delegated
114
	 *
115
	 * @see set_datastore()
116
	 * @see get_datastore()
117
	 * @var Datastore_Interface
118
	 */
119
	protected $datastore;
120
121
	/**
122
	 * Flag whether the datastore is the default one or replaced with a custom one
123
	 *
124
	 * @see set_datastore()
125
	 * @see get_datastore()
126
	 * @var boolean
127
	 */
128
	protected $has_default_datastore = true;
129
130
	/**
131
	 * The type of the container this field is in
132
	 *
133
	 * @see get_context()
134
	 * @var string
135
	 */
136
	protected $context;
137
138
	/**
139
	 * Whether or not this value should be auto loaded. Applicable to theme options only.
140
	 *
141
	 * @see set_autoload()
142
	 * @var bool
143
	 **/
144
	protected $autoload = false;
145
146
	/**
147
	 * Whether or not this field will be initialized when the field is in the viewport (visible).
148
	 *
149
	 * @see set_lazyload()
150
	 * @var bool
151
	 **/
152
	protected $lazyload = false;
153
154
	/**
155
	 * The width of the field.
156
	 *
157
	 * @see set_width()
158
	 * @var int
159
	 **/
160
	protected $width = 0;
161
162
	/**
163
	 * Custom CSS classes.
164
	 *
165
	 * @see add_class()
166
	 * @var array
167
	 **/
168
	protected $classes = array();
169
170
	/**
171
	 * Whether or not this field is required.
172
	 *
173
	 * @see set_required()
174
	 * @var bool
175
	 **/
176
	protected $required = false;
177
178
	/**
179
	 * Stores the field conditional logic rules.
180
	 *
181
	 * @var array
182
	 **/
183
	protected $conditional_logic = array();
184
185
	/**
186
	 * Whether the field should be included in the response of the requests to the REST API
187
	 *
188
	 * @see  set_visible_in_rest_api
189
	 * @see  get_visible_in_rest_api
190
	 * @var boolean
191
	 */
192
	protected $visible_in_rest_api = false;
193
194
	/**
195
	 * Clone the Value_Set object as well
196
	 *
197
	 * @var array
198
	 **/
199
	public function __clone() {
200
		$this->set_value_set( clone $this->get_value_set() );
201
	}
202
203
	/**
204
	 * Create a new field of type $type and name $name and label $label.
205
	 *
206
	 * @param string $type
207
	 * @param string $name lower case and underscore-delimited
208
	 * @param string $label (optional) Automatically generated from $name if not present
209
	 * @return Field
210
	 **/
211 14
	public static function factory( $type, $name, $label = null ) {
212 14
		$type = str_replace( ' ', '_', ucwords( str_replace( '_', ' ', $type ) ) );
213
214 14
		$class = __NAMESPACE__ . '\\' . $type . '_Field';
215
216 14 View Code Duplication
		if ( ! class_exists( $class ) ) {
217 4
			Incorrect_Syntax_Exception::raise( 'Unknown field "' . $type . '".' );
218 1
			$class = __NAMESPACE__ . '\\Broken_Field';
219 1
		}
220
221 11
		$field = new $class( $type, $name, $label );
222
223 7
		return $field;
224
	}
225
226
	/**
227
	 * An alias of factory().
228
	 *
229
	 * @see Field::factory()
230
	 * @return Field
231
	 **/
232 14
	public static function make( $type, $name, $label = null ) {
233 14
		return static::factory( $type, $name, $label );
234
	}
235
236
	/**
237
	 * Create a field from a certain type with the specified label.
238
	 * 
239
	 * @param string $type  Field type
240
	 * @param string $name  Field name
241
	 * @param string $label Field label
242
	 */
243 11
	protected function __construct( $type, $name, $label ) {
244 11
		App::verify_boot();
245
		
246 11
		$this->type = $type;
247 11
		$this->set_base_name( $name );
248 11
		$this->set_name( $name );
249 7
		$this->set_label( $label );
250
251
		// Pick random ID
252 7
		$random_string = md5( mt_rand() . $this->get_name() . $this->get_label() );
253 7
		$random_string = substr( $random_string, 0, 5 ); // 5 chars should be enough
254 7
		$this->id = 'carbon-' . $random_string;
255
256 7
		$this->init();
257 7
	}
258
259
	/**
260
	 * Activate the field once the container is attached.
261
	 */
262
	public function activate() {
263
		$this->admin_init();
264
		$this->add_template( $this->get_type(), array( $this, 'template' ) );
265
266
		add_action( 'admin_footer', array( get_class(), 'admin_hook_scripts' ), 5 );
267
		add_action( 'admin_footer', array( get_class(), 'admin_hook_styles' ), 5 );
268
		add_action( 'admin_footer', array( get_class( $this ), 'admin_enqueue_scripts' ), 5 );
269
270
		do_action( 'crb_field_activated', $this );
271
	}
272
273
	/**
274
	 * Set array of hierarchy field names
275
	 *
276
	 * @return array
277
	 **/
278
	public function set_hierarchy( $hierarchy ) {
279
		$this->hierarchy = $hierarchy;
280
	}
281
282
	/**
283
	 * Get array of hierarchy field names
284
	 *
285
	 * @return array
286
	 **/
287
	public function get_hierarchy() {
288
		return $this->hierarchy;
289
	}
290
291
	/**
292
	 * Set array of hierarchy indexes
293
	 *
294
	 * @return array
295
	 **/
296
	public function set_hierarchy_index( $hierarchy_index ) {
297
		$this->hierarchy_index = $hierarchy_index;
298
	}
299
300
	/**
301
	 * Get array of hierarchy indexes
302
	 *
303
	 * @return array
304
	 **/
305
	public function get_hierarchy_index() {
306
		return $this->hierarchy_index;
307
	}
308
309
	/**
310
	 * Return whether the field is a root field and holds a single value
311
	 *
312
	 * @return bool
313
	 **/
314 3
	public function is_simple_root_field() {
315 3
		$hierarchy = $this->get_hierarchy();
316
		return (
317 3
			empty( $hierarchy )
318 3
			&&
319
			(
320 2
				$this->get_value_set()->get_type() === Value_Set::TYPE_SINGLE_VALUE
321 2
				||
322 2
				$this->get_value_set()->get_type() === Value_Set::TYPE_MULTIPLE_PROPERTIES
323 2
			)
324 3
		);
325
	}
326
327
	/**
328
	 * Perform instance initialization
329
	 **/
330
	public function init() {}
331
332
	/**
333
	 * Instance initialization when in the admin area.
334
	 * Called during field boot.
335
	 **/
336
	public function admin_init() {}
337
338
	/**
339
	 * Enqueue admin scripts.
340
	 * Called once per field type.
341
	 **/
342
	public static function admin_enqueue_scripts() {}
343
344
	/**
345
	 * Prints the main Underscore template
346
	 **/
347
	public function template() { }
348
349
	/**
350
	 * Returns all the Backbone templates
351
	 *
352
	 * @return array
353
	 **/
354
	public function get_templates() {
355
		return $this->templates;
356
	}
357
358
	/**
359
	 * Adds a new Backbone template
360
	 **/
361
	protected function add_template( $name, $callback ) {
362
		$this->templates[ $name ] = $callback;
363
	}
364
365
	/**
366
	 * Get value from datastore
367
	 *
368
	 * @param bool $fallback_to_default
369
	 * @return mixed
370
	 **/
371
	protected function get_value_from_datastore( $fallback_to_default = true ) {
372
		$raw_value_set_tree = $this->get_datastore()->load( $this );
373
		
374
		$value = null;
375
		if ( isset( $raw_value_set_tree[ $this->get_base_name() ] ) ) {
376
			$value = $raw_value_set_tree[ $this->get_base_name() ]['value_set'];
377
		}
378
379
		if ( $value === null && $fallback_to_default ) {
380
			$value = $this->get_default_value();
381
		}
382
383
		return $value;
384
	}
385
386
	/**
387
	 * Load value from datastore
388
	 **/
389 2
	public function load() {
390 2
		$value = $this->get_value_from_datastore();
391 2
		$this->set_value( $value );
392 2
	}
393
394
	/**
395
	 * Save value to storage
396
	 **/
397 5
	public function save() {
398 5
		if ( ! in_array( $this->get_value_set()->get_type(), array( Value_Set::TYPE_SINGLE_VALUE, Value_Set::TYPE_MULTIPLE_PROPERTIES ) ) ) {
399 2
			$this->delete();
400 2
		}
401 5
		return $this->get_datastore()->save( $this );
402
	}
403
404
	/**
405
	 * Delete value from storage
406
	 */
407 1
	public function delete() {
408 1
		$this->get_datastore()->delete( $this );
409 1
	}
410
411
	/**
412
	 * Load the field value from an input array based on it's name
413
	 *
414
	 * @param array $input Array of field names and values.
415
	 **/
416 2
	public function set_value_from_input( $input ) {
417 2
		if ( isset( $input[ $this->get_name() ] ) ) {
418 1
			$this->set_value( $input[ $this->get_name() ] );
419 1
		} else {
420 1
			$this->set_value( array() );
421
		}
422 2
	}
423
424
	/**
425
	 * Return whether the datastore instance is the default one or has been overriden
426
	 *
427
	 * @return boolean
428
	 **/
429
	public function has_default_datastore() {
430
		return $this->has_default_datastore;
431
	}
432
433
	/**
434
	 * Set datastore instance
435
	 *
436
	 * @param Datastore_Interface $datastore
437
	 * @return object $this
438
	 **/
439 1
	public function set_datastore( Datastore_Interface $datastore, $set_as_default = false ) {
440 1
		if ( $set_as_default && ! $this->has_default_datastore() ) {
441
			return $this; // datastore has been overriden with a custom one - abort changing to a default one
442
		}
443 1
		$this->datastore = $datastore;
444 1
		$this->has_default_datastore = $set_as_default;
445 1
		return $this;
446
	}
447
448
	/**
449
	 * Get the DataStore instance
450
	 *
451
	 * @return Datastore_Interface $datastore
452
	 **/
453 1
	public function get_datastore() {
454 1
		return $this->datastore;
455
	}
456
457
	/**
458
	 * Assign the type of the container this field is in
459
	 *
460
	 * @param string
461
	 * @return object $this
462
	 **/
463
	public function set_context( $context ) {
464
		$this->context = $context;
465
		return $this;
466
	}
467
468
	/**
469
	 * Return the type of the container this field is in
470
	 *
471
	 * @return string
472
	 **/
473
	public function get_context() {
474
		return $this->context;
475
	}
476
477
	/**
478
	 * Get the Value_Set object
479
	 *
480
	 * @return Value_Set
481
	 **/
482 2
	public function get_value_set() {
483 2
		if ( $this->value_set === null ) {
484 1
			$this->set_value_set( new Value_Set() );
485 1
		}
486 2
		return $this->value_set;
487
	}
488
489
	/**
490
	 * Set the Value_Set object
491
	 *
492
	 * @param Value_Set $value_set
493
	 **/
494 1
	public function set_value_set( $value_set ) {
495 1
		$this->value_set = $value_set;
496 1
	}
497
498
	/**
499
	 * Alias for $this->get_value_set()->get();
500
	 *
501
	 * @return mixed
502
	 **/
503 3
	public function get_value() {
504 3
		return $this->get_value_set()->get();
505
	}
506
507
	/**
508
	 * Return a differently formatted value for end-users
509
	 *
510
	 * @return mixed
511
	 **/
512 2
	public function get_formatted_value() {
513 2
		$value = $this->get_value();
514 2
		if ( $value === null ) {
515 1
			$value = $this->get_default_value();
516 1
		}
517 2
		return $value;
518
	}
519
520
	/**
521
	 * Alias for $this->get_value_set()->set( $value );
522
	 **/
523 1
	public function set_value( $value ) {
524 1
		$this->get_value_set()->set( $value );
525 1
	}
526
527
	/**
528
	 * Set default field value
529
	 *
530
	 * @param mixed $default_value
531
	 **/
532 1
	public function set_default_value( $default_value ) {
533 1
		$this->default_value = $default_value;
534 1
		return $this;
535
	}
536
537
	/**
538
	 * Get default field value
539
	 *
540
	 * @return mixed
541
	 **/
542 1
	public function get_default_value() {
543 1
		return $this->default_value;
544
	}
545
546
	/**
547
	 * Set field name.
548
	 * Use only if you are completely aware of what you are doing.
549
	 *
550
	 * @param string $name Field name, either sanitized or not
551
	 **/
552 6
	public function set_name( $name ) {
553 6
		if ( empty( $name ) ) {
554 1
			Incorrect_Syntax_Exception::raise( 'Field name can\'t be empty' );
555
		}
556
557 5
		$regex = '/\A[a-z0-9_\-\[\]]+\z/'; // symbols ]-[ are supported in a hidden way - required for widgets to work (WP imposes dashes and square brackets on field names)
558 5
		if ( ! preg_match( $regex, $name ) ) {
559 3
			Incorrect_Syntax_Exception::raise( 'Field name can only contain lowercase alphanumeric characters and underscores.' );
560
		}
561
562 2
		$name_prefix = $this->get_name_prefix();
563 2
		$name = ( substr( $name, 0, strlen( $name_prefix ) ) !== $name_prefix ? $name_prefix . $name : $name );
564
565 2
		$this->name = $name;
566 2
	}
567
568
	/**
569
	 * Return the field name
570
	 *
571
	 * @return string
572
	 **/
573 2
	public function get_name() {
574 2
		return $this->name;
575
	}
576
577
	/**
578
	 * Set field name prefix
579
	 * Use only if you are completely aware of what you are doing.
580
	 *
581
	 * @param string $name_prefix
582
	 **/
583 3
	public function set_name_prefix( $name_prefix ) {
584 3
		$name_prefix = strval( $name_prefix );
585 3
		$old_prefix_length = strlen( $this->name_prefix );
586 3
		$this->name_prefix = '';
587 3
		$this->set_name( substr( $this->get_name(), $old_prefix_length ) );
588
589 3
		$this->name_prefix = $name_prefix;
590 3
		$this->set_name( $this->name_prefix . $this->get_name() );
591 3
	}
592
593
	/**
594
	 * Return the field name prefix
595
	 *
596
	 * @return string
597
	 **/
598 3
	public function get_name_prefix() {
599 3
		return $this->name_prefix;
600
	}
601
602
	/**
603
	 * Set field base name as defined in the container.
604
	 **/
605
	public function set_base_name( $name ) {
606
		$this->base_name = $name;
607
	}
608
609
	/**
610
	 * Return the field base name.
611
	 *
612
	 * @return string
613
	 **/
614
	public function get_base_name() {
615
		return $this->base_name;
616
	}
617
618
	/**
619
	 * Set field label.
620
	 *
621
	 * @param string $label If null, the label will be generated from the field name
622
	 **/
623 View Code Duplication
	public function set_label( $label ) {
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...
624
		// Try to guess field label from it's name
625
		if ( is_null( $label ) ) {
626
			// remove the leading underscore(if it's there)
627
			$label = preg_replace( '~^_~', '', $this->name );
628
629
			// remove the leading "crb_"(if it's there)
630
			$label = preg_replace( '~^crb_~', '', $label );
631
632
			// split the name into words and make them capitalized
633
			$label = mb_convert_case( str_replace( '_', ' ', $label ), MB_CASE_TITLE );
634
		}
635
636
		$this->label = $label;
637
	}
638
639
	/**
640
	 * Return field label.
641
	 *
642
	 * @return string
643
	 **/
644
	public function get_label() {
645
		return $this->label;
646
	}
647
648
	/**
649
	 * Set additional text to be displayed during field render,
650
	 * containing information and guidance for the user
651
	 *
652
	 * @return object $this
653
	 **/
654
	public function set_help_text( $help_text ) {
655
		$this->help_text = $help_text;
656
		return $this;
657
	}
658
659
	/**
660
	 * Alias for set_help_text()
661
	 *
662
	 * @see set_help_text()
663
	 * @return object $this
664
	 **/
665
	public function help_text( $help_text ) {
666
		return $this->set_help_text( $help_text );
667
	}
668
669
	/**
670
	 * Return the field help text
671
	 *
672
	 * @return object $this
673
	 **/
674
	public function get_help_text() {
675
		return $this->help_text;
676
	}
677
678
	/**
679
	 * Whether or not this value should be auto loaded. Applicable to theme options only.
680
	 *
681
	 * @param bool $autoload
682
	 * @return object $this
683
	 **/
684
	public function set_autoload( $autoload ) {
685
		$this->autoload = $autoload;
686
		return $this;
687
	}
688
689
	/**
690
	 * Return whether or not this value should be auto loaded.
691
	 *
692
	 * @return bool
693
	 **/
694
	public function get_autoload() {
695
		return $this->autoload;
696
	}
697
698
	/**
699
	 * Whether or not this field will be initialized when the field is in the viewport (visible).
700
	 *
701
	 * @param bool $lazyload
702
	 * @return object $this
703
	 **/
704
	public function set_lazyload( $lazyload ) {
705
		$this->lazyload = $lazyload;
706
		return $this;
707
	}
708
709
	/**
710
	 * Return whether or not this field should be lazyloaded.
711
	 *
712
	 * @return bool
713
	 **/
714
	public function get_lazyload() {
715
		return $this->lazyload;
716
	}
717
718
	/**
719
	 * Set the field width.
720
	 *
721
	 * @param int $width
722
	 * @return object $this
723
	 **/
724
	public function set_width( $width ) {
725
		$this->width = (int) $width;
726
		return $this;
727
	}
728
729
	/**
730
	 * Get the field width.
731
	 *
732
	 * @return int $width
733
	 **/
734
	public function get_width() {
735
		return $this->width;
736
	}
737
738
	/**
739
	 *  Add custom CSS class to the field html container.
740
	 *
741
	 * @param string|array $classes
742
	 * @return object $this
743
	 **/
744
	public function add_class( $classes ) {
745
		if ( ! is_array( $classes ) ) {
746
			$classes = array_values( array_filter( explode( ' ', $classes ) ) );
747
		}
748
749
		$this->classes = array_map( 'sanitize_html_class', $classes );
750
		return $this;
751
	}
752
753
	/**
754
	 * Get the field custom CSS classes.
755
	 *
756
	 * @return array
757
	 **/
758
	public function get_classes() {
759
		return $this->classes;
760
	}
761
762
	/**
763
	 * Whether this field is mandatory for the user
764
	 *
765
	 * @param bool $required
766
	 * @return object $this
767
	 **/
768
	public function set_required( $required = true ) {
769
		$this->required = $required;
770
		return $this;
771
	}
772
773
	/**
774
	 * HTML id attribute getter.
775
	 * @return string
776
	 */
777 1
	public function get_id() {
778 1
		return $this->id;
779
	}
780
781
	/**
782
	 * HTML id attribute setter
783
	 * @param string $id
784
	 */
785 1
	public function set_id( $id ) {
786 1
		$this->id = $id;
787 1
	}
788
789
	/**
790
	 * Return whether this field is mandatory for the user
791
	 *
792
	 * @return bool
793
	 **/
794
	public function is_required() {
795
		return $this->required;
796
	}
797
798
	/**
799
	 * Returns the type of the field based on the class.
800
	 * The class is stripped by the "CarbonFields" prefix.
801
	 * Also the "Field" suffix is removed.
802
	 * Then underscores and backslashes are removed.
803
	 *
804
	 * @return string
805
	 */
806
	public function get_type() {
807
		$class = get_class( $this );
808
809
		return $this->clean_type( $class );
810
	}
811
812
	/**
813
	 * Cleans up an object class for usage as HTML class
814
	 *
815
	 * @param string $type
816
	 * @return string
817
	 */
818
	protected function clean_type( $type ) {
819
		$remove = array(
820
			'_',
821
			'\\',
822
			'CarbonFields',
823
			'Field',
824
		);
825
		$clean_class = str_replace( $remove, '', $type );
826
827
		return $clean_class;
828
	}
829
830
	/**
831
	 * Returns an array that holds the field data, suitable for JSON representation.
832
	 * This data will be available in the Underscore template and the Backbone Model.
833
	 *
834
	 * @param bool $load  Should the value be loaded from the database or use the value from the current instance.
835
	 * @return array
836
	 */
837
	public function to_json( $load ) {
838
		if ( $load ) {
839
			$this->load();
840
		}
841
842
		$field_data = array(
843
			'id' => $this->get_id(),
844
			'type' => $this->get_type(),
845
			'label' => $this->get_label(),
846
			'name' => $this->get_name(),
847
			'base_name' => $this->get_base_name(),
848
			'value' => $this->get_value(),
849
			'default_value' => $this->get_default_value(),
850
			'help_text' => $this->get_help_text(),
851
			'context' => $this->get_context(),
852
			'required' => $this->is_required(),
853
			'lazyload' => $this->get_lazyload(),
854
			'width' => $this->get_width(),
855
			'classes' => $this->get_classes(),
856
			'conditional_logic' => $this->get_conditional_logic(),
857
		);
858
859
		return $field_data;
860
	}
861
862
	/**
863
	 * Set the field visibility conditional logic.
864
	 *
865
	 * @param array
866
	 */
867 8
	public function set_conditional_logic( $rules ) {
868 8
		$this->conditional_logic = $this->parse_conditional_rules( $rules );
869
870 3
		return $this;
871
	}
872
873
	/**
874
	 * Get the conditional logic rules
875
	 *
876
	 * @return array
877
	 */
878 3
	public function get_conditional_logic() {
879 3
		return $this->conditional_logic;
880
	}
881
882
	/**
883
	 * Validate and parse the conditional logic rules.
884
	 *
885
	 * @param array $rules
886
	 * @return array
887
	 */
888
	protected function parse_conditional_rules( $rules ) {
889
		if ( ! is_array( $rules ) ) {
890
			Incorrect_Syntax_Exception::raise( 'Conditional logic rules argument should be an array.' );
891
		}
892
893
		$allowed_operators = array( '=', '!=', '>', '>=', '<', '<=', 'IN', 'NOT IN' );
894
895
		$parsed_rules = array(
896
			'relation' => Helper::get_relation_type_from_array( $rules ),
897
			'rules' => array(),
898
		);
899
900
		foreach ( $rules as $key => $rule ) {
901
			if ( $key === 'relation' ) {
902
				continue; // Skip the relation key as it is already handled above
903
			}
904
905
			// Check if the rule is valid
906
			if ( ! is_array( $rule ) || empty( $rule['field'] ) ) {
907
				Incorrect_Syntax_Exception::raise( 'Invalid conditional logic rule format. ' .
908
				'The rule should be an array with the "field" key set.' );
909
			}
910
911
			// Check the compare operator
912
			if ( empty( $rule['compare'] ) ) {
913
				$rule['compare'] = '=';
914
			}
915
			if ( ! in_array( $rule['compare'], $allowed_operators ) ) {
916
				Incorrect_Syntax_Exception::raise( 'Invalid conditional logic compare operator: <code>' .
917
					$rule['compare'] . '</code><br>Allowed operators are: <code>' .
918
				implode( ', ', $allowed_operators ) . '</code>' );
919
			}
920
			if ( $rule['compare'] === 'IN' || $rule['compare'] === 'NOT IN' ) {
921
				if ( ! is_array( $rule['value'] ) ) {
922
					Incorrect_Syntax_Exception::raise( 'Invalid conditional logic value format. ' .
923
					'An array is expected, when using the "' . $rule['compare'] . '" operator.' );
924
				}
925
			}
926
927
			// Check the value
928
			if ( ! isset( $rule['value'] ) ) {
929
				$rule['value'] = '';
930
			}
931
932
			$parsed_rules['rules'][] = $rule;
933
		}
934
935
		return $parsed_rules;
936
	}
937
938
	/**
939
	 * Configuration function for setting the field visibility in the response of the requests to the REST API
940
	 * 
941
	 * @param bool $visible
942
	 * @return Field $this
943
	 */
944
	public function show_in_rest( $visible = true ) {
945
		$this->set_visible_in_rest_api( $visible );
946
		return $this;
947
	}
948
	/**
949
	 * Set the REST visibility of the field
950
	 * 
951
	 * @param bool $visible
952
	 */
953
	public function set_visible_in_rest_api( $visible ) {
954
		$this->visible_in_rest_api = $visible;
955
	}
956
	/**
957
	 * Get the REST visibility of the field
958
	 * 
959
	 * @return bool
960
	 */
961
	public function get_visible_in_rest_api() {
962
		return $this->visible_in_rest_api;
963
	}
964
965
	/**
966
	 * Hook administration scripts.
967
	 */
968
	public static function admin_hook_scripts() {
969
		wp_enqueue_media();
970
		wp_enqueue_script( 'carbon-fields', \Carbon_Fields\URL . '/assets/js/fields.js', array( 'carbon-app', 'carbon-containers' ), \Carbon_Fields\VERSION );
971
		wp_localize_script( 'carbon-fields', 'crbl10n',
972
			array(
973
				'title' => __( 'Files', \Carbon_Fields\TEXT_DOMAIN ),
974
				'geocode_zero_results' => __( 'The address could not be found. ', \Carbon_Fields\TEXT_DOMAIN ),
975
				'geocode_not_successful' => __( 'Geocode was not successful for the following reason: ', \Carbon_Fields\TEXT_DOMAIN ),
976
				'max_num_items_reached' => __( 'Maximum number of items reached (%s items)', \Carbon_Fields\TEXT_DOMAIN ),
977
				'max_num_rows_reached' => __( 'Maximum number of rows reached (%s rows)', \Carbon_Fields\TEXT_DOMAIN ),
978
				'cannot_create_more_rows' => __( 'Cannot create more than %s rows', \Carbon_Fields\TEXT_DOMAIN ),
979
				'complex_no_rows' => __( 'There are no %s yet. Click <a href="#">here</a> to add one.', \Carbon_Fields\TEXT_DOMAIN ),
980
				'complex_add_button' => __( 'Add %s', \Carbon_Fields\TEXT_DOMAIN ),
981
				'complex_min_num_rows_not_reached' => __( 'Minimum number of rows not reached (%1$d %2$s)', \Carbon_Fields\TEXT_DOMAIN ),
982
				'message_form_validation_failed' => __( 'Please fill out all fields correctly. ', \Carbon_Fields\TEXT_DOMAIN ),
983
				'message_required_field' => __( 'This field is required. ', \Carbon_Fields\TEXT_DOMAIN ),
984
				'message_choose_option' => __( 'Please choose an option. ', \Carbon_Fields\TEXT_DOMAIN ),
985
986
				'enter_name_of_new_sidebar' => __( 'Please enter the name of the new sidebar:', \Carbon_Fields\TEXT_DOMAIN ),
987
			)
988
		);
989
	}
990
991
	/**
992
	 * Hook administration styles.
993
	 */
994
	public static function admin_hook_styles() {
995
		wp_enqueue_style( 'thickbox' );
996
	}
997
}
998