CMB2_REST_Controller_Fields   C
last analyzed

Complexity

Total Complexity 53

Size/Duplication

Total Lines 482
Duplicated Lines 0 %

Test Coverage

Coverage 94.08%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 53
eloc 153
c 1
b 0
f 0
dl 0
loc 482
ccs 143
cts 152
cp 0.9408
rs 6.96

17 Methods

Rating   Name   Duplication   Size   Complexity  
A delete_item() 0 4 1
A prepare_field_response() 0 7 1
A get_item_permissions_check_filter() 0 10 1
A get_items_permissions_check() 0 13 1
A update_item() 0 10 2
A prepare_read_field() 0 10 2
A maybe_hook_registered_callback() 0 13 3
A get_item_permissions_check() 0 7 2
A maybe_unhook_registered_callback() 0 6 2
A delete_item_permissions_check() 0 17 2
A update_item_permissions_check() 0 17 2
A get_items() 0 25 6
B modify_field_value() 0 33 8
A get_item() 0 8 2
A register_routes() 0 53 1
C prepare_field_data() 0 49 16
A prepare_links() 0 18 1

How to fix   Complexity   

Complex Class

Complex classes like CMB2_REST_Controller_Fields often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CMB2_REST_Controller_Fields, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * CMB2 objects/fields endpoint for WordPres REST API.
4
 * Allows access to fields registered to a specific box.
5
 *
6
 * @todo  Add better documentation.
7
 * @todo  Research proper schema.
8
 *
9
 * @since 2.2.3
10
 *
11
 * @category  WordPress_Plugin
12
 * @package   CMB2
13
 * @author    CMB2 team
14
 * @license   GPL-2.0+
15
 * @link      https://cmb2.io
16
 */
17
class CMB2_REST_Controller_Fields extends CMB2_REST_Controller_Boxes {
18
19
	/**
20
	 * Register the routes for the objects of the controller.
21
	 *
22
	 * @since 2.2.3
23
	 */
24 1
	public function register_routes() {
25
		$args = array(
26
			'_embed' => array(
27 1
				'description' => __( 'Includes the box object which the fields are registered to in the response.', 'cmb2' ),
0 ignored issues
show
Bug introduced by
The function __ was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

27
				'description' => /** @scrutinizer ignore-call */ __( 'Includes the box object which the fields are registered to in the response.', 'cmb2' ),
Loading history...
28
			),
29
			'_rendered' => array(
30 1
				'description' => __( 'When the \'_rendered\' argument is passed, the renderable field attributes will be returned fully rendered. By default, the names of the callback handers for the renderable attributes will be returned.', 'cmb2' ),
31
			),
32
			'object_id' => array(
33 1
				'description' => __( 'To view or modify the field\'s value, the \'object_id\' and \'object_type\' arguments are required.', 'cmb2' ),
34
			),
35
			'object_type' => array(
36 1
				'description' => __( 'To view or modify the field\'s value, the \'object_id\' and \'object_type\' arguments are required.', 'cmb2' ),
37
			),
38
		);
39
40
		// Returns specific box's fields.
41 1
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<cmb_id>[\w-]+)/fields/', array(
0 ignored issues
show
Bug introduced by
The function register_rest_route was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

41
		/** @scrutinizer ignore-call */ 
42
  register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<cmb_id>[\w-]+)/fields/', array(
Loading history...
42
			array(
43 1
				'methods'             => WP_REST_Server::READABLE,
0 ignored issues
show
Bug introduced by
The type WP_REST_Server was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
44 1
				'permission_callback' => array( $this, 'get_items_permissions_check' ),
45 1
				'callback'            => array( $this, 'get_items' ),
46 1
				'args'                => $args,
47
			),
48 1
			'schema' => array( $this, 'get_item_schema' ),
49
		) );
50
51 1
		$delete_args = $args;
52 1
		$delete_args['object_id']['required'] = true;
53 1
		$delete_args['object_type']['required'] = true;
54
55
		// Returns specific field data.
56 1
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<cmb_id>[\w-]+)/fields/(?P<field_id>[\w-]+)', array(
57
			array(
58 1
				'methods'             => WP_REST_Server::READABLE,
59 1
				'permission_callback' => array( $this, 'get_item_permissions_check' ),
60 1
				'callback'            => array( $this, 'get_item' ),
61 1
				'args'                => $args,
62
			),
