Completed
Push — test/legacy-storage-service ( 13c02e...9939d7 )
by
unknown
02:29
created

Field::set_hierarchy_index()   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
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 3
cp 0
crap 2
rs 10
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 15
	public static function factory( $type, $name, $label = null ) {
212 15
		$type = str_replace( ' ', '_', ucwords( str_replace( '_', ' ', $type ) ) );
213
214 15
		$class = __NAMESPACE__ . '\\' . $type . '_Field';
215
216 15 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 12
		$field = new $class( $name, $label );
222 10
		$field->type = $type;
223
224 10
		return $field;
225
	}
226
227
	/**
228
	 * An alias of factory().
229
	 *
230
	 * @see Field::factory()
231
	 * @return Field
232
	 **/
233 15
	public static function make( $type, $name, $label = null ) {
234 15
		return static::factory( $type, $name, $label );
235
	}
236
237
	/**
238
	 * Create a field from a certain type with the specified label.
239
	 * @param string $name  Field name
240
	 * @param string $label Field label
241
	 */
242 12 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...
243 12
		App::verify_boot();
244
		
245 12
		$this->set_base_name( $name );
246 12
		$this->set_name( $name );
247 10
		$this->set_label( $label );
248
249
		// Pick random ID
250 10
		$random_string = md5( mt_rand() . $this->get_name() . $this->get_label() );
251 10
		$random_string = substr( $random_string, 0, 5 ); // 5 chars should be enough
252 10
		$this->id = 'carbon-' . $random_string;
253
254 10
		$this->init();
255 10
	}
256
257
	/**
258
	 * Activate the field once the container is attached.
259
	 */
260
	public function activate() {
261
		$this->admin_init();
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
		add_action( 'admin_footer', array( get_class( $this ), 'admin_enqueue_scripts' ), 5 );
267
268
		do_action( 'crb_field_activated', $this );
269
	}
270
271
	/**
272
	 * Set array of hierarchy field names
273
	 *
274
	 * @return array
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
	 * @return array
293
	 **/
294
	public function set_hierarchy_index( $hierarchy_index ) {
295
		$this->hierarchy_index = $hierarchy_index;
296
	}
297
298
	/**
299
	 * Get array of hierarchy indexes
300
	 *
301
	 * @return array
302
	 **/
303
	public function get_hierarchy_index() {
304
		return $this->hierarchy_index;
305
	}
306
307
	/**
308
	 * Return whether the field is a root field and holds a single value
309
	 *
310
	 * @return bool
311
	 **/
312 3
	public function is_simple_root_field() {
313 3
		$hierarchy = $this->get_hierarchy();
314
		return (
315 3
			empty( $hierarchy )
316 3
			&&
317
			(
318 2
				$this->get_value_set()->get_type() === Value_Set::TYPE_SINGLE_VALUE
319 2
				||
320 2
				$this->get_value_set()->get_type() === Value_Set::TYPE_MULTIPLE_PROPERTIES
321 2
			)
322 3
		);
323
	}
324
325
	/**
326
	 * Perform instance initialization
327
	 **/
328
	public function init() {}
329
330
	/**
331
	 * Instance initialization when in the admin area.
332
	 * Called during field boot.
333
	 **/
334
	public function admin_init() {}
335
336
	/**
337
	 * Enqueue admin scripts.
338
	 * Called once per field type.
339
	 **/
340
	public static function admin_enqueue_scripts() {}
341
342
	/**
343
	 * Prints the main Underscore template
344
	 **/
345
	public function template() { }
346
347
	/**
348
	 * Returns all the Backbone templates
349
	 *
350
	 * @return array
351
	 **/
352
	public function get_templates() {
353
		return $this->templates;
354
	}
355
356
	/**
357
	 * Adds a new Backbone template
358
	 **/
359
	protected function add_template( $name, $callback ) {
360
		$this->templates[ $name ] = $callback;
361
	}
362
363
	/**
364
	 * Get value from datastore
365
	 *
366
	 * @param bool $fallback_to_default
367
	 * @return mixed
368
	 **/
