Completed
Push — milestone/2.0 ( dae7a5...48be68 )
by
unknown
03:13
created

Field::get_value_from_datastore()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

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

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

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

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