acf_field_user   B
last analyzed

Complexity

Total Complexity 43

Size/Duplication

Total Lines 615
Duplicated Lines 7.97 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 49
loc 615
rs 8.945
c 0
b 0
f 0
wmc 43
lcom 1
cbo 1

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 22 22 1
D get_choices() 0 146 15
A ajax_query() 27 27 3
A get_result() 0 40 4
A user_search_columns() 0 24 2
A render_field() 0 42 4
B render_field_settings() 0 56 2
A update_value() 0 20 5
A load_value() 0 13 2
B format_value() 0 64 5

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like acf_field_user 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 acf_field_user, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
*  ACF User Field Class
5
*
6
*  All the logic for this field type
7
*
8
*  @class 		acf_field_user
9
*  @extends		acf_field
10
*  @package		ACF
11
*  @subpackage	Fields
12
*/
13
14
if( ! class_exists('acf_field_user') ) :
15
16
class acf_field_user extends acf_field {
17
	
18
	
19
	/*
20
	*  __construct
21
	*
22
	*  This function will setup the field type data
23
	*
24
	*  @type	function
25
	*  @date	5/03/2014
26
	*  @since	5.0.0
27
	*
28
	*  @param	n/a
29
	*  @return	n/a
30
	*/
0 ignored issues
show
Documentation introduced by
The doc-type n/a could not be parsed: Unknown type name "n/a" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
31
	
32 View Code Duplication
	function __construct() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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...
33
		
34
		// vars
35
		$this->name = 'user';
36
		$this->label = __("User",'acf');
0 ignored issues
show
Bug introduced by
The property label does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
37
		$this->category = 'relational';
38
		$this->defaults = array(
39
			'role' 			=> '',
40
			'multiple' 		=> 0,
41
			'allow_null' 	=> 0,
42
		);
43
		
44
		
45
		// extra
46
		add_action('wp_ajax_acf/fields/user/query',			array($this, 'ajax_query'));
47
		add_action('wp_ajax_nopriv_acf/fields/user/query',	array($this, 'ajax_query'));
48
		
49
		
50
		// do not delete!
51
    	parent::__construct();
52
    	
53
	}
54
55
	
56
	/*
57
	*  get_choices
58
	*
59
	*  This function will return an array of data formatted for use in a select2 AJAX response
60
	*
61
	*  @type	function
62
	*  @date	15/10/2014
63
	*  @since	5.0.9
64
	*
65
	*  @param	$options (array)
66
	*  @return	(array)
67
	*/
68
	
69
	function get_choices( $options = array() ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
70
		
71
   		// defaults
72
   		$options = acf_parse_args($options, array(
73
			'post_id'		=>	0,
74
			's'				=>	'',
75
			'field_key'		=>	'',
76
		));
77
		
78
				
79
   		// vars
80
   		$r = array();
81
   		$args = array();
82
   		
83
		
84
		// load field
85
		$field = acf_get_field( $options['field_key'] );
86
		
87
		if( !$field ) {
88
		
89
			return false;
90
			
91
		}
92
		
93
		
94
		// editable roles
95
		$editable_roles = get_editable_roles();
96
		
97
		if( !empty($field['role']) ) {
98
			
99
			foreach( $editable_roles as $role => $role_info ) {
100
				
101
				if( !in_array($role, $field['role']) ) {
102
				
103
					unset( $editable_roles[ $role ] );
104
					
105
				}
106
				
107
			}
108
			
109
		}
110
		
111
				
112
		// search
113
		if( $options['s'] ) {
114
			
115
			// append to $args
116
			$args['search'] = '*' . $options['s'] . '*';
117
			
118
			
119
			// add reference
120
			$this->field = $field;
0 ignored issues
show
Bug introduced by
The property field does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
121
			
122
			
123
			// add filter to modify search colums
124
			add_filter('user_search_columns', array($this, 'user_search_columns'), 10, 3);
125
			
126
		}
127
		
128
		
129
		// filters
130
		$args = apply_filters("acf/fields/user/query",							$args, $field, $options['post_id']);
131
		$args = apply_filters("acf/fields/user/query/name={$field['_name']}",	$args, $field, $options['post_id']);
132
		$args = apply_filters("acf/fields/user/query/key={$field['key']}",		$args, $field, $options['post_id']);
133
		
134
		
135
		// get users
136
		$users = get_users( $args );
137
		
138
		if( !empty($users) && !empty($editable_roles) ) {
139
			
140
			foreach( $editable_roles as $role => $role_info ) {
141
				
142
				// vars
143
				$this_users = array();
144
				$this_json = array();
145
				
146
				
147
				// loop over users
148
				foreach( array_keys($users) as $key ) {
149
					
150
					if( in_array($role, $users[ $key ]->roles) ) {
151
						
152
						// extract user
153
						$user = acf_extract_var( $users, $key );
154
						
155
						
156
						// append to $this_users
157
						$this_users[ $user->ID ] = $this->get_result( $user, $field, $options['post_id'] );
158
						
159
					}
160
					
161
				}
162
				
163
				
164
				// bail early if no users for this role
165
				if( empty($this_users) ) {
166
				
167
					continue;
168
					
169
				}
170
				
171
								
172
				// order by search
173
				if( !empty($args['s']) ) {
174
					
175
					$this_users = acf_order_by_search( $this_users, $args['s'] );
176
					
177
				}
178
				
179
				
180
				// append to json
181
				foreach( array_keys($this_users) as $user_id ) {
182
					
183
					// add to json
184
					$this_json[] = array(
185
						'id'	=> $user_id,
186
						'text'	=> $this_users[ $user_id ]
187
					);
188
	
189
				}
190
				
191
				
192
				// add as optgroup or results
193
				if( count($editable_roles) == 1 ) {
194
				
195
					$r = $this_json;
196
					
197
				} else {
198
					
199
					$r[] = array(
200
						'text'		=> translate_user_role( $role_info['name'] ),
201
						'children'	=> $this_json
202
					);
203
					
204
				}
205
				
206
			}
207
			
208
		}
209
		
210
		
211
		// return
212
		return $r;
213
			
214
	}