369
	protected function get_value_from_datastore( $fallback_to_default = true ) {
370
		$raw_value_set_tree = $this->get_datastore()->load( $this );
371
		
372
		$value = null;
373
		if ( isset( $raw_value_set_tree[ $this->get_base_name() ] ) ) {
374
			$value = $raw_value_set_tree[ $this->get_base_name() ]['value_set'];
375
		}
376
377
		if ( $value === null && $fallback_to_default ) {
378
			$value = $this->get_default_value();
379
		}
380
381
		return $value;
382
	}
383
384
	/**
385
	 * Load value from datastore
386
	 **/
387 2
	public function load() {
388 2
		$value = $this->get_value_from_datastore();
389 2
		$this->set_value( $value );
390 2
	}
391
392
	/**
393
	 * Save value to storage
394
	 **/
395 5
	public function save() {
396 5
		if ( ! in_array( $this->get_value_set()->get_type(), array( Value_Set::TYPE_SINGLE_VALUE, Value_Set::TYPE_MULTIPLE_PROPERTIES ) ) ) {
397 2
			$this->delete();
398 2
		}
399 5
		return $this->get_datastore()->save( $this );
400
	}
401
402
	/**
403
	 * Delete value from storage
404
	 */
405 1
	public function delete() {
406 1
		$this->get_datastore()->delete( $this );
407 1
	}
408
409
	/**
410
	 * Load the field value from an input array based on it's name
411
	 *
412
	 * @param array $input Array of field names and values.
413
	 **/
414 2
	public function set_value_from_input( $input ) {
415 2
		if ( isset( $input[ $this->get_name() ] ) ) {
416 1
			$this->set_value( $input[ $this->get_name() ] );
417 1
		} else {
418 1
			$this->set_value( array() );
419
		}
420 2
	}
421
422
	/**
423
	 * Return whether the datastore instance is the default one or has been overriden
424
	 *
425
	 * @return boolean
426
	 **/
427
	public function has_default_datastore() {
428
		return $this->has_default_datastore;
429
	}
430
431
	/**
432
	 * Set datastore instance
433
	 *
434
	 * @param Datastore_Interface $datastore
435
	 * @return object $this
436
	 **/
437 1
	public function set_datastore( Datastore_Interface $datastore, $set_as_default = false ) {
438 1
		if ( $set_as_default && ! $this->has_default_datastore() ) {
439
			return $this; // datastore has been overriden with a custom one - abort changing to a default one
440
		}
441 1
		$this->datastore = $datastore;
442 1
		$this->has_default_datastore = $set_as_default;
443 1
		return $this;
444
	}
445
446
	/**
447
	 * Get the DataStore instance
448
	 *
449
	 * @return Datastore_Interface $datastore
450
	 **/
451 1
	public function get_datastore() {
452 1
		return $this->datastore;
453
	}
454
455
	/**
456
	 * Assign the type of the container this field is in
457
	 *
458
	 * @param string
459
	 * @return object $this
460
	 **/
461
	public function set_context( $context ) {
462
		$this->context = $context;
463
		return $this;
464
	}
465
466
	/**
467
	 * Return the type of the container this field is in
468
	 *
469
	 * @return string
470
	 **/
471
	public function get_context() {
472
		return $this->context;
473
	}
474
475
	/**
476
	 * Get the Value_Set object
477
	 *
478
	 * @return Value_Set
479
	 **/
480 2
	public function get_value_set() {
481 2
		if ( $this->value_set === null ) {
482 1
			$this->set_value_set( new Value_Set() );
483 1
		}
484 2
		return $this->value_set;
485
	}
486
487
	/**
488
	 * Set the Value_Set object
489
	 *
490
	 * @param Value_Set $value_set
491
	 **/
492 1
	public function set_value_set( $value_set ) {
493 1
		$this->value_set = $value_set;
494 1
	}
495
496
	/**
497
	 * Alias for $this->get_value_set()->get();
498
	 *
499
	 * @return mixed
500
	 **/
501 3
	public function get_value() {
502 3
		return $this->get_value_set()->get();
503
	}
