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