Completed
Pull Request — master (#193)
by
unknown
09:54
created

Updater::update_field()   B

Complexity

Conditions 6
Paths 12

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 16
nc 12
nop 5
dl 0
loc 25
rs 8.439
c 0
b 0
f 0
1
<?php 
2
namespace Carbon_Fields\Updater;
3
4
use Carbon_Fields\Container\Container;
5
use Carbon_Fields\Container\Container_Validator;
6
use Carbon_Fields\Helper\Helper;
7
8
/**
9
* Class for updating meta data/theme options
10
*/
11
class Updater {
12
13
	/**
14
	 * Relevant containers
15
	 * 
16
	 * @var arrat
17
	 */
18
	public static $containers;
19
20
	/**
21
	 * Instance of the Container_Validator class
22
	 * 
23
	 * @var object
24
	 */
25
	public static $validator;
26
27
	/**
28
	 * The fields that belong
29
	 * to the $containers
30
	 * 
31
	 * @var array
32
	 */
33
	public static $fields;
34
35
	/**
36
	 * Map for classes parsing
37
	 * special input types
38
	 * 
39
	 * @var array
40
	 */
41
	public static $value_types = array(
42
		'complex'          => 'Complex_Value_Parser',
43
		'association'      => 'Association_Value_Parser',
44
		'map'              => 'Map_Value_Parser',
45
		'map_with_address' => 'Map_Value_Parser',
46
	);
47
48
	/**
49
	 * Flag indicating whether the update call
50
	 * is initialized by a REST request
51
	 * 
52
	 * @var boolean
53
	 */
54
	public static $is_rest_request = false;
55
56
	/**
57
	 * Load containers and fields, based on params
58
	 * 
59
	 * @param  string $context   
60
	 * @param  string $object_id 
61
	 */
62
	public static function boot( $context, $object_id = '' ) {
63
		self::$validator = new Container_Validator();
64
		self::load_containers( $context, $object_id );
65
		self::load_fields();
66
	}
67
68
	/**
69
	 * Update Carbon Field
70
	 * 
71
	 * @param  string $context    post_meta|term_meta|user_meta|comment_meta|theme_option
72
	 * @param  string $object_id  
73
	 * @param  string $field_name 
74
	 * @param  mixed $input       string|array|json
75
	 * @param  string $value_type complex|map|map_with_address|association|null
76
	 */
77
	public static function update_field( $context, $object_id = '', $field_name, $input, $value_type = null ) {
78
		self::boot( $context, $object_id );
79
80
		$is_option    = true;
81
		$field_name   = $object_id ? Helper::prepare_meta_name( $field_name ) : $field_name;
82
		$carbon_field = self::get_field_by_name( $field_name );
83
84
		if ( $object_id ) {
85
			$carbon_field->get_datastore()->set_id( $object_id );
86
			$is_option = false;
87
		}	
88
89
		$carbon_field_type  = strtolower( $carbon_field->type );
90
91
		if ( $value_type && ( $carbon_field_type !== $value_type ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $value_type of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
92
			throw new \Exception( printf( __( 'The field <strong>%s</strong> is of type <strong>%s</strong>. You are passing <strong>%s</strong> value.', 'crb' ), $field_name, $carbon_field_type, $value_type ) );
93
		}
94
95
		$input = self::maybe_json_decode( $input );
96
		$class = __NAMESPACE__ . '\\' . ( isset( self::$value_types[ $carbon_field_type ] ) ? self::$value_types[ $carbon_field_type ] : 'Value_Parser' );
97
		$input = $class::parse( $input, $is_option );
98
99
		$carbon_field->set_value_from_input( array( $field_name => $input ) );
100
		$carbon_field->save();
101
	}
102
103
	/**
104
	 * Load all appropriate containers
105
	 * 
106
	 * @param  string $type
107
	 * @param  string $id  
108
	 */
109
	public static function load_containers( $type, $id = '' ) {
110
		if ( empty( Container::$active_containers ) ) {
111
			do_action( 'carbon_trigger_containers_attach' );
112
		}
113
114
		$type = self::normalize_type( $type );
115
116
		self::$containers = array_filter( Container::$active_containers, function( $container ) use ( $type, $id ) {
0 ignored issues
show
Documentation Bug introduced by
It seems like array_filter(\Carbon_Fie...::$is_rest_request); }) of type array is incompatible with the declared type object<Carbon_Fields\Updater\arrat> of property $containers.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
117
			return self::$validator->is_valid_container( $container, $type, $id, self::$is_rest_request );
118
		} );
119
	}
120
121
	/**
122
	 * Extract all fields
123
	 * from the containers
124
	 */
125
	public static function load_fields() {
126
		$fields = array_map( function( $container ) {
127
			return $container->get_fields();
128
		}, self::$containers );
129
130
		self::$fields = call_user_func_array( 'array_merge', $fields );
0 ignored issues
show
Documentation Bug introduced by
It seems like call_user_func_array('array_merge', $fields) of type * is incompatible with the declared type array of property $fields.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
131
	}
132
133
	/**
134
	 * Retrieve Carbon Field by name
135
	 * 
136
	 * @param  string $field_name 
137
	 * @return object
138
	 */
139
	public static function get_field_by_name( $field_name ) {
140
		$field_array = array_filter( self::$fields, function( $field ) use ( $field_name ) { 
141
			return $field->get_name() === $field_name;
142
		} );
143
144
		if ( empty( $field_array ) ) {
145
			throw new \Exception( sprintf( __( 'There is no <strong>%s</strong> Carbon Field.', 'crb' ), $field_name ) );
146
		}
147
148
		return array_pop( $field_array );
149
	}
150
151
	/**
152
	 * Normalize type
153
	 * 
154
	 * @param  string $type 
155
	 * @return string       
156
	 */
157
	public static function normalize_type( $type ) {
158
		$type = Helper::prepare_data_type_name( $type );
159
160
		if ( $type === 'Theme_Option' ) {
161
			$type = 'Theme_Options';
162
		}
163
164
		return $type;
165
	}
166
167
	/**
168
	 * Decode json
169
	 * 
170
	 * @param  mixed $maybe_json
171
	 * @return array
172
	 */
173
	public static function maybe_json_decode( $maybe_json ) {
174
		if ( self::is_json( $maybe_json ) ) {
175
			return json_decode( $maybe_json );
176
		}
177
178
		return $maybe_json;
179
	}
180
181
	/**
182
	 * is_json
183
	 * 
184
	 * @param  string  $string
185
	 * @return boolean       
186
	 */
187
	public static function is_json( $string ) {
188
		return is_string( $string ) && is_array( json_decode( $string, true ) ) && ( json_last_error() === JSON_ERROR_NONE ) ? true : false;
189
	}
190
}