504
505
	/**
506
	 * Return a differently formatted value for end-users
507
	 *
508
	 * @return mixed
509
	 **/
510 2
	public function get_formatted_value() {
511 2
		$value = $this->get_value();
512 2
		if ( $value === null ) {
513 1
			$value = $this->get_default_value();
514 1
		}
515 2
		return $value;
516
	}
517
518
	/**
519
	 * Alias for $this->get_value_set()->set( $value );
520
	 **/
521 1
	public function set_value( $value ) {
522 1
		$this->get_value_set()->set( $value );
523 1
	}
524
525
	/**
526
	 * Set default field value
527
	 *
528
	 * @param mixed $default_value
529
	 **/
530 1
	public function set_default_value( $default_value ) {
531 1
		$this->default_value = $default_value;
532 1
		return $this;
533
	}
534
535
	/**
536
	 * Get default field value
537
	 *
538
	 * @return mixed
539
	 **/
540 1
	public function get_default_value() {
541 1
		return $this->default_value;
542
	}
543
544
	/**
545
	 * Set field name.
546
	 * Use only if you are completely aware of what you are doing.
547
	 *
548
	 * @param string $name Field name, either sanitized or not
549
	 **/
550 7
	public function set_name( $name ) {
551 7
		$name = mb_strtolower( $name );
552 7
		$name = preg_replace( '~\s+~', '_', $name );
553
554 7
		if ( empty( $name ) ) {
555 1
			Incorrect_Syntax_Exception::raise( 'Field name can\'t be empty' );
556
		}
557
558 6
		$regex = '/[\|\:]+/';
559 6
		if ( preg_match( $regex, $name ) ) {
560 1
			Incorrect_Syntax_Exception::raise( 'Field name "' . $name . '" cannot contain "|" or ":" characters.' );
561
		}
562
563 5
		$name_prefix = $this->get_name_prefix();
564 5
		$name = ( substr( $name, 0, strlen( $name_prefix ) ) !== $name_prefix ? $name_prefix . $name : $name );
565
566 5
		$this->name = $name;
567 5
	}
568
569
	/**
570
	 * Return the field name
571
	 *
572
	 * @return string
573
	 **/
574 5
	public function get_name() {
575 5
		return $this->name;
576
	}
577
578
	/**
579
	 * Set field name prefix
580
	 * Use only if you are completely aware of what you are doing.
581
	 *
582
	 * @param string $name_prefix
583
	 **/
584 3
	public function set_name_prefix( $name_prefix ) {
585 3
		$name_prefix = strval( $name_prefix );
586 3
		$old_prefix_length = strlen( $this->name_prefix );
587 3
		$this->name_prefix = '';
588 3
		$this->set_name( substr( $this->get_name(), $old_prefix_length ) );
589
590 3
		$this->name_prefix = $name_prefix;
591 3
		$this->set_name( $this->name_prefix . $this->get_name() );
592 3
	}
593
594
	/**
595
	 * Return the field name prefix
596
	 *
597
	 * @return string
598
	 **/
599 3
	public function get_name_prefix() {
600 3
		return $this->name_prefix;
601
	}
602
603
	/**
604
	 * Set field base name as defined in the container.
605
	 **/
606
	public function set_base_name( $name ) {
607
		$this->base_name = $name;
608
	}
609
610
	/**
611
	 * Return the field base name.
612
	 *
613
	 * @return string
614
	 **/
615
	public function get_base_name() {
616
		return $this->base_name;
617
	}
618
619
	/**
620
	 * Set field label.
621
	 *
622
	 * @param string $label If null, the label will be generated from the field name
623
	 **/
624 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...
625
		// Try to guess field label from it's name
626
		if ( is_null( $label ) ) {
627
			// remove the leading underscore(if it's there)
628
			$label = preg_replace( '~^_~', '', $this->name );
629
630
			// remove the leading "crb_"(if it's there)
631
			$label = preg_replace( '~^crb_~', '', $label );
632
633
			// split the name into words and make them capitalized
634
			$label = mb_convert_case( str_replace( '_', ' ', $label ), MB_CASE_TITLE );
635
		}