63
			array(
64
				'methods'             => WP_REST_Server::EDITABLE,
65 1
				'permission_callback' => array( $this, 'update_item_permissions_check' ),
66 1
				'callback'            => array( $this, 'update_item' ),
67 1
				'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
68 1
				'args'                => $args,
69
			),
70
			array(
71
				'methods'             => WP_REST_Server::DELETABLE,
72 1
				'permission_callback' => array( $this, 'delete_item_permissions_check' ),
73 1
				'callback'            => array( $this, 'delete_item' ),
74 1
				'args'                => $delete_args,
75
			),
76 1
			'schema' => array( $this, 'get_item_schema' ),
77
		) );
78 1
	}
79
80
	/**
81
	 * Check if a given request has access to get fields.
82
	 * By default, no special permissions needed, but filtering return value.
83
	 *
84
	 * @since 2.2.3
85
	 *
86
	 * @param  WP_REST_Request $request Full data about the request.
0 ignored issues
show
Bug introduced by
The type WP_REST_Request was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
87
	 * @return WP_Error|boolean
88
	 */
89 1
	public function get_items_permissions_check( $request ) {
90 1
		$this->initiate_rest_read_box( $request, 'fields_read' );
91 1
		$can_access = true;
92
93
		/**
94
		 * By default, no special permissions needed.
95
		 *
96
		 * @since 2.2.3
97
		 *
98
		 * @param bool   $can_access Whether this CMB2 endpoint can be accessed.
99
		 * @param object $controller This CMB2_REST_Controller object.
100
		 */
101 1
		return $this->maybe_hook_callback_and_apply_filters( 'cmb2_api_get_fields_permissions_check', $can_access );
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->maybe_hook_callba...ns_check', $can_access) targeting CMB2_REST_Controller::ma...ack_and_apply_filters() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
102
	}
103
104
	/**
105
	 * Get all public CMB2 box fields.
106
	 *
107
	 * @since 2.2.3
108
	 *
109
	 * @param  WP_REST_Request $request Full data about the request.
110
	 * @return WP_Error|WP_REST_Response
0 ignored issues
show
Bug introduced by
The type WP_REST_Response was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
111
	 */