215
	
216
	
217
	/*
218
	*  ajax_query
219
	*
220
	*  description
221
	*
222
	*  @type	function
223
	*  @date	24/10/13
224
	*  @since	5.0.0
225
	*
226
	*  @param	$post_id (int)
227
	*  @return	$post_id (int)
228
	*/
0 ignored issues
show
Documentation introduced by
The doc-type $post_id could not be parsed: Unknown type name "$post_id" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
229
	
230 View Code Duplication
	function ajax_query() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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...
231
		
232
		// validate
233
		if( !acf_verify_ajax() ) {
234
		
235
			die();
236
			
237
		}
238
		
239
		
240
		// get choices
241
		$choices = $this->get_choices( $_POST );
242
		
243
		
244
		// validate
245
		if( !$choices ) {
246
			
247
			die();
248
			
249
		}
250
		
251
		
252
		// return JSON
253
		echo json_encode( $choices );
254
		die();
255
			
256
	}
257
	
258
	
259
	/*
260
	*  get_result
261
	*
262
	*  This function returns the HTML for a result
263
	*
264
	*  @type	function
265
	*  @date	1/11/2013
266
	*  @since	5.0.0
267
	*
268
	*  @param	$post (object)
269
	*  @param	$field (array)
270
	*  @param	$post_id (int) the post_id to which this value is saved to
271
	*  @return	(string)
272
	*/
273
	
274
	function get_result( $user, $field, $post_id = 0 ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
275
		
276
		// get post_id
277
		if( !$post_id ) {
278
			
279
			$post_id = acf_get_setting('form_data/post_id', get_the_ID());
280
			
281
		}
282
		
283
		
284
		// vars
285
		$result = $user->user_login;
286
		
287
		
288
		// append name
289
		if( $user->first_name ) {
290
			
291
			$result .= ' (' .  $user->first_name;
292
			
293
			if( $user->last_name ) {
294
				
295
				$result .= ' ' . $user->last_name;
296
				
297
			}
298
			
299
			$result .= ')';
300
			
301
		}
302
		
303
		
304
		// filters
305
		$result = apply_filters("acf/fields/user/result",							$result, $user, $field, $post_id);
306
		$result = apply_filters("acf/fields/user/result/name={$field['_name']}",	$result, $user, $field, $post_id);
307
		$result = apply_filters("acf/fields/user/result/key={$field['key']}",		$result, $user, $field, $post_id);
308
		
309
		
310
		// return
311
		return $result;
312
		
313
	}
314
	
315
	
316
	/*
317
	*  user_search_columns
318
	*
319
	*  This function will modify the columns which the user AJAX search looks in
320
	*
321
	*  @type	function
322
	*  @date	17/06/2014
323
	*  @since	5.0.0
324
	*
325
	*  @param	$columns (array)
326
	*  @return	$columns
327
	*/
0 ignored issues
show
Documentation introduced by
The doc-type $columns could not be parsed: Unknown type name "$columns" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
328
	