636
637
		$this->label = $label;
638
	}
639
640
	/**
641
	 * Return field label.
642
	 *
643
	 * @return string
644
	 **/
645
	public function get_label() {
646
		return $this->label;
647
	}
648
649
	/**
650
	 * Set additional text to be displayed during field render,
651
	 * containing information and guidance for the user
652
	 *
653
	 * @return object $this
654
	 **/
655
	public function set_help_text( $help_text ) {
656
		$this->help_text = $help_text;
657
		return $this;
658
	}
659
660
	/**
661
	 * Alias for set_help_text()
662
	 *
663
	 * @see set_help_text()
664
	 * @return object $this
665
	 **/
666
	public function help_text( $help_text ) {
667
		return $this->set_help_text( $help_text );
668
	}
669
670
	/**
671
	 * Return the field help text
672
	 *
673
	 * @return object $this
674
	 **/
675
	public function get_help_text() {
676
		return $this->help_text;
677
	}
678
679
	/**
680
	 * Whether or not this value should be auto loaded. Applicable to theme options only.
681
	 *
682
	 * @param bool $autoload
683
	 * @return object $this
684
	 **/
685
	public function set_autoload( $autoload ) {
686
		$this->autoload = $autoload;
687
		return $this;
688
	}
689
690
	/**
691
	 * Return whether or not this value should be auto loaded.
692
	 *
693
	 * @return bool
694
	 **/
695
	public function get_autoload() {
696
		return $this->autoload;
697
	}
698
699
	/**
700
	 * Whether or not this field will be initialized when the field is in the viewport (visible).
701
	 *
702
	 * @param bool $lazyload
703
	 * @return object $this
704
	 **/
705
	public function set_lazyload( $lazyload ) {
706
		$this->lazyload = $lazyload;
707
		return $this;
708
	}
709
710
	/**
711
	 * Return whether or not this field should be lazyloaded.
712
	 *
713
	 * @return bool
714
	 **/
715
	public function get_lazyload() {
716
		return $this->lazyload;
717
	}
718
719
	/**
720
	 * Set the field width.
721
	 *
722
	 * @param int $width
723
	 * @return object $this
724
	 **/
725
	public function set_width( $width ) {
726
		$this->width = (int) $width;
727
		return $this;
728
	}
729
730
	/**
731
	 * Get the field width.
732
	 *
733
	 * @return int $width
734
	 **/
735
	public function get_width() {
736
		return $this->width;
737
	}
738
739
	/**
740
	 *  Add custom CSS class to the field html container.
741
	 *
742
	 * @param string|array $classes
743
	 * @return object $this
744
	 **/
745
	public function add_class( $classes ) {
746
		if ( ! is_array( $classes ) ) {
747
			$classes = array_values( array_filter( explode( ' ', $classes ) ) );
748
		}
749
750
		$this->classes = array_map( 'sanitize_html_class', $classes );
751
		return $this;
752
	}
753
754
	/**
755
	 * Get the field custom CSS classes.
756
	 *
757
	 * @return array
758
	 **/
759
	public function get_classes() {
760
		return $this->classes;
761
	}
762
763
	/**
764
	 * Whether this field is mandatory for the user
765
	 *
766
	 * @param bool $required
767
	 * @return object $this
768
	 **/
769
	public function set_required( $required = true ) {
770
		$this->required = $required;
771
		return $this;
772
	}
773
774
	/**
775
	 * HTML id attribute getter.
776
	 * @return string
777
	 */
778 1
	public function get_id() {
779 1
		return $this->id;
780
	}
781
782
	/**
783
	 * HTML id attribute setter
784
	 * @param string $id
785
	 */
786 1
	public function set_id( $id ) {
787 1
		$this->id = $id;
788 1
	}
789
790
	/**
791
	 * Return whether this field is mandatory for the user
792
	 *
793
	 * @return bool
794
	 **/
795
	public function is_required() {
796
		return $this->required;
797
	}
