Completed
Push — milestone/2_0/container-condit... ( 3aa2e2...d923a5 )
by
unknown
04:55
created

Container::all_conditions_pass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 0
cts 0
cp 0
crap 2
1
<?php
2
3
namespace Carbon_Fields\Container;
4
5
use Carbon_Fields\App;
6
use Carbon_Fields\Helper\Helper;
7
use Carbon_Fields\Field\Field;
8
use Carbon_Fields\Field\Group_Field;
9
use Carbon_Fields\Container\Fulfillable\Fulfillable_Collection;
10
use Carbon_Fields\Datastore\Datastore_Interface;
11
use Carbon_Fields\Datastore\Datastore_Holder_Interface;
12
use Carbon_Fields\Exception\Incorrect_Syntax_Exception;
13
14
/**
15
 * Base container class.
16
 * Defines the key container methods and their default implementations.
17
 */
18
abstract class Container implements Datastore_Holder_Interface {
19
	/**
20
	 * Where to put a particular tab -- at the head or the tail. Tail by default
21
	 */
22
	const TABS_TAIL = 1;
23
	const TABS_HEAD = 2;
24
25
	/**
26
	 * Separator signifying field hierarchy relation
27
	 * Used when searching for fields in a specific complex field
28
	 */
29
	const HIERARCHY_FIELD_SEPARATOR = '/';
30
31
	/**
32
	 * Separator signifying complex_field->group relation
33
	 * Used when searching for fields in a specific complex field group
34
	 */
35
	const HIERARCHY_GROUP_SEPARATOR = ':';
36
37
	/**
38
	 * Stores if the container is active on the current page
39
	 *
40
	 * @see activate()
41
	 * @var bool
42
	 */
43
	protected $active = false;
44
45
	/**
46
	 * List of registered unique field names for this container instance
47
	 *
48
	 * @see verify_unique_field_name()
49
	 * @var array
50
	 */
51
	protected $registered_field_names = array();
52
53
	/**
54
	 * Tabs available
55
	 */
56
	protected $tabs = array();
57
58
	/**
59
	 * List of default container settings
60
	 *
61
	 * @see init()
62
	 * @var array
63
	 */
64
	public $settings = array();
65
66
	/**
67
	 * Title of the container
68
	 *
69
	 * @var string
70
	 */
71
	public $title = '';
72
73
	/**
74
	 * List of notification messages to be displayed on the front-end
75
	 *
76
	 * @var array
77
	 */
78
	protected $notifications = array();
79
80
	/**
81
	 * List of error messages to be displayed on the front-end
82
	 *
83
	 * @var array
84
	 */
85
	protected $errors = array();
86
87
	/**
88
	 * List of container fields
89
	 *
90
	 * @see add_fields()
91
	 * @var array
92
	 */
93
	protected $fields = array();
94
95
	/**
96
	 * Container datastores. Propagated to all container fields
97
	 *
98
	 * @see set_datastore()
99
	 * @see get_datastore()
100
	 * @var object
101
	 */
102
	protected $datastore;
103
104
	/**
105
	 * Flag whether the datastore is the default one or replaced with a custom one
106
	 *
107
	 * @see set_datastore()
108
	 * @see get_datastore()
109
	 * @var boolean
110
	 */
111
	protected $has_default_datastore = true;
112
113
	/**
114
	 * Fulfillable_Collection to use when checking attachment/saving conditions
115
	 *
116
	 * @var Fulfillable_Collection
117
	 */
118
	protected $condition_collection;
119
120
	/**
121
	 * Get array of all static condition types
122
	 *
123
	 * @param  boolean       $static
124
	 * @return array<string>
125
	 */
126
	protected function get_condition_types( $static ) {
127
		$group = $static ? 'static' : 'dynamic';
128
		$container_type = Helper::class_to_type( get_class( $this ), '_Container' );
129
		
130
		$condition_types = array();
131
		$condition_types = apply_filters( 'carbon_fields_' . $container_type . '_container_' . $group . '_condition_types', $condition_types, $container_type, $this );
132
		$condition_types = apply_filters( 'carbon_fields_container_' . $group . '_condition_types', $condition_types, $container_type, $this );
133
			
134
		return $condition_types;
135
	}
136
137
	/**
138
	 * Create a new container of type $type and name $name.
139
	 *
140
	 * @param string $type
141
	 * @param string $name Human-readable name of the container
142
	 * @return object $container
143
	 */
144
	public static function factory( $type, $name ) {
145
		$normalized_type = Helper::normalize_type( $type );
146
		$class = Helper::type_to_class( $normalized_type, __NAMESPACE__, '_Container' );
147
		
148 View Code Duplication
		if ( ! class_exists( $class ) ) {
149
			Incorrect_Syntax_Exception::raise( 'Unknown container "' . $type . '".' );
150
			$class = __NAMESPACE__ . '\\Broken_Container';
151
		}
152
		
153
		$repository = App::resolve( 'container_repository' );
154
		$unique_id = $repository->get_unique_panel_id( $name );
155
		$container = new $class( $unique_id, $name, $normalized_type );
156
		$repository->register_container( $container );
157
158
		return $container;
159
	}
160
161
	/**
162
	 * An alias of factory().
163
	 *
164
	 * @see Container::factory()
165
	 */
166
	public static function make( $type, $name ) {
167
		return static::factory( $type, $name );
168
	}
169
170
	/**
171
	 * Create a new container
172
	 *
173
	 * @param string $unique_id Unique id of the container
174
	 * @param string $title title of the container
175
	 * @param string $type Type of the container
176
	 */
177
	public function __construct( $unique_id, $title, $type ) {
178
		App::verify_boot();
179
180
		if ( empty( $title ) ) {
181
			Incorrect_Syntax_Exception::raise( 'Empty container title is not supported' );
182
		}
183
184
		$this->id = $unique_id;
185
		$this->title = $title;
186
		$this->type = $type;
187
		$this->condition_collection = App::resolve( 'container_condition_fulfillable_collection' );
188
		$this->condition_collection->set_condition_type_list(
189
			array_merge( $this->get_condition_types( true ), $this->get_condition_types( false ) ),
190
			true
191
		);
192
	}
193
194
	/**
195
	 * Return whether the container is active
196 9
	 */
197 9
	public function active() {
198 9
		return $this->active;
199
	}
200 9
201 9
	/**
202 7
	 * Activate the container and trigger an action
203 7
	 */
204
	protected function activate() {
205 7
		$this->active = true;
206
		$this->boot();
207
		do_action( 'crb_container_activated', $this );
208
209
		$fields = $this->get_fields();
210
		foreach ( $fields as $field ) {
211
			$field->activate();
212
		}
213
	}
214
215
	/**
216
	 * Perform instance initialization
217
	 */
218
	abstract public function init();
219
220
	/**
221
	 * Boot the container once it's attached.
222
	 */
223
	protected function boot() {
224 2
		add_action( 'admin_footer', array( get_class(), 'admin_hook_styles' ), 5 );
225 2
	}
226
227 2
	/**
228 1
	 * Load the value for each field in the container.
229
	 * Could be used internally during container rendering
230
	 */
231 1
	public function load() {
232 1
		foreach ( $this->fields as $field ) {
233 1
			$field->load();
234 1
		}
235 1
	}
236 1
237
	/**
238 1
	 * Called first as part of the container save procedure.
239 1
	 * Responsible for checking the request validity and
240
	 * calling the container-specific save() method
241
	 *
242
	 * @see save()
243
	 * @see is_valid_save()
244
	 */
245
	public function _save() {
246
		$param = func_get_args();
247
		if ( call_user_func_array( array( $this, 'is_valid_save' ), $param ) ) {
248
			call_user_func_array( array( $this, 'save' ), $param );
249
		}
250
	}
251
252
	/**
253
	 * Load submitted data and save each field in the container
254
	 *
255
	 * @see is_valid_save()
256
	 */
257
	public function save( $data = null ) {
258
		foreach ( $this->fields as $field ) {
259
			$field->set_value_from_input( stripslashes_deep( $_POST ) );
1 ignored issue
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
260
			$field->save();
261
		}
262
	}
263
264
	/**
265
	 * Checks whether the current request is valid
266
	 *
267
	 * @return bool
268
	 */
269
	public function is_valid_save() {
270
		return false;
271
	}
272
273
	/**
274
	 * Called first as part of the container attachment procedure.
275
	 * Responsible for checking it's OK to attach the container
276
	 * and if it is, calling the container-specific attach() method
277
	 *
278
	 * @see attach()
279
	 * @see is_valid_attach()
280
	 */
281
	public function _attach() {
282
		$param = func_get_args();
283
		if ( call_user_func_array( array( $this, 'is_valid_attach' ), $param ) ) {
284
			call_user_func_array( array( $this, 'attach' ), $param );
285
286
			// Allow containers to activate but not load (useful in cases such as theme options)
287
			if ( $this->should_activate() ) {
288
				$this->activate();
289
			}
290
		}
291
	}
292
293
	/**
294
	 * Attach the container rendering and helping methods
295
	 * to concrete WordPress Action hooks
296
	 */
297
	public function attach() {}
298
299
	/**
300
	 * Perform checks whether the container should be attached during the current request
301
	 *
302
	 * @return bool True if the container is allowed to be attached
303
	 */
304
	final public function is_valid_attach() {
305
		$is_valid_attach = $this->is_valid_attach_for_request();
306
		return apply_filters( 'carbon_fields_container_is_valid_attach', $is_valid_attach, $this );
307
	}
308
309
	/**
310
	 * Get environment array for page request (in admin)
311
	 *
312
	 * @return array
313
	 */
314
	abstract protected function get_environment_for_request();
315
316
	/**
317
	 * Check container attachment rules against current page request (in admin)
318
	 *
319
	 * @return bool
320
	 */
321
	abstract protected function is_valid_attach_for_request();
322
323
	/**
324
	 * Check if conditions pass for request
325
	 *
326
	 * @return bool
327
	 */
328
	protected function static_conditions_pass() {
329
		$environment = $this->get_environment_for_request();
330
		$static_condition_collection = $this->condition_collection->evaluate(
1 ignored issue
show
Comprehensibility Naming introduced by
The variable name $static_condition_collection exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
331
			$this->get_condition_types( false ),
332
			true
333
		);
334
		return $static_condition_collection->is_fulfilled( $environment );
335
	}
336
337
	/**
338
	 * Get environment array for object id
339
	 *
340
	 * @param integer $object_id
341
	 * @return array
342
	 */
343
	abstract protected function get_environment_for_object( $object_id );
344
345
	/**
346
	 * Check container attachment rules against object id
347
	 *
348
	 * @param int $object_id
349
	 * @return bool
350
	 */
351
	abstract public function is_valid_attach_for_object( $object_id );
352
353
	/**
354
	 * Check if all conditions pass for object
355
	 *
356
	 * @return bool
357
	 */
358
	protected function all_conditions_pass( $object_id ) {
359
		$environment = $this->get_environment_for_object( $object_id );
360
		return $this->condition_collection->is_fulfilled( $environment );
361
	}
362
363
	/**
364
	 * Whether this container is currently viewed.
365
	 */
366
	public function should_activate() {
367
		return $this->is_valid_attach();
368
	}
369
370
	/**
371
	 * Perform a check whether the current container has fields
372
	 *
373
	 * @return bool
374
	 */
375
	public function has_fields() {
376
		return (bool) $this->fields;
377
	}
378
379
	/**
380
	 * Returns the private container array of fields.
381
	 * Use only if you are completely aware of what you are doing.
382
	 *
383
	 * @return array
384
	 */
385
	public function get_fields() {
386
		return $this->fields;
387
	}
388
389
	/**
390
	 * Return root field from container with specified name
391
	 * 
392
	 * @example crb_complex
393
	 * 
394
	 * @param string $field_name
395
	 * @return Field
396
	 */
397
	public function get_root_field_by_name( $field_name ) {
398
		$fields = $this->get_fields();
399
		foreach ( $fields as $field ) {
400
			if ( $field->get_base_name() === $field_name ) {
401
				return $field;
402
			}
403
		}
404
		return null;
405
	}
406
407
	/**
408
	 * Get a regex to match field name patterns used to fetch specific fields
409
	 * 
410
	 * @return string
411
	 */
412
	protected function get_field_pattern_regex() {
413
		// matches:
414
		// field_name
415
		// field_name[0]
416
		// field_name[0]:group_name
417
		// field_name:group_name
418
		$regex = '/
419
			\A
420
			(?P<field_name>[a-z0-9_]+)
421
			(?:\[(?P<group_index>\d+)\])?
422
			(?:' .  preg_quote( static::HIERARCHY_GROUP_SEPARATOR, '/' ). '(?P<group_name>[a-z0-9_]+))?
423
			\z
424
		/x';
425
		return $regex;
426
	}
427
428
	/**
429
	 * Return field from container with specified name
430
	 * 
431
	 * @example crb_complex/text_field
432
	 * @example crb_complex/complex_2
433
	 * @example crb_complex/complex_2:text_group/text_field
434
	 * 
435
	 * @param string $field_name Can specify a field inside a complex with a / (slash) separator
436
	 * @return Field
437
	 */
438
	public function get_field_by_name( $field_name ) {
439
		$hierarchy = array_filter( explode( static::HIERARCHY_FIELD_SEPARATOR, $field_name ) );
440
		$field = null;
441
442
		$field_group = $this->get_fields();
443
		$hierarchy_left = $hierarchy;
444
		$field_pattern_regex = $this->get_field_pattern_regex();
445
		$hierarchy_index = array();
446
447
		while ( ! empty( $hierarchy_left ) ) {
448
			$segment = array_shift( $hierarchy_left );
449
			$segment_pieces = array();
450
			if ( ! preg_match( $field_pattern_regex, $segment, $segment_pieces ) ) {
451
				Incorrect_Syntax_Exception::raise( 'Invalid field name pattern used: ' . $field_name );
452
			}
453
			
454
			$segment_field_name = $segment_pieces['field_name'];
455
			$segment_group_index = isset( $segment_pieces['group_index'] ) ? $segment_pieces['group_index'] : 0;
456
			$segment_group_name = isset( $segment_pieces['group_name'] ) ? $segment_pieces['group_name'] : Group_Field::DEFAULT_GROUP_NAME;
457
458
			foreach ( $field_group as $f ) {
459
				if ( $f->get_base_name() === $segment_field_name ) {
460
					if ( empty( $hierarchy_left ) ) {
461
						$field = clone $f;
462
						$field->set_hierarchy_index( $hierarchy_index );
463
					} else {
464
						if ( is_a( $f, 'Carbon_Fields\\Field\\Complex_Field' ) ) {
465
							$group = $f->get_group_by_name( $segment_group_name );
466
							if ( ! $group ) {
467
								Incorrect_Syntax_Exception::raise( 'Unknown group name specified when fetching a value inside a complex field: "' . $segment_group_name . '".' );
468
							}
469
							$field_group = $group->get_fields();
470
							$hierarchy_index[] = $segment_group_index;
471
						} else {
472
							Incorrect_Syntax_Exception::raise( 'Attempted to look for a nested field inside a non-complex field.' );
473
						}
474
					}
475
					break;
476
				}
477
			}
478
		}
479
480
		return $field;
481
	}
482
483
	/**
484
	 * Perform checks whether there is a field registered with the name $name.
485
	 * If not, the field name is recorded.
486
	 *
487
	 * @param string $name
488
	 */
489 View Code Duplication
	public function verify_unique_field_name( $name ) {
490
		if ( in_array( $name, $this->registered_field_names ) ) {
491
			Incorrect_Syntax_Exception::raise( 'Field name "' . $name . '" already registered' );
492
		}
493
494
		$this->registered_field_names[] = $name;
495
	}
496
497
	/**
498
	 * Remove field name $name from the list of unique field names
499
	 *
500
	 * @param string $name
501
	 */
502
	public function drop_unique_field_name( $name ) {
503
		$index = array_search( $name, $this->registered_field_names );
504
505
		if ( $index !== false ) {
506
			unset( $this->registered_field_names[ $index ] );
507
		}
508
	}
509
510
	/**
511
	 * Return whether the datastore instance is the default one or has been overriden
512
	 *
513
	 * @return boolean
514
	 */
515
	public function has_default_datastore() {
516
		return $this->has_default_datastore;
517
	}
518
519
	/**
520
	 * Set datastore instance
521
	 *
522
	 * @param Datastore_Interface $datastore
523
	 * @return object $this
524
	 */
525 View Code Duplication
	public function set_datastore( Datastore_Interface $datastore, $set_as_default = false ) {
526
		if ( $set_as_default && ! $this->has_default_datastore() ) {
527
			return $this; // datastore has been overriden with a custom one - abort changing to a default one
528
		}
529
		$this->datastore = $datastore;
530
		$this->has_default_datastore = $set_as_default;
531
532
		foreach ( $this->fields as $field ) {
533
			$field->set_datastore( $this->get_datastore(), true );
534
		}
535
		return $this;
536
	}
537
538 6
	/**
539 6
	 * Get the DataStore instance
540
	 *
541
	 * @return Datastore_Interface $datastore
542
	 */
543
	public function get_datastore() {
544
		return $this->datastore;
545
	}
546
547
	/**
548 6
	 * Return WordPress nonce name used to identify the current container instance
549 6
	 *
550 1
	 * @return string
551
	 */
552 6
	public function get_nonce_name() {
553 6
		return 'carbon_panel_' . $this->id . '_nonce';
554
	}
555 6
556
	/**
557 6
	 * Return WordPress nonce field
558 6
	 *
559
	 * @return string
560
	 */
561
	public function get_nonce_field() {
562
		return wp_nonce_field( $this->get_nonce_name(), $this->get_nonce_name(), /*referer?*/ false, /*echo?*/ false );
563
	}
564
565
	/**
566 6
	 * Check if the nonce is present in the request and that it is verified
567 6
	 *
568
	 * @return bool
569
	 */
570
	protected function verified_nonce_in_request() {
571
		$nonce_name = $this->get_nonce_name();
572
		$nonce_value = isset( $_REQUEST[ $nonce_name ] ) ? $_REQUEST[ $nonce_name ] : '';
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
573
		return wp_verify_nonce( $nonce_value, $nonce_name );
574
	}
575
576
	/**
577
	 * Internal function that creates the tab and associates it with particular field set
578
	 *
579
	 * @param string $tab_name
580
	 * @param array $fields
581
	 * @param int $queue_end
582
	 * @return object $this
583
	 */
584
	private function create_tab( $tab_name, $fields, $queue_end = self::TABS_TAIL ) {
585
		if ( isset( $this->tabs[ $tab_name ] ) ) {
586
			Incorrect_Syntax_Exception::raise( "Tab name duplication for $tab_name" );
587
		}
588
589
		if ( $queue_end === static::TABS_TAIL ) {
590
			$this->tabs[ $tab_name ] = array();
591
		} else if ( $queue_end === static::TABS_HEAD ) {
592
			$this->tabs = array_merge(
593
				array( $tab_name => array() ),
594
				$this->tabs
595
			);
596
		}
597
598
		foreach ( $fields as $field ) {
599
			$field_name = $field->get_name();
600
			$this->tabs[ $tab_name ][ $field_name ] = $field;
601
		}
602
603
		$this->settings['tabs'] = $this->get_tabs_json();
604
	}
605
606
	/**
607
	 * Whether the container is tabbed or not
608
	 *
609
	 * @return bool
610
	 */
611
	public function is_tabbed() {
612
		return (bool) $this->tabs;
613
	}
614
615
	/**
616
	 * Retrieve all fields that are not defined under a specific tab
617
	 *
618
	 * @return array
619
	 */
620
	protected function get_untabbed_fields() {
621
		$tabbed_fields_names = array();
622
		foreach ( $this->tabs as $tab_fields ) {
623
			$tabbed_fields_names = array_merge( $tabbed_fields_names, array_keys( $tab_fields ) );
624
		}
625
626
		$all_fields_names = array();
627
		foreach ( $this->fields as $field ) {
628
			$all_fields_names[] = $field->get_name();
629
		}
630
631
		$fields_not_in_tabs = array_diff( $all_fields_names, $tabbed_fields_names );
632
633
		$untabbed_fields = array();
634
		foreach ( $this->fields as $field ) {
635
			if ( in_array( $field->get_name(), $fields_not_in_tabs ) ) {
636
				$untabbed_fields[] = $field;
637
			}
638
		}
639
640
		return $untabbed_fields;
641
	}
642
643
	/**
644
	 * Retrieve all tabs.
645
	 * Create a default tab if there are any untabbed fields.
646
	 *
647
	 * @return array
648
	 */
649
	protected function get_tabs() {
650
		$untabbed_fields = $this->get_untabbed_fields();
651
652
		if ( ! empty( $untabbed_fields ) ) {
653
			$this->create_tab( __( 'General', \Carbon_Fields\TEXT_DOMAIN ), $untabbed_fields, static::TABS_HEAD );
654
		}
655
656
		return $this->tabs;
657
	}
658
659
	/**
660
	 * Build the tabs JSON
661
	 *
662
	 * @return array
663
	 */
664
	protected function get_tabs_json() {
665
		$tabs_json = array();
666
		$tabs = $this->get_tabs();
667
668
		foreach ( $tabs as $tab_name => $fields ) {
669
			foreach ( $fields as $field_name => $field ) {
670
				$tabs_json[ $tab_name ][] = $field_name;
671
			}
672
		}
673
674
		return $tabs_json;
675
	}
676
677
	/**
678
	 * Returns an array that holds the container data, suitable for JSON representation.
679
	 *
680
	 * @param bool $load  Should the value be loaded from the database or use the value from the current instance.
681
	 * @return array
682
	 */
683
	public function to_json( $load ) {
684
		$array_translator = App::resolve( 'container_condition_translator_array' );
685
		$dynamic_conditions = $this->condition_collection->evaluate( $this->get_condition_types( true ), $this->get_environment_for_request() );
686
		$dynamic_conditions = $array_translator->fulfillable_to_foreign( $dynamic_conditions );
687
688
		$container_data = array(
689
			'id' => $this->id,
690
			'type' => $this->type,
691
			'title' => $this->title,
692
			'settings' => $this->settings,
693
			'dynamic_conditions' => $dynamic_conditions,
694
			'fields' => array(),
695
		);
696
697
		$fields = $this->get_fields();
698
		foreach ( $fields as $field ) {
699
			$field_data = $field->to_json( $load );
700
			$container_data['fields'][] = $field_data;
701
		}
702
703
		return $container_data;
704
	}
705
706
	/**
707
	 * Enqueue admin styles
708
	 */
709
	public static function admin_hook_styles() {
710
		wp_enqueue_style( 'carbon-main', \Carbon_Fields\URL . '/assets/bundle.css', array(), \Carbon_Fields\VERSION );
711
	}
712
713
	/**
714
	 * COMMON USAGE METHODS
715
	 */
716
717
	/**
718
	 * Append array of fields to the current fields set. All items of the array
719
	 * must be instances of Field and their names should be unique for all
720
	 * Carbon containers.
721
	 * If a field does not have DataStore already, the container datastore is
722
	 * assigned to them instead.
723
	 *
724
	 * @param array $fields
725
	 * @return object $this
726
	 */
727
	public function add_fields( $fields ) {
728
		foreach ( $fields as $field ) {
729
			if ( ! is_a( $field, 'Carbon_Fields\\Field\\Field' ) ) {
730
				Incorrect_Syntax_Exception::raise( 'Object must be of type Carbon_Fields\\Field\\Field' );
731
			}
732
733
			$this->verify_unique_field_name( $field->get_name() );
734
735
			$field->set_context( $this->type );
736
			if ( ! $field->get_datastore() ) {
737
				$field->set_datastore( $this->get_datastore(), $this->has_default_datastore() );
738
			}
739
		}
740
741
		$this->fields = array_merge( $this->fields, $fields );
742
743
		return $this;
744
	}
745
746
	/**
747
	 * Configuration function for adding tab with fields
748
	 *
749
	 * @param string $tab_name
750
	 * @param array $fields
751
	 * @return object $this
752
	 */
753
	public function add_tab( $tab_name, $fields ) {
754
		$this->add_fields( $fields );
755
		$this->create_tab( $tab_name, $fields );
756
		return $this;
757
	}
758
759
	/**
760
	 * Proxy function to set attachment conditions
761
	 * 
762
	 * @see    Fulfillable_Collection::when()
763
	 * @return Container $this
764
	 */
765
	public function when() {
766
		call_user_func_array( array( $this->condition_collection, 'when' ), func_get_args() );
767
		return $this;
768
	}
769
770
	/**
771
	 * Proxy function to set attachment conditions
772
	 * 
773
	 * @see    Fulfillable_Collection::and_when()
774
	 * @return Container $this
775
	 */
776
	public function and_when() {
777
		call_user_func_array( array( $this->condition_collection, 'and_when' ), func_get_args() );
778
		return $this;
779
	}
780
781
	/**
782
	 * Proxy function to set attachment conditions
783
	 * 
784
	 * @see    Fulfillable_Collection::or_when()
785
	 * @return Container $this
786
	 */
787
	public function or_when() {
788
		call_user_func_array( array( $this->condition_collection, 'or_when' ), func_get_args() );
789
		return $this;
790
	}
791
}
792