329
	function user_search_columns( $columns, $search, $WP_User_Query ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
330
		
331
		// bail early if no field
332
		if( empty($this->field) ) {
333
			
334
			return $columns;
335
			
336
		}
337
		
338
		
339
		// vars
340
		$field = $this->field;
341
		
342
		
343
		// filter for 3rd party customization
344
		$columns = apply_filters("acf/fields/user/search_columns", 							$columns, $search, $WP_User_Query, $field);
345
		$columns = apply_filters("acf/fields/user/search_columns/name={$field['_name']}",	$columns, $search, $WP_User_Query, $field);
346
		$columns = apply_filters("acf/fields/user/search_columns/key={$field['key']}",		$columns, $search, $WP_User_Query, $field);
347
		
348
		
349
		// return
350
		return $columns;
351
		
352
	}
353
	
354
	/*
355
	*  render_field()
356
	*
357
	*  Create the HTML interface for your field
358
	*
359
	*  @type	action
360
	*  @since	3.6
361
	*  @date	23/01/13
362
	*
363
	*  @param	$field - an array holding all the field's data
364
	*/
365
	
366
	function render_field( $field ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
367
		
368
		// Change Field into a select
369
		$field['type'] = 'select';
370
		$field['ui'] = 1;
371
		$field['ajax'] = 1;
372
		$field['choices'] = array();
373
		
374
		
375
		// populate choices
376
		if( !empty($field['value']) ) {
377
			
378
			// force value to array
379
			$field['value'] = acf_get_array( $field['value'] );
380
			
381
			
382
			// convert values to int
383
			$field['value'] = array_map('intval', $field['value']);
384
			
385
			
386
			$users = get_users(array(
387
				'include' => $field['value']
388
			));
389
			
390
			
391
			if( !empty($users) ) {
392
			
393
				foreach( $users as $user ) {
394
				
395
					$field['choices'][ $user->ID ] = $this->get_result( $user, $field );
396
					
397
				}
398
				
399
			}
400
			
401
		}
402
		
403
		
404
		// render
405
		acf_render_field( $field );
0 ignored issues
show
Documentation introduced by
$field is of type array<string,string|integer|array>, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
406
		
407
	}
408
	
409
	
410
	/*
411
	*  render_field_settings()
412
	*
413
	*  Create extra options for your field. This is rendered when editing a field.
414
	*  The value of $field['name'] can be used (like bellow) to save extra data to the $field
415
	*
416
	*  @type	action
417
	*  @since	3.6
418
	*  @date	23/01/13
419
	*
420
	*  @param	$field	- an array holding all the field's data
421
	*/
422
	
423
	function render_field_settings( $field ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
424
		
425
		// role
426
		$choices = array();
427
		$editable_roles = get_editable_roles();
428
429
		foreach( $editable_roles as $role => $details ) {	
430
				
431
			// only translate the output not the value
432
			$choices[ $role ] = translate_user_role( $details['name'] );
433
			
434
		}
435
		
436
		acf_render_field_setting( $field, array(
437
			'label'			=> __('Filter by role','acf'),
438
			'instructions'	=> '',
439
			'type'			=> 'select',
440
			'name'			=> 'role',
441
			'choices'		=> $choices,
442
			'multiple'		=> 1,
443
			'ui'			=> 1,
444
			'allow_null'	=> 1,
445
			'placeholder'	=> __("All user roles",'acf'),
446
		));
447
		
448
		
449
		
450
		// allow_null
451
		acf_render_field_setting( $field, array(
452
			'label'			=> __('Allow Null?','acf'),
453
			'instructions'	=> '',
454
			'type'			=> 'radio',
455
			'name'			=> 'allow_null',
456
			'choices'		=> array(
457
				1				=> __("Yes",'acf'),
458
				0				=> __("No",'acf'),
459
			),
460
			'layout'	=>	'horizontal',
461
		));
462
		
463
		
464
		// multiple
465
		acf_render_field_setting( $field, array(
466
			'label'			=> __('Select multiple values?','acf'),
467
			'instructions'	=> '',
468
			'type'			=> 'radio',
469
			'name'			=> 'multiple',
470
			'choices'		=> array(
471
				1				=> __("Yes",'acf'),
472
				0				=> __("No",'acf'),
473
			),
474
			'layout'	=>	'horizontal',
475
		));
476
		
477
		
478
	}
479
	
480
	
481
	/*
482
	*  update_value()
483
	*
484
	*  This filter is appied to the $value before it is updated in the db
485
	*
486
	*  @type	filter
487
	*  @since	3.6
488
	*  @date	23/01/13
489
	*
490
	*  @param	$value - the value which will be saved in the database
491
	*  @param	$post_id - the $post_id of which the value will be saved
492
	*  @param	$field - the field array holding all the field options
493
	*
494
	*  @return	$value - the modified value
495
	*/
