Completed
Push — milestone/2.0 ( 2fc31a...c63841 )
by
unknown
02:32
created

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