Completed
Push — milestone/2.0 ( 0dfc11...693dca )
by
unknown
03:12
created

Field::delete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
ccs 3
cts 3
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
	public function set_hierarchy( $hierarchy ) {
277
		$this->hierarchy = $hierarchy;
278
	}
279
280
	/**
281
	 * Get array of hierarchy field names
282
	 *
283
	 * @return array
284
	 **/
285
	public function get_hierarchy() {
286
		return $this->hierarchy;
287
	}
288
289
	/**
290
	 * Set array of hierarchy indexes
291
	 **/
292
	public function set_hierarchy_index( $hierarchy_index ) {
293
		$hierarchy_index = ( ! empty( $hierarchy_index ) ) ? $hierarchy_index : array( 0 );
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 3
	public function is_simple_root_field() {
312 3
		$hierarchy = $this->get_hierarchy();
313
		return (
314 3
			empty( $hierarchy )
315 3
			&&
316
			(
317 2
				$this->get_value_set()->get_type() === Value_Set::TYPE_SINGLE_VALUE
318 2
				||
319 2
				$this->get_value_set()->get_type() === Value_Set::TYPE_MULTIPLE_PROPERTIES
320 2
			)
321 3
		);
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['value_set'] ) ) {
373
			$value = $raw_value_set_tree['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 2
	public function load() {
387 2
		$value = $this->get_value_from_datastore();
388 2
		$this->set_value( $value );
389 2
	}
390
391
	/**
392
	 * Save value to storage
393
	 **/
394 5
	public function save() {
395 5
		if ( ! in_array( $this->get_value_set()->get_type(), array( Value_Set::TYPE_SINGLE_VALUE, Value_Set::TYPE_MULTIPLE_PROPERTIES ) ) ) {
396 2
			$this->delete();
397 2
		}
398 5
		return $this->get_datastore()->save( $this );
399
	}
400
401
	/**
402
	 * Delete value from storage
403
	 */
404 1
	public function delete() {
405 1
		$this->get_datastore()->delete( $this );
406 1
	}
407
408
	/**
409
	 * Load the field value from an input array based on it's name
410
	 *
411
	 * @param array $input Array of field names and values.
412
	 **/
413 2
	public function set_value_from_input( $input ) {
414 2
		if ( isset( $input[ $this->get_name() ] ) ) {
415 1
			$this->set_value( $input[ $this->get_name() ] );
416 1
		} else {
417 1
			$this->set_value( array() );
418
		}
419 2
	}
420
421
	/**
422
	 * Return whether the datastore instance is the default one or has been overriden
423
	 *
424
	 * @return boolean
425
	 **/
426
	public function has_default_datastore() {
427
		return $this->has_default_datastore;
428
	}
429
430
	/**
431
	 * Set datastore instance
432
	 *
433
	 * @param Datastore_Interface $datastore
434
	 * @return object $this
435
	 **/
436 1
	public function set_datastore( Datastore_Interface $datastore, $set_as_default = false ) {
437 1
		if ( $set_as_default && ! $this->has_default_datastore() ) {
438
			return $this; // datastore has been overriden with a custom one - abort changing to a default one
439
		}
440 1
		$this->datastore = $datastore;
441 1
		$this->has_default_datastore = $set_as_default;
442 1
		return $this;
443
	}
444
445
	/**
446
	 * Get the DataStore instance
447
	 *
448
	 * @return Datastore_Interface $datastore
449
	 **/
450 1
	public function get_datastore() {
451 1
		return $this->datastore;
452
	}
453
454
	/**
455
	 * Assign the type of the container this field is in
456
	 *
457
	 * @param string
458
	 * @return object $this
459
	 **/
460
	public function set_context( $context ) {
461
		$this->context = $context;
462
		return $this;
463
	}
464
465
	/**
466
	 * Return the type of the container this field is in
467
	 *
468
	 * @return string
469
	 **/
470
	public function get_context() {
471
		return $this->context;
472
	}
473
474
	/**
475
	 * Get the Value_Set object
476
	 *
477
	 * @return Value_Set
478
	 **/
479 2
	public function get_value_set() {
480 2
		if ( $this->value_set === null ) {
481 1
			$this->set_value_set( new Value_Set() );
482 1
		}
483 2
		return $this->value_set;
484
	}
485
486
	/**
487
	 * Set the Value_Set object
488
	 *
489
	 * @param Value_Set $value_set
490
	 **/
491 1
	public function set_value_set( $value_set ) {
492 1
		$this->value_set = $value_set;
493 1
	}
494
495
	/**
496
	 * Alias for $this->get_value_set()->get(); with fallback to default value
497
	 *
498
	 * @return mixed
499
	 **/
500 3
	public function get_value() {
501 3
		if ( $this->get_value_set()->get() === null ) {
502 1
			$this->set_value( $this->get_default_value() );
503 1
		}
504 3
		return $this->get_value_set()->get();
505
	}
506
507
	/**
508
	 * Alias for $this->get_value_set()->get_set(); with fallback to default value
509
	 *
510
	 * @return mixed
511
	 **/
512 2
	public function get_full_value() {
513 2
		if ( $this->get_value_set()->get_set() === null ) {
514
			$this->set_value( $this->get_default_value() );
515
		}
516
		return $this->get_value_set()->get_set();
517
	}
518
519 1
	/**
520 1
	 * Return a differently formatted value for end-users
521 1
	 *
522
	 * @return mixed
523
	 **/
524
	public function get_formatted_value() {
525
		return $this->get_value();
526
	}
527
528 1
	/**
529 1
	 * Alias for $this->get_value_set()->set( $value );
530 1
	 **/
531
	public function set_value( $value ) {
532
		$this->get_value_set()->set( $value );
533
	}
534
535
	/**
536
	 * Set default field value
537
	 *
538 1
	 * @param mixed $default_value
539 1
	 **/
540
	public function set_default_value( $default_value ) {
541
		$this->default_value = $default_value;
542
		return $this;
543
	}
544
545
	/**
546
	 * Get default field value
547
	 *
548 6
	 * @return mixed
549 6
	 **/
550 1
	public function get_default_value() {
551
		return $this->default_value;
552
	}
553 5
554 5
	/**
555 3
	 * Set field name.
556
	 * Use only if you are completely aware of what you are doing.
557
	 *
558 2
	 * @param string $name Field name, either sanitized or not
559 2
	 **/
560
	public function set_name( $name ) {
561 2
		if ( empty( $name ) ) {
562 2
			Incorrect_Syntax_Exception::raise( 'Field name can\'t be empty' );
563
		}
564
565
		$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)
566
		if ( ! preg_match( $regex, $name ) ) {
567
			Incorrect_Syntax_Exception::raise( 'Field name can only contain lowercase alphanumeric characters and underscores.' );
568
		}
569 2
570 2
		$name_prefix = $this->get_name_prefix();
571
		$name = ( substr( $name, 0, strlen( $name_prefix ) ) !== $name_prefix ? $name_prefix . $name : $name );
572
573
		$this->name = $name;
574
	}
575
576
	/**
577
	 * Return the field name
578
	 *
579 3
	 * @return string
580 3
	 **/
581 3
	public function get_name() {
582 3
		return $this->name;
583 3
	}
584
585 3
	/**
586 3
	 * Set field name prefix
587 3
	 * Use only if you are completely aware of what you are doing.
588
	 *
589
	 * @param string $name_prefix
590
	 **/
591
	public function set_name_prefix( $name_prefix ) {
592
		$name_prefix = strval( $name_prefix );
593
		$old_prefix_length = strlen( $this->name_prefix );
594 3
		$this->name_prefix = '';
595 3
		$this->set_name( substr( $this->get_name(), $old_prefix_length ) );
596
597
		$this->name_prefix = $name_prefix;
598
		$this->set_name( $this->name_prefix . $this->get_name() );
599
	}
600
601
	/**
602
	 * Return the field name prefix
603
	 *
604
	 * @return string
605
	 **/
606
	public function get_name_prefix() {
607
		return $this->name_prefix;
608
	}
609
610
	/**
611
	 * Set field base name as defined in the container.
612
	 **/
613
	public function set_base_name( $name ) {
614
		$this->base_name = $name;
615
	}
616
617
	/**
618
	 * Return the field base name.
619
	 *
620
	 * @return string
621
	 **/
622
	public function get_base_name() {
623
		return $this->base_name;
624
	}
625
626
	/**
627
	 * Set field label.
628
	 *
629
	 * @param string $label If null, the label will be generated from the field name
630
	 **/
631 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...
632
		// Try to guess field label from it's name
633
		if ( is_null( $label ) ) {
634
			// remove the leading underscore(if it's there)
635
			$label = preg_replace( '~^_~', '', $this->name );
636
637
			// remove the leading "crb_"(if it's there)
638
			$label = preg_replace( '~^crb_~', '', $label );
639
640
			// split the name into words and make them capitalized
641
			$label = mb_convert_case( str_replace( '_', ' ', $label ), MB_CASE_TITLE );
642
		}
643
644
		$this->label = $label;
645
	}