0 ignored issues
show
Documentation introduced by
The doc-type $value could not be parsed: Unknown type name "$value" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
496
	
497
	function update_value( $value, $post_id, $field ) {
0 ignored issues
show
Unused Code introduced by
The parameter $post_id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $field is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
498
	
499
		// array?
500
		if( is_array($value) && isset($value['ID']) ) {
501
		
502
			$value = $value['ID'];	
503
			
504
		}
505
		
506
		// object?
507
		if( is_object($value) && isset($value->ID) ) {
508
		
509
			$value = $value->ID;
510
			
511
		}
512
		
513
		
514
		// return
515
		return $value;
516
	}
517
	
518
	
519
	/*
520
	*  load_value()
521
	*
522
	*  This filter is applied to the $value after it is loaded from the db
523
	*
524
	*  @type	filter
525
	*  @since	3.6
526
	*  @date	23/01/13
527
	*
528
	*  @param	$value (mixed) the value found in the database
529
	*  @param	$post_id (mixed) the $post_id from which the value was loaded
530
	*  @param	$field (array) the field array holding all the field options
531
	*  @return	$value
532
	*/
0 ignored issues
show
Documentation introduced by
The doc-type $value could not be parsed: Unknown type name "$value" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
533
	
534
	function load_value( $value, $post_id, $field ) {
0 ignored issues
show
Unused Code introduced by
The parameter $post_id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $field is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
535
		
536
		// ACF4 null
537
		if( $value === 'null' ) {
538
		
539
			return false;
540
			
541
		}
542
		
543
		
544
		// return
545
		return $value;
546
	}
547
	
548
	
549
	/*
550
	*  format_value()
551
	*
552
	*  This filter is appied to the $value after it is loaded from the db and before it is returned to the template
553
	*
554
	*  @type	filter
555
	*  @since	3.6
556
	*  @date	23/01/13
557
	*
558
	*  @param	$value (mixed) the value which was loaded from the database
559
	*  @param	$post_id (mixed) the $post_id from which the value was loaded
560
	*  @param	$field (array) the field array holding all the field options
561
	*
562
	*  @return	$value (mixed) the modified value
563
	*/
0 ignored issues
show
Documentation introduced by
The doc-type $value could not be parsed: Unknown type name "$value" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
564
	
565
	function format_value( $value, $post_id, $field ) {
0 ignored issues
show
Unused Code introduced by
The parameter $post_id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
566
		
567
		// bail early if no value
568
		if( empty($value) ) {
569
		
570
			return $value;
571
			
572
		}
573
		
574
		
575
		// force value to array
576
		$value = acf_get_array( $value );
577
		
578
		
579
		// convert values to int
580
		$value = array_map('intval', $value);
581
		
582
		
583
		// load users	
584
		foreach( array_keys($value) as $i ) {
585
			
586
			// vars
587
			$user_id = $value[ $i ];
588
			$user_data = get_userdata( $user_id );
589
			
590
			
591
			//cope with deleted users by @adampope
592
			if( !is_object($user_data) ) {
593
			
594
				unset( $value[ $i ] );
595
				continue;
596
				
597
			}
598
	
599
			
600
			// append to array
601
			$value[ $i ] = array();
602
			$value[ $i ]['ID'] = $user_id;
603
			$value[ $i ]['user_firstname'] = $user_data->user_firstname;
604
			$value[ $i ]['user_lastname'] = $user_data->user_lastname;
605
			$value[ $i ]['nickname'] = $user_data->nickname;
606
			$value[ $i ]['user_nicename'] = $user_data->user_nicename;
607
			$value[ $i ]['display_name'] = $user_data->display_name;
608
			$value[ $i ]['user_email'] = $user_data->user_email;
609
			$value[ $i ]['user_url'] = $user_data->user_url;
610
			$value[ $i ]['user_registered'] = $user_data->user_registered;
611
			$value[ $i ]['user_description'] = $user_data->user_description;
612
			$value[ $i ]['user_avatar'] = get_avatar( $user_id );
613
			
614
		}
615
		
616
		
617
		// convert back from array if neccessary
618
		if( !$field['multiple'] ) {
619
		
620
			$value = array_shift($value);
621
			
622
		}
623
		
624
		
625
		// return value
626
		return $value;
627
		
628
	}
629
		
630
}
631
632
new acf_field_user();
633
634
endif;
635
636
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
637