798
799
	/**
800
	 * Returns the type of the field based on the class.
801
	 * The class is stripped by the "CarbonFields" prefix.
802
	 * Also the "Field" suffix is removed.
803
	 * Then underscores and backslashes are removed.
804
	 *
805
	 * @return string
806
	 */
807
	public function get_type() {
808
		$class = get_class( $this );
809
810
		return $this->clean_type( $class );
811
	}
812
813
	/**
814
	 * Cleans up an object class for usage as HTML class
815
	 *
816
	 * @param string $type
817
	 * @return string
818
	 */
819
	protected function clean_type( $type ) {
820
		$remove = array(
821
			'_',
822
			'\\',
823
			'CarbonFields',
824
			'Field',
825
		);
826
		$clean_class = str_replace( $remove, '', $type );
827
828
		return $clean_class;
829
	}
830
831
	/**
832
	 * Returns an array that holds the field data, suitable for JSON representation.
833
	 * This data will be available in the Underscore template and the Backbone Model.
834
	 *
835
	 * @param bool $load  Should the value be loaded from the database or use the value from the current instance.
836
	 * @return array
837
	 */
838
	public function to_json( $load ) {
839
		if ( $load ) {
840
			$this->load();
841
		}
842
843
		$field_data = array(
844
			'id' => $this->get_id(),
845
			'type' => $this->get_type(),
846
			'label' => $this->get_label(),
847
			'name' => $this->get_name(),
848
			'base_name' => $this->get_base_name(),
849
			'value' => $this->get_value(),
850
			'default_value' => $this->get_default_value(),
851
			'help_text' => $this->get_help_text(),
852
			'context' => $this->get_context(),
853
			'required' => $this->is_required(),
854
			'lazyload' => $this->get_lazyload(),
855
			'width' => $this->get_width(),
856
			'classes' => $this->get_classes(),
857
			'conditional_logic' => $this->get_conditional_logic(),
858
		);
859
860
		return $field_data;
861
	}
862
863
	/**
864
	 * Set the field visibility conditional logic.
865
	 *
866
	 * @param array
867
	 */
868 8
	public function set_conditional_logic( $rules ) {
869 8
		$this->conditional_logic = $this->parse_conditional_rules( $rules );
870
871 3
		return $this;
872
	}
873
874
	/**
875
	 * Get the conditional logic rules
876
	 *
877
	 * @return array
878
	 */
879 3
	public function get_conditional_logic() {
880 3
		return $this->conditional_logic;
881
	}
882
883
	/**
884
	 * Validate and parse the conditional logic rules.
885
	 *
886
	 * @param array $rules
887
	 * @return array
888
	 */
889
	protected function parse_conditional_rules( $rules ) {
890
		if ( ! is_array( $rules ) ) {
891
			Incorrect_Syntax_Exception::raise( 'Conditional logic rules argument should be an array.' );
892
		}
893
894
		$allowed_operators = array( '=', '!=', '>', '>=', '<', '<=', 'IN', 'NOT IN' );
895
896
		$parsed_rules = array(
897
			'relation' => Helper::get_relation_type_from_array( $rules ),
898
			'rules' => array(),
899
		);
900
901
		foreach ( $rules as $key => $rule ) {
902
			if ( $key === 'relation' ) {
903
				continue; // Skip the relation key as it is already handled above
904
			}
905
906
			// Check if the rule is valid
907
			if ( ! is_array( $rule ) || empty( $rule['field'] ) ) {
908
				Incorrect_Syntax_Exception::raise( 'Invalid conditional logic rule format. ' .
909
				'The rule should be an array with the "field" key set.' );
910
			}
911
912
			// Check the compare operator
913
			if ( empty( $rule['compare'] ) ) {
914
				$rule['compare'] = '=';
915
			}
916 View Code Duplication
			if ( ! in_array( $rule['compare'], $allowed_operators ) ) {
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
917
				Incorrect_Syntax_Exception::raise( 'Invalid conditional logic compare operator: <code>' .
918
					$rule['compare'] . '</code><br>Allowed operators are: <code>' .
919
				implode( ', ', $allowed_operators ) . '</code>' );
920
			}
921
			if ( $rule['compare'] === 'IN' || $rule['compare'] === 'NOT IN' ) {
922
				if ( ! is_array( $rule['value'] ) ) {
923
					Incorrect_Syntax_Exception::raise( 'Invalid conditional logic value format. ' .
924
					'An array is expected, when using the "' . $rule['compare'] . '" operator.' );
925
				}
926
			}
927
928
			// Check the value
929
			if ( ! isset( $rule['value'] ) ) {
930
				$rule['value'] = '';
931
			}
932
933
			$parsed_rules['rules'][] = $rule;
934
		}
935
936
		return $parsed_rules;
937
	}