646
647
	/**
648
	 * Return field label.
649
	 *
650
	 * @return string
651
	 **/
652
	public function get_label() {
653
		return $this->label;
654
	}
655
656
	/**
657
	 * Set additional text to be displayed during field render,
658
	 * containing information and guidance for the user
659
	 *
660
	 * @return object $this
661
	 **/
662
	public function set_help_text( $help_text ) {
663
		$this->help_text = $help_text;
664
		return $this;
665
	}
666
667
	/**
668
	 * Alias for set_help_text()
669
	 *
670
	 * @see set_help_text()
671
	 * @return object $this
672
	 **/
673
	public function help_text( $help_text ) {
674
		return $this->set_help_text( $help_text );
675
	}
676
677
	/**
678
	 * Return the field help text
679
	 *
680
	 * @return object $this
681
	 **/
682
	public function get_help_text() {
683
		return $this->help_text;
684
	}
685
686
	/**
687
	 * Whether or not this value should be auto loaded. Applicable to theme options only.
688
	 *
689
	 * @param bool $autoload
690
	 * @return object $this
691
	 **/
692
	public function set_autoload( $autoload ) {
693
		$this->autoload = $autoload;
694
		return $this;
695
	}
696
697
	/**
698
	 * Return whether or not this value should be auto loaded.
699
	 *
700
	 * @return bool
701
	 **/
