Completed
Push — milestone/2.0 ( cbeb64...663741 )
by
unknown
04:13
created

Field::get_html_class()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

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