938
939
	/**
940
	 * Configuration function for setting the field visibility in the response of the requests to the REST API
941
	 * 
942
	 * @param bool $visible
943
	 * @return Field $this
944
	 */
945
	public function show_in_rest( $visible = true ) {
946
		$this->set_visible_in_rest_api( $visible );
947
		return $this;
948
	}
949
	/**
950
	 * Set the REST visibility of the field
951
	 * 
952
	 * @param bool $visible
953
	 */
954
	public function set_visible_in_rest_api( $visible ) {
955
		$this->visible_in_rest_api = $visible;
956
	}
957
	/**
958
	 * Get the REST visibility of the field
959
	 * 
960
	 * @return bool
961
	 */
962
	public function get_visible_in_rest_api() {
963
		return $this->visible_in_rest_api;
964
	}
965
966
	/**
967
	 * Hook administration scripts.
968
	 */
969
	public static function admin_hook_scripts() {
970
		wp_enqueue_media();
971
		wp_enqueue_script( 'carbon-fields', \Carbon_Fields\URL . '/assets/js/fields.js', array( 'carbon-app', 'carbon-containers' ), \Carbon_Fields\VERSION );
972
		wp_localize_script( 'carbon-fields', 'crbl10n',
973
			array(
974
				'title' => __( 'Files', \Carbon_Fields\TEXT_DOMAIN ),
975
				'geocode_zero_results' => __( 'The address could not be found. ', \Carbon_Fields\TEXT_DOMAIN ),
976
				'geocode_not_successful' => __( 'Geocode was not successful for the following reason: ', \Carbon_Fields\TEXT_DOMAIN ),
977
				'max_num_items_reached' => __( 'Maximum number of items reached (%s items)', \Carbon_Fields\TEXT_DOMAIN ),
978
				'max_num_rows_reached' => __( 'Maximum number of rows reached (%s rows)', \Carbon_Fields\TEXT_DOMAIN ),
979
				'cannot_create_more_rows' => __( 'Cannot create more than %s rows', \Carbon_Fields\TEXT_DOMAIN ),
980
				'complex_no_rows' => __( 'There are no %s yet. Click <a href="#">here</a> to add one.', \Carbon_Fields\TEXT_DOMAIN ),
981
				'complex_add_button' => __( 'Add %s', \Carbon_Fields\TEXT_DOMAIN ),
982
				'complex_min_num_rows_not_reached' => __( 'Minimum number of rows not reached (%1$d %2$s)', \Carbon_Fields\TEXT_DOMAIN ),
983
				'message_form_validation_failed' => __( 'Please fill out all fields correctly. ', \Carbon_Fields\TEXT_DOMAIN ),
984
				'message_required_field' => __( 'This field is required. ', \Carbon_Fields\TEXT_DOMAIN ),
985
				'message_choose_option' => __( 'Please choose an option. ', \Carbon_Fields\TEXT_DOMAIN ),
986
987
				'enter_name_of_new_sidebar' => __( 'Please enter the name of the new sidebar:', \Carbon_Fields\TEXT_DOMAIN ),
988
			)
989
		);
990
	}
991
992
	/**
993
	 * Hook administration styles.
994
	 */
995
	public static function admin_hook_styles() {
996
		wp_enqueue_style( 'thickbox' );
997
	}
998
}
999