702
	public function get_autoload() {
703
		return $this->autoload;
704
	}
705
706
	/**
707
	 * Whether or not this field will be initialized when the field is in the viewport (visible).
708
	 *
709
	 * @param bool $lazyload
710
	 * @return object $this
711
	 **/
712
	public function set_lazyload( $lazyload ) {
713
		$this->lazyload = $lazyload;
714
		return $this;
715
	}
716
717
	/**
718
	 * Return whether or not this field should be lazyloaded.
719
	 *
720
	 * @return bool
721
	 **/
722
	public function get_lazyload() {
723
		return $this->lazyload;
724
	}
725
726
	/**
727
	 * Set the field width.
728
	 *
729
	 * @param int $width
730
	 * @return object $this
731
	 **/
732
	public function set_width( $width ) {
733
		$this->width = (int) $width;
734
		return $this;
735
	}
736
737
	/**
738
	 * Get the field width.
739
	 *
740
	 * @return int $width
741
	 **/
742
	public function get_width() {
743
		return $this->width;
744
	}
745
746
	/**
747
	 *  Add custom CSS class to the field html container.
748
	 *
749
	 * @param string|array $classes
750
	 * @return object $this
751
	 **/
752
	public function add_class( $classes ) {
753
		if ( ! is_array( $classes ) ) {
754
			$classes = array_values( array_filter( explode( ' ', $classes ) ) );
755
		}
756
757
		$this->classes = array_map( 'sanitize_html_class', $classes );
758
		return $this;
759
	}
760
761
	/**
762
	 * Get the field custom CSS classes.
763
	 *
764
	 * @return array
765
	 **/
766
	public function get_classes() {
767
		return $this->classes;
768
	}
769
770
	/**
771
	 * Whether this field is mandatory for the user
772
	 *
773 1
	 * @param bool $required
774 1
	 * @return object $this
775
	 **/
776
	public function set_required( $required = true ) {
777
		$this->required = $required;
778
		return $this;
779
	}
780
781 1
	/**
782 1
	 * HTML id attribute getter.
783 1
	 * @return string
784
	 */
785
	public function get_id() {
786
		return $this->id;
787
	}