112 1
	public function get_items( $request ) {
113 1
		if ( ! $this->rest_box ) {
114
			$this->initiate_rest_read_box( $request, 'fields_read' );
115
		}
116
117 1
		if ( is_wp_error( $this->rest_box ) ) {
0 ignored issues
show
Bug introduced by
The function is_wp_error was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

117
		if ( /** @scrutinizer ignore-call */ is_wp_error( $this->rest_box ) ) {
Loading history...
118
			return $this->rest_box;
119
		}
120
121 1
		$fields = array();
122 1
		foreach ( $this->rest_box->cmb->prop( 'fields', array() ) as $field ) {
123
124
			// Make sure this field can be read.
125 1
			$this->field = $this->rest_box->field_can_read( $field['id'], true );
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->rest_box->field_c...ead($field['id'], true) can also be of type false. However, the property $field is declared as type CMB2_Field. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
126
127
			// And make sure current user can view this box.
128 1
			if ( $this->field && $this->get_item_permissions_check_filter() ) {
129 1
				$fields[ $field['id'] ] = $this->server->response_to_data(
130 1
					$this->prepare_field_response(),
131 1
					isset( $this->request['_embed'] )
132
				);
133
			}
134
		}
135
136 1
		return $this->prepare_item( $fields );
137
	}
138
139
	/**
140
	 * Check if a given request has access to a field.
141
	 * By default, no special permissions needed, but filtering return value.
142
	 *
143
	 * @since 2.2.3
144
	 *
145
	 * @param  WP_REST_Request $request Full details about the request.
146
	 * @return WP_Error|boolean
147
	 */
148 4
	public function get_item_permissions_check( $request ) {
149 4
		$this->initiate_rest_read_box( $request, 'field_read' );
150 4
		if ( ! is_wp_error( $this->rest_box ) ) {
0 ignored issues
show
Bug introduced by
The function is_wp_error was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

150
		if ( ! /** @scrutinizer ignore-call */ is_wp_error( $this->rest_box ) ) {
Loading history...
151 4
			$this->field = $this->rest_box->field_can_read( $this->request->get_param( 'field_id' ), true );
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->rest_box->field_c...aram('field_id'), true) can also be of type false. However, the property $field is declared as type CMB2_Field. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
152
		}
153
154 4
		return $this->get_item_permissions_check_filter();
155
	}
156
157
	/**
158
	 * Check by filter if a given request has access to a field.
159
	 * By default, no special permissions needed, but filtering return value.
160
	 *
161
	 * @since 2.2.3
162
	 *
163
	 * @param  bool $can_access Whether the current request has access to view the field by default.
164
	 * @return WP_Error|boolean
165
	 */
166 5
	public function get_item_permissions_check_filter( $can_access = true ) {
167
		/**
168
		 * By default, no special permissions needed.
169
		 *
170
		 * @since 2.2.3
171
		 *
172
		 * @param bool   $can_access Whether this CMB2 endpoint can be accessed.
173
		 * @param object $controller This CMB2_REST_Controller object.
174
		 */
175 5
		return $this->maybe_hook_callback_and_apply_filters( 'cmb2_api_get_field_permissions_check', $can_access );
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->maybe_hook_callba...ns_check', $can_access) targeting CMB2_REST_Controller::ma...ack_and_apply_filters() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
176
	}
177
178
	/**
179
	 * Get one CMB2 field from the collection.
180
	 *
181
	 * @since 2.2.3
182
	 *
183
	 * @param  WP_REST_Request $request Full data about the request.
184
	 * @return WP_Error|WP_REST_Response
185
	 */
186 2
	public function get_item( $request ) {
187 2
		$this->initiate_rest_read_box( $request, 'field_read' );
188
189 2
		if ( is_wp_error( $this->rest_box ) ) {
0 ignored issues
show
Bug introduced by
The function is_wp_error was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

189
		if ( /** @scrutinizer ignore-call */ is_wp_error( $this->rest_box ) ) {
Loading history...
190
			return $this->rest_box;
191
		}
192
193 2
		return $this->prepare_read_field( $this->request->get_param( 'field_id' ) );
194
	}
195
196
	/**
197
	 * Check if a given request has access to update a field value.
198
	 * By default, requires 'edit_others_posts' capability, but filtering return value.
199
	 *
200
	 * @since 2.2.3
201
	 *
202
	 * @param  WP_REST_Request $request Full details about the request.
203
	 * @return WP_Error|boolean
204
	 */
205 5
	public function update_item_permissions_check( $request ) {
206 5
		$this->initiate_rest_read_box( $request, 'field_value_update' );
207 5
		if ( ! is_wp_error( $this->rest_box ) ) {
0 ignored issues
show
Bug introduced by
The function is_wp_error was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

207
		if ( ! /** @scrutinizer ignore-call */ is_wp_error( $this->rest_box ) ) {
Loading history...
208 5
			$this->field = $this->rest_box->field_can_edit( $this->request->get_param( 'field_id' ), true );
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->rest_box->field_c...aram('field_id'), true) can also be of type false. However, the property $field is declared as type CMB2_Field. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
209
		}
210
211 5
		$can_update = current_user_can( 'edit_others_posts' );
0 ignored issues
show
Bug introduced by
The function current_user_can was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

211
		$can_update = /** @scrutinizer ignore-call */ current_user_can( 'edit_others_posts' );
Loading history...
212
213
		/**
214
		 * By default, 'edit_others_posts' is required capability.
215
		 *
216
		 * @since 2.2.3
217
		 *
218
		 * @param bool   $can_update Whether this CMB2 endpoint can be accessed.
219
		 * @param object $controller This CMB2_REST_Controller object.
220
		 */
221 5
		return $this->maybe_hook_callback_and_apply_filters( 'cmb2_api_update_field_value_permissions_check', $can_update );
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->maybe_hook_callba...ns_check', $can_update) targeting CMB2_REST_Controller::ma...ack_and_apply_filters() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
222
	}
223
224
	/**
225
	 * Update CMB2 field value.
226
	 *
227
	 * @since 2.2.3
228
	 *
229
	 * @param  WP_REST_Request $request Full data about the request.
230
	 * @return WP_Error|WP_REST_Response
231
	 */
232 2
	public function update_item( $request ) {
233 2
		$this->initiate_rest_read_box( $request, 'field_value_update' );
234
235 2
		if ( ! $this->request['value'] ) {
236 1
			return new WP_Error( 'cmb2_rest_update_field_error', __( 'CMB2 Field value cannot be updated without the value parameter specified.', 'cmb2' ), array(
0 ignored issues
show
Bug introduced by
The function __ was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

236
			return new WP_Error( 'cmb2_rest_update_field_error', /** @scrutinizer ignore-call */ __( 'CMB2 Field value cannot be updated without the value parameter specified.', 'cmb2' ), array(
Loading history...
237 1
				'status' => 400,
238
			) );
239
		}
240
241 2
		return $this->modify_field_value( 'updated' );
242
	}
243
244
	/**
245
	 * Check if a given request has access to delete a field value.
246
	 * By default, requires 'delete_others_posts' capability, but filtering return value.
247
	 *
248
	 * @since 2.2.3
249
	 *
250
	 * @param  WP_REST_Request $request Full details about the request.
251
	 * @return WP_Error|boolean
252
	 */
253 3
	public function delete_item_permissions_check( $request ) {
254 3
		$this->initiate_rest_read_box( $request, 'field_value_delete' );
255 3
		if ( ! is_wp_error( $this->rest_box ) ) {
0 ignored issues
show
Bug introduced by
The function is_wp_error was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

255
		if ( ! /** @scrutinizer ignore-call */ is_wp_error( $this->rest_box ) ) {
Loading history...
256 3
			$this->field = $this->rest_box->field_can_edit( $this->request->get_param( 'field_id' ), true );
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->rest_box->field_c...aram('field_id'), true) can also be of type false. However, the property $field is declared as type CMB2_Field. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
257
		}
258
259 3
		$can_delete = current_user_can( 'delete_others_posts' );
0 ignored issues
show
Bug introduced by
The function current_user_can was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

259
		$can_delete = /** @scrutinizer ignore-call */ current_user_can( 'delete_others_posts' );
Loading history...
260
261
		/**
262
		 * By default, 'delete_others_posts' is required capability.
263
		 *
264
		 * @since 2.2.3
265
		 *
266
		 * @param bool   $can_delete Whether this CMB2 endpoint can be accessed.
267
		 * @param object $controller This CMB2_REST_Controller object.
268
		 */
269 3
		return $this->maybe_hook_callback_and_apply_filters( 'cmb2_api_delete_field_value_permissions_check', $can_delete );
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->maybe_hook_callba...ns_check', $can_delete) targeting CMB2_REST_Controller::ma...ack_and_apply_filters() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
270
	}
271
272
	/**
273
	 * Delete CMB2 field value.
274
	 *
275
	 * @since 2.2.3
276
	 *
277
	 * @param  WP_REST_Request $request Full data about the request.
278
	 * @return WP_Error|WP_REST_Response
279
	 */
280 1
	public function delete_item( $request ) {
281 1
		$this->initiate_rest_read_box( $request, 'field_value_delete' );
282
283 1
		return $this->modify_field_value( 'deleted' );
284
	}
285
286
	/**
287
	 * Modify CMB2 field value.
288
	 *
289
	 * @since 2.2.3
290
	 *
291
	 * @param  string $activity The modification activity (updated or deleted).
292
	 * @return WP_Error|WP_REST_Response
293
	 */
294 3
	public function modify_field_value( $activity ) {
295
296 3
		if ( ! $this->request['object_id'] || ! $this->request['object_type'] ) {
297 1
			return new WP_Error( 'cmb2_rest_modify_field_value_error', __( 'CMB2 Field value cannot be modified without the object_id and object_type parameters specified.', 'cmb2' ), array(
0 ignored issues
show
Bug introduced by
The function __ was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

297
			return new WP_Error( 'cmb2_rest_modify_field_value_error', /** @scrutinizer ignore-call */ __( 'CMB2 Field value cannot be modified without the object_id and object_type parameters specified.', 'cmb2' ), array(
Loading history...
298 1
				'status' => 400,
299
			) );
300
		}
301
302 2
		if ( is_wp_error( $this->rest_box ) ) {
0 ignored issues
show
Bug introduced by
The function is_wp_error was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

302
		if ( /** @scrutinizer ignore-call */ is_wp_error( $this->rest_box ) ) {
Loading history...
303
			return $this->rest_box;
304
		}
305
306 2
		$this->field = $this->rest_box->field_can_edit(
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->rest_box->field_c...aram('field_id'), true) can also be of type false. However, the property $field is declared as type CMB2_Field. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
307 2
			$this->field ? $this->field : $this->request->get_param( 'field_id' ),
308 2
			true
309
		);
310
311 2
		if ( ! $this->field ) {
312
			return new WP_Error( 'cmb2_rest_no_field_by_id_error', __( 'No field found by that id.', 'cmb2' ), array(
313
				'status' => 403,
314
			) );
315
		}
316
317 2
		$this->field->args[ "value_{$activity}" ] = (bool) 'deleted' === $activity
0 ignored issues
show
introduced by
The condition (bool)'deleted' === $activity is always false.
Loading history...
318
			? $this->field->remove_data()
319 2
			: $this->field->save_field( $this->request['value'] );
320
321
		// If options page, save the $activity options
322 2
		if ( 'options-page' == $this->request['object_type'] ) {
323
			$this->field->args[ "value_{$activity}" ] = cmb2_options( $this->request['object_id'] )->set();
324
		}
325
326 2
		return $this->prepare_read_field( $this->field );
327
	}
328
329
	/**
330
	 * Get a response object for a specific field ID.
331
	 *
332
	 * @since 2.2.3
333
	 *
334
	 * @param  string\CMB2_Field Field id or Field object.
0 ignored issues
show
Bug introduced by
The type Field was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
335
	 * @return WP_Error|WP_REST_Response
336
	 */
337 4
	public function prepare_read_field( $field ) {
338 4
		$this->field = $this->rest_box->field_can_read( $field, true );
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->rest_box->field_can_read($field, true) can also be of type false. However, the property $field is declared as type CMB2_Field. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
339
340 4
		if ( ! $this->field ) {
341 1
			return new WP_Error( 'cmb2_rest_no_field_by_id_error', __( 'No field found by that id.', 'cmb2' ), array(
0 ignored issues
show
Bug introduced by
The function __ was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

341
			return new WP_Error( 'cmb2_rest_no_field_by_id_error', /** @scrutinizer ignore-call */ __( 'No field found by that id.', 'cmb2' ), array(
Loading history...
342 1
				'status' => 403,
343
			) );
344
		}
345
346 4
		return $this->prepare_item( $this->prepare_field_response() );
347
	}
348
349
	/**
350
	 * Get a specific field response.
351
	 *
352
	 * @since 2.2.3
353
	 *
354
	 * @param  CMB2_Field Field object.
355
	 * @return array      Response array.
356
	 */
357 5
	public function prepare_field_response() {
358 5
		$field_data = $this->prepare_field_data( $this->field );
359 5
		$response = rest_ensure_response( $field_data );
0 ignored issues
show
Bug introduced by
The function rest_ensure_response was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

359
		$response = /** @scrutinizer ignore-call */ rest_ensure_response( $field_data );
Loading history...
360
361 5
		$response->add_links( $this->prepare_links( $this->field ) );
362
363 5
		return $response;
364
	}
365
366
	/**
367
	 * Prepare the field data array for JSON.
368
	 *
369
	 * @since  2.2.3
370
	 *
371
	 * @param  CMB2_Field $field field object.
372
	 *
373
	 * @return array             Array of field data.
374
	 */
375 5
	protected function prepare_field_data( CMB2_Field $field ) {
376 5
		$field_data = array();
377 5
		$params_to_ignore = array( 'show_in_rest', 'options' );
378
		$params_to_rename = array(
379 5
			'label_cb' => 'label',
380
			'options_cb' => 'options',
381
		);
382
383
		// Run this first so the js_dependencies arg is populated.
384 5
		$rendered = ( $cb = $field->maybe_callback( 'render_row_cb' ) )
385
			// Ok, callback is good, let's run it.
386 5
			? $this->get_cb_results( $cb, $field->args(), $field )
387 5
			: false;
388
389 5
		$field_args = $field->args();
390
391 5
		foreach ( $field_args as $key => $value ) {
392 5
			if ( in_array( $key, $params_to_ignore, true ) ) {
393 5
				continue;
394
			}
395
396 5
			if ( 'options_cb' === $key ) {
397 5
				$value = $field->options();
398 5
			} elseif ( in_array( $key, CMB2_Field::$callable_fields, true ) ) {
399
400 5
				if ( isset( $this->request['_rendered'] ) ) {
401
					$value = $key === 'render_row_cb' ? $rendered : $field->get_param_callback_result( $key );
402 5
				} elseif ( is_array( $value ) ) {
403
					// We need to rewrite callbacks as string as they will cause
404
					// JSON recursion errors.
405 5
					$class = is_string( $value[0] ) ? $value[0] : get_class( $value[0] );
406 5
					$value = $class . '::' . $value[1];
407
				}
408
			}
409
410 5
			$key = isset( $params_to_rename[ $key ] ) ? $params_to_rename[ $key ] : $key;
411
412 5
			if ( empty( $value ) || is_scalar( $value ) || is_array( $value ) ) {
413 5
				$field_data[ $key ] = $value;
414
			} else {
415 5
				$field_data[ $key ] = sprintf( __( 'Value Error for %s', 'cmb2' ), $key );
0 ignored issues
show
Bug introduced by
The function __ was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

415
				$field_data[ $key ] = sprintf( /** @scrutinizer ignore-call */ __( 'Value Error for %s', 'cmb2' ), $key );
Loading history...
416
			}
417
		}
418
419 5
		if ( $this->request['object_id'] && $this->request['object_type'] ) {
420 3
			$field_data['value'] = $field->get_rest_value();
421
		}
422
423 5
		return $field_data;
424
	}
425
426
	/**
427
	 * Return an array of contextual links for field/fields.
428
	 *
429
	 * @since  2.2.3
430
	 *
431
	 * @param  CMB2_Field $field Field object to build links from.
432
	 *
433
	 * @return array             Array of links
434
	 */
435 5
	protected function prepare_links( $field ) {
436 5
		$boxbase      = $this->namespace_base . '/' . $this->rest_box->cmb->cmb_id;
437 5
		$query_string = $this->get_query_string();
438
439
		$links = array(
440 5
			'self' => array(
441 5
				'href' => rest_url( trailingslashit( $boxbase ) . 'fields/' . $field->_id() . $query_string ),
0 ignored issues
show
Bug introduced by
The function trailingslashit was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

441
				'href' => rest_url( /** @scrutinizer ignore-call */ trailingslashit( $boxbase ) . 'fields/' . $field->_id() . $query_string ),
Loading history...
Bug introduced by
The function rest_url was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

441
				'href' => /** @scrutinizer ignore-call */ rest_url( trailingslashit( $boxbase ) . 'fields/' . $field->_id() . $query_string ),
Loading history...
442
			),
443
			'collection' => array(
444 5
				'href' => rest_url( trailingslashit( $boxbase ) . 'fields' . $query_string ),
445
			),
446
			'up' => array(
447
				'embeddable' => true,
448 5
				'href' => rest_url( $boxbase . $query_string ),
449
			),
450
		);
451
452 5
		return $links;
453
	}
454
455
	/**
456
	 * Checks if the CMB2 box or field has any registered callback parameters for the given filter.
457
	 *
458
	 * The registered handlers will have a property name which matches the filter, except:
459
	 * - The 'cmb2_api' prefix will be removed
460
	 * - A '_cb' suffix will be added (to stay inline with other '*_cb' parameters).
461
	 *
462
	 * @since  2.2.3
463
	 *
464
	 * @param  string $filter      The filter name.
465
	 * @param  bool   $default_val The default filter value.
466
	 *
467
	 * @return bool                The possibly-modified filter value (if the _cb param is a non-callable).
468
	 */
469 10
	public function maybe_hook_registered_callback( $filter, $default_val ) {
470 10
		$default_val = parent::maybe_hook_registered_callback( $filter, $default_val );
471
472 10
		if ( $this->field ) {
473
474
			// Hook field specific filter callbacks.
475 9
			$val = $this->field->maybe_hook_parameter( $filter, $default_val );
476 9
			if ( null !== $val ) {
477 9
				$default_val = $val;
478
			}
479
		}
480
481 10
		return $default_val;
482
	}
483
484
	/**
485
	 * Unhooks any CMB2 box or field registered callback parameters for the given filter.
486
	 *
487
	 * @since  2.2.3
488
	 *
489
	 * @param  string $filter The filter name.
490
	 *
491
	 * @return void
492
	 */
493 9
	public function maybe_unhook_registered_callback( $filter ) {
494 9
		parent::maybe_unhook_registered_callback( $filter );
495
496 9
		if ( $this->field ) {
497
			// Unhook field specific filter callbacks.
498 9
			$this->field->maybe_hook_parameter( $filter, null, 'remove_filter' );
499
		}
500 9
	}
501
502
}
503