788
789
	/**
790
	 * HTML id attribute setter
791
	 * @param string $id
792
	 */
793
	public function set_id( $id ) {
794
		$this->id = $id;
795
	}
796
797
	/**
798
	 * Return whether this field is mandatory for the user
799
	 *
800
	 * @return bool
801
	 **/
802
	public function is_required() {
803
		return $this->required;
804
	}
805
806
	/**
807
	 * Returns the type of the field based on the class.
808
	 * The class is stripped by the "CarbonFields" prefix.
809
	 * Also the "Field" suffix is removed.
810
	 * Then underscores and backslashes are removed.
811
	 *
812
	 * @return string
813
	 */
814
	public function get_type() {
815
		$class = get_class( $this );
816
817
		return $this->clean_type( $class );
818
	}
819
820
	/**
821
	 * Cleans up an object class for usage as HTML class
822
	 *
823
	 * @param string $type
824
	 * @return string
825
	 */
826
	protected function clean_type( $type ) {
827
		$remove = array(
828
			'_',
829
			'\\',
830
			'CarbonFields',
831
			'Field',
832
		);
833
		$clean_class = str_replace( $remove, '', $type );
834
835
		return $clean_class;
836
	}
837
838
	/**
839
	 * Returns an array that holds the field data, suitable for JSON representation.
840
	 * This data will be available in the Underscore template and the Backbone Model.
841
	 *
842
	 * @param bool $load  Should the value be loaded from the database or use the value from the current instance.
843
	 * @return array
844
	 */
845
	public function to_json( $load ) {
846
		if ( $load ) {
847
			$this->load();
848
		}
849
850
		$field_data = array(
851
			'id' => $this->get_id(),
852
			'type' => $this->get_type(),
853
			'label' => $this->get_label(),
854
			'name' => $this->get_name(),
855
			'base_name' => $this->get_base_name(),
856
			'value' => $this->get_value(),
857
			'default_value' => $this->get_default_value(),
858
			'help_text' => $this->get_help_text(),
859
			'context' => $this->get_context(),
860
			'required' => $this->is_required(),
861
			'lazyload' => $this->get_lazyload(),
862
			'width' => $this->get_width(),
863 8
			'classes' => $this->get_classes(),
864 8
			'conditional_logic' => $this->get_conditional_logic(),
865
		);
866 3
867
		return $field_data;
868
	}
869
870
	/**
871
	 * Set the field visibility conditional logic.
872
	 *
873
	 * @param array
874 3
	 */
875 3
	public function set_conditional_logic( $rules ) {
876
		$this->conditional_logic = $this->parse_conditional_rules( $rules );
877
878
		return $this;
879
	}
880
881
	/**
882
	 * Get the conditional logic rules
883
	 *
884
	 * @return array
885
	 */
886
	public function get_conditional_logic() {
887
		return $this->conditional_logic;
888
	}
889
890
	/**
891
	 * Validate and parse the conditional logic rules.
892
	 *
893
	 * @param array $rules
894
	 * @return array
895
	 */
896
	protected function parse_conditional_rules( $rules ) {
897
		if ( ! is_array( $rules ) ) {
898
			Incorrect_Syntax_Exception::raise( 'Conditional logic rules argument should be an array.' );
899
		}
900
901
		$allowed_operators = array( '=', '!=', '>', '>=', '<', '<=', 'IN', 'NOT IN' );
902
903
		$parsed_rules = array(
904
			'relation' => Helper::get_relation_type_from_array( $rules ),
905
			'rules' => array(),
906
		);
907
908
		foreach ( $rules as $key => $rule ) {
909
			if ( $key === 'relation' ) {
910
				continue; // Skip the relation key as it is already handled above
911
			}
912
913
			// Check if the rule is valid
914
			if ( ! is_array( $rule ) || empty( $rule['field'] ) ) {
915
				Incorrect_Syntax_Exception::raise( 'Invalid conditional logic rule format. ' .
916
				'The rule should be an array with the "field" key set.' );
917
			}
918
919
			// Check the compare operator
920
			if ( empty( $rule['compare'] ) ) {
921
				$rule['compare'] = '=';
922
			}
923
			if ( ! in_array( $rule['compare'], $allowed_operators ) ) {
924
				Incorrect_Syntax_Exception::raise( 'Invalid conditional logic compare operator: <code>' .
925
					$rule['compare'] . '</code><br>Allowed operators are: <code>' .
926
				implode( ', ', $allowed_operators ) . '</code>' );
927
			}
928
			if ( $rule['compare'] === 'IN' || $rule['compare'] === 'NOT IN' ) {
929
				if ( ! is_array( $rule['value'] ) ) {
930
					Incorrect_Syntax_Exception::raise( 'Invalid conditional logic value format. ' .
931
					'An array is expected, when using the "' . $rule['compare'] . '" operator.' );
932
				}
933
			}
934
935
			// Check the value
936
			if ( ! isset( $rule['value'] ) ) {
937
				$rule['value'] = '';
938
			}
939
940
			$parsed_rules['rules'][] = $rule;
941
		}
942
943
		return $parsed_rules;
944
	}
945
946
	/**
947
	 * Configuration function for setting the field visibility in the response of the requests to the REST API
948
	 * 
949
	 * @param bool $visible
950
	 * @return Field $this
951
	 */
952
	public function show_in_rest( $visible = true ) {
953
		$this->set_visible_in_rest_api( $visible );
954
		return $this;
955
	}
956
	/**
957
	 * Set the REST visibility of the field
958
	 * 
959
	 * @param bool $visible
960
	 */
961
	public function set_visible_in_rest_api( $visible ) {
962
		$this->visible_in_rest_api = $visible;
963
	}
964
	/**
965
	 * Get the REST visibility of the field
966
	 * 
967
	 * @return bool
968
	 */
969
	public function get_visible_in_rest_api() {
970
		return $this->visible_in_rest_api;
971
	}
972
973
	/**
974
	 * Hook administration scripts.
975
	 */
976
	public static function admin_hook_scripts() {
977
		wp_enqueue_media();
978
		wp_enqueue_script( 'carbon-fields', \Carbon_Fields\URL . '/assets/js/fields.js', array( 'carbon-app', 'carbon-containers' ), \Carbon_Fields\VERSION );
979
		wp_localize_script( 'carbon-fields', 'crbl10n',
980
			array(
981
				'title' => __( 'Files', \Carbon_Fields\TEXT_DOMAIN ),
982
				'geocode_zero_results' => __( 'The address could not be found. ', \Carbon_Fields\TEXT_DOMAIN ),
983
				'geocode_not_successful' => __( 'Geocode was not successful for the following reason: ', \Carbon_Fields\TEXT_DOMAIN ),
984
				'max_num_items_reached' => __( 'Maximum number of items reached (%s items)', \Carbon_Fields\TEXT_DOMAIN ),
985
				'max_num_rows_reached' => __( 'Maximum number of rows reached (%s rows)', \Carbon_Fields\TEXT_DOMAIN ),
986
				'cannot_create_more_rows' => __( 'Cannot create more than %s rows', \Carbon_Fields\TEXT_DOMAIN ),
987
				'complex_no_rows' => __( 'There are no %s yet. Click <a href="#">here</a> to add one.', \Carbon_Fields\TEXT_DOMAIN ),
988
				'complex_add_button' => __( 'Add %s', \Carbon_Fields\TEXT_DOMAIN ),
989
				'complex_min_num_rows_not_reached' => __( 'Minimum number of rows not reached (%1$d %2$s)', \Carbon_Fields\TEXT_DOMAIN ),
990
				'message_form_validation_failed' => __( 'Please fill out all fields correctly. ', \Carbon_Fields\TEXT_DOMAIN ),
991
				'message_required_field' => __( 'This field is required. ', \Carbon_Fields\TEXT_DOMAIN ),
992
				'message_choose_option' => __( 'Please choose an option. ', \Carbon_Fields\TEXT_DOMAIN ),
993
994
				'enter_name_of_new_sidebar' => __( 'Please enter the name of the new sidebar:', \Carbon_Fields\TEXT_DOMAIN ),
995
			)
996
		);
997
	}
998
999
	/**
1000
	 * Hook administration styles.
1001
	 */
1002
	public static function admin_hook_styles() {
1003
		wp_enqueue_style( 'thickbox' );
1004
	}
1005
}
1006