WordPoints_Entity   B
last analyzed

Complexity

Total Complexity 41

Size/Duplication

Total Lines 498
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 498
rs 8.2769
c 0
b 0
f 0
wmc 41

19 Methods

Rating   Name   Duplication   Size   Complexity  
A get_entity_from_context() 0 14 2
A exists() 0 2 1
A get_the_id() 0 9 3
A get_human_id() 0 9 2
A get_entity() 0 9 2
A get_entity_human_id() 0 2 1
A get_context() 0 2 1
A is_entity() 0 7 3
A get_id_field() 0 2 1
A is_guid() 0 11 4
A get_the_context() 0 2 1
B set_the_value() 0 39 5
A get_the_attr_value() 0 2 1
A split_guid() 0 9 1
A get_the_human_id() 0 2 1
A get_attr_value() 0 13 4
A get_entity_id() 0 9 3
A get_the_guid() 0 11 2
A get_child() 0 14 3

How to fix   Complexity   

Complex Class

Complex classes like WordPoints_Entity 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 WordPoints_Entity, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * Class for representing an entity.
5
 *
6
 * @package WordPoints\Entities
7
 * @since 2.1.0
8
 */
9
10
/**
11
 * Represents an entity.
12
 *
13
 * An entity can be just about anything, like a Post, a User, a Comment, a Site, etc.
14
 * This class defines a single common interface for interacting with entities. This
15
 * is useful when some code needs to be able to work with several different kinds of
16
 * entities and can't know beforehand what they are.
17
 *
18
 * Each different type of entity is defined by a child of this class.
19
 *
20
 * @since 2.1.0
21
 */
22
abstract class WordPoints_Entity
23
	extends WordPoints_Entityish
24
	implements WordPoints_Entity_ParentI {
25
26
	//
27
	// Protected Methods.
28
	//
29
30
	/**
31
	 * The context in which this type of entity exists.
32
	 *
33
	 * Most entities exist only in the context of a specific site on the network (in
34
	 * multisite—when not on multisite they are just global to the install). Entities
35
	 * with other contexts need to specify that by overriding this property.
36
	 *
37
	 * You must either define this or override get_context() in your subclass.
38
	 *
39
	 * @since 2.1.0
40
	 *
41
	 * @see wordpoints_entities_get_current_context_id()
42
	 *
43
	 * @var string
44
	 */
45
	protected $context = 'site';
46
47
	/**
48
	 * The field the entity is identified by.
49
	 *
50
	 * You must either define this or override get_id_field() in your subclass.
51
	 *
52
	 * @since 2.1.0
53
	 *
54
	 * @var string
55
	 */
56
	protected $id_field;
57
58
	/**
59
	 * Whether the IDs of the entities are integers.
60
	 *
61
	 * If true, the ID will always be casted to an integer before it is returned.
62
	 *
63
	 * @since 2.4.0
64
	 *
65
	 * @var bool
66
	 */
67
	protected $id_is_int = false;
68
69
	/**
70
	 * The field the entity can be identified by humans by.
71
	 *
72
	 * You must either define this or override get_entity_human_id().
73
	 *
74
	 * @since 2.1.0
75
	 *
76
	 * @var string
77
	 */
78
	protected $human_id_field;
79
80
	/**
81
	 * A function to call with an entity ID to retrieve that entity.
82
	 *
83
	 * You must either define this or override get_entity().
84
	 *
85
	 * @since 2.1.0
86
	 *
87
	 * @var callable
88
	 */
89
	protected $getter;
90
91
	/**
92
	 * The entity itself.
93
	 *
94
	 * This will probably always be an array or object.
95
	 *
96
	 * @since 2.1.0
97
	 *
98
	 * @var mixed
99
	 */
100
	protected $the_entity;
101
102
	/**
103
	 * The GUID of the context in which the entity exists.
104
	 *
105
	 * @since 2.1.0
106
	 *
107
	 * @see wordpoints_entities_get_current_context_id()
108
	 *
109
	 * @var array|false|null
110
	 */
111
	protected $the_context;
112
113
	/**
114
	 * Get an entity by its ID.
115
	 *
116
	 * @since 2.1.0
117
	 *
118
	 * @param mixed $id The unique ID of the entity.
119
	 *
120
	 * @return mixed The entity, or false if not found.
121
	 */
122
	protected function get_entity( $id ) {
123
124
		$entity = call_user_func( $this->getter, $id );
125
126
		if ( ! $this->is_entity( $entity ) ) {
127
			return false;
128
		}
129
130
		return $entity;
131
	}
132
133
	/**
134
	 * Checks if a value is an entity of this type.
135
	 *
136
	 * @since 2.1.0
137
	 *
138
	 * @param mixed $entity A value that might be an entity.
139
	 *
140
	 * @return bool Whether the passed value is an entity.
141
	 */
142
	protected function is_entity( $entity ) {
143
144
		if ( ! is_object( $entity ) && ! is_array( $entity ) ) {
145
			return false;
146
		}
147
148
		return (bool) $this->get_entity_id( $entity );
149
	}
150
151
	/**
152
	 * Get an entity from a (possibly) foreign context.
153
	 *
154
	 * Normally we only get entities from the current context. This method will grab
155
	 * an entity from a particular context, regardless of whether it is the current
156
	 * context or not.
157
	 *
158
	 * @since 2.2.0
159
	 *
160
	 * @param int|string $id      The unique ID of the entity.
161
	 * @param array      $context The context to get the entity from.
162
	 *
163
	 * @return mixed The entity, or false if not found.
164
	 */
165
	protected function get_entity_from_context( $id, $context ) {
166
167
		/** @var WordPoints_Entity_Contexts $contexts */
168
		$contexts = wordpoints_entities()->get_sub_app( 'contexts' );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $contexts is correct as wordpoints_entities()->get_sub_app('contexts') targeting WordPoints_App::get_sub_app() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

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

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

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

Loading history...
169
170
		if ( ! $contexts->switch_to( $context ) ) {
171
			return false;
172
		}
173
174
		$entity = $this->get_entity( $id );
175
176
		$contexts->switch_back();
177
178
		return $entity;
179
	}
180
181
	/**
182
	 * Checks if a value is a GUID for an entity of this type.
183
	 *
184
	 * @since 2.2.0
185
	 *
186
	 * @param array $guid A value that might be an entity GUID.
187
	 *
188
	 * @return bool Whether the passed value is a GUID for an entity of this type.
189
	 */
190
	protected function is_guid( $guid ) {
191
192
		if ( ! is_array( $guid ) ) {
193
			return false;
194
		}
195
196
		$context = $this->get_context();
197
198
		return (
199
			isset( $guid[ $this->get_slug() ] )
200
			&& ( '' === $context || isset( $guid[ $context ] ) )
201
		);
202
	}
203
204
	/**
205
	 * Splits an entity GUID into the ID and context.
206
	 *
207
	 * @since 2.2.0
208
	 *
209
	 * @param array $guid An entity GUID.
210
	 *
211
	 * @return array {
212
	 *         @type string|int $id      The entity ID.
213
	 *         @type array      $context The entity context.
214
	 * }
215
	 */
216
	protected function split_guid( $guid ) {
217
218
		$slug    = $this->get_slug();
219
		$id      = $guid[ $slug ];
220
		$context = $guid;
221
222
		unset( $context[ $slug ] );
223
224
		return array( 'id' => $id, 'context' => $context );
225
	}
226
227
	/**
228
	 * Gets the value of one of an entity's attributes.
229
	 *
230
	 * @since 2.1.0
231
	 *
232
	 * @param mixed  $entity An entity of this type.
233
	 * @param string $attr   The attribute whose value to get.
234
	 *
235
	 * @return mixed The value of the attribute of the entity.
236
	 */
237
	protected function get_attr_value( $entity, $attr ) {
238
239
		if ( is_array( $entity ) ) {
240
			if ( isset( $entity[ $attr ] ) ) {
241
				return $entity[ $attr ];
242
			}
243
		} else {
244
			if ( isset( $entity->{$attr} ) ) {
245
				return $entity->{$attr};
246
			}
247
		}
248
249
		return null;
250
	}
251
252
	/**
253
	 * Get the ID from an entity.
254
	 *
255
	 * @since 2.1.0
256
	 *
257
	 * @param mixed $entity The entity (usually object or array).
258
	 *
259
	 * @return mixed The ID of the entity.
260
	 */
261
	protected function get_entity_id( $entity ) {
262
263
		$id = $this->get_attr_value( $entity, $this->get_id_field() );
264
265
		if ( $this->id_is_int && null !== $id ) {
266
			$id = wordpoints_posint( $id );
267
		}
268
269
		return $id;
270
	}
271
272
	/**
273
	 * Get the human ID from an entity.
274
	 *
275
	 * The human ID is a human readable identifier for the entity, and may be
276
	 * different than the regular ID. It is also possible that the human ID will not
277
	 * always be unique.
278
	 *
279
	 * @since 2.1.0
280
	 *
281
	 * @param mixed $entity The entity (usually object or array).
282
	 *
283
	 * @return mixed The human ID of the entity.
284
	 */
285
	protected function get_entity_human_id( $entity ) {
286
		return $this->get_attr_value( $entity, $this->human_id_field );
287
	}
288
289
	//
290
	// Public Methods.
291
	//
292
293
	/**
294
	 * Get the slug of the context in which this type of entity exists.
295
	 *
296
	 * @since 2.1.0
297
	 *
298
	 * @see wordpoints_entities_get_current_context_id()
299
	 *
300
	 * @return string The slug of the context in which this type of entity exists.
301
	 */
302
	public function get_context() {
303
		return $this->context;
304
	}
305
306
	/**
307
	 * Get the attribute that holds the entity's unique ID.
308
	 *
309
	 * @since 2.1.0
310
	 *
311
	 * @return string The attribute that holds the entity's unique ID.
312
	 */
313
	public function get_id_field() {
314
		return $this->id_field;
315
	}
316
317
	/**
318
	 * Get the human ID for an entity.
319
	 *
320
	 * @since 2.1.0
321
	 *
322
	 * @see self::get_entity_human_id()
323
	 *
324
	 * @param mixed $id The ID of an entity.
325
	 *
326
	 * @return string|int|float|false The human identifier for the entity, or false.
327
	 */
328
	public function get_human_id( $id ) {
329
330
		$entity = $this->get_entity( $id );
331
332
		if ( ! $entity ) {
333
			return false;
334
		}
335
336
		return $this->get_entity_human_id( $entity );
337
	}
338
339
	/**
340
	 * Check if an entity exists, by ID.
341
	 *
342
	 * @since 2.1.0
343
	 *
344
	 * @param mixed $id The entity ID.
345
	 *
346
	 * @return bool Whether or not an entity with that ID exists.
347
	 */
348
	public function exists( $id ) {
349
		return (bool) $this->get_entity( $id );
350
	}
351
352
	/**
353
	 * Get a child of this entity.
354
	 *
355
	 * Entities can have children, which currently fall into two types: attributes
356
	 * and relationships.
357
	 *
358
	 * @since 2.1.0
359
	 *
360
	 * @param string $child_slug The slug of the child.
361
	 *
362
	 * @return WordPoints_Entityish|false The child's object, or false if not found.
363
	 */
364
	public function get_child( $child_slug ) {
365
366
		$children = wordpoints_entities()->get_sub_app( 'children' );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $children is correct as wordpoints_entities()->get_sub_app('children') targeting WordPoints_App::get_sub_app() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

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

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

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

Loading history...
367
368
		$child = $children->get( $this->slug, $child_slug );
369
370
		if (
371
			isset( $this->the_value )
372
			&& $child instanceof WordPoints_Entity_ChildI
373
		) {
374
			$child->set_the_value_from_entity( $this );
375
		}
376
377
		return $child;
378
	}
379
380
	/**
381
	 * Set the value of this entity.
382
	 *
383
	 * This class can represent a type of entity generically (e.g., Post), or a
384
	 * specific entity of that type (the Post with ID 3). This function allows you to
385
	 * make this object instance represent a specific entity.
386
	 *
387
	 * If the value passed is not an entity, and is not a valid ID, it will be
388
	 * ignored and the value will not be set.
389
	 *
390
	 * @since 2.1.0
391
	 * @since 2.2.0 The $value parameter now accepts an entity GUID.
392
	 *
393
	 * @param mixed $value An entity or entity ID or GUID.
394
	 *
395
	 * @return bool Whether the value was set.
396
	 */
397
	public function set_the_value( $value ) {
398
399
		$this->the_value   = null;
400
		$this->the_entity  = null;
401
		$this->the_context = null;
402
403
		if ( $this->is_entity( $value ) ) {
404
405
			$entity = $value;
406
			$value  = $this->get_entity_id( $value );
407
408
		} elseif ( $this->is_guid( $value ) ) {
409
410
			$guid    = $this->split_guid( $value );
411
			$context = $guid['context'];
412
			$value   = $guid['id'];
413
414
			$entity = $this->get_entity_from_context( $guid['id'], $context );
415
416
		} else {
417
418
			$entity = $this->get_entity( $value );
419
		}
420
421
		if ( ! $entity ) {
422
			return false;
423
		}
424
425
		if ( ! isset( $context ) ) {
426
			$context = wordpoints_entities_get_current_context_id(
427
				$this->get_context()
428
			);
429
		}
430
431
		$this->the_value   = $value;
432
		$this->the_entity  = $entity;
433
		$this->the_context = $context;
434
435
		return true;
436
	}
437
438
	/**
439
	 * Get the value of one of this entity's attributes.
440
	 *
441
	 * @since 2.1.0
442
	 *
443
	 * @param string $attr The attribute to get the value of.
444
	 *
445
	 * @return mixed The value of the attribute.
446
	 */
447
	public function get_the_attr_value( $attr ) {
448
		return $this->get_attr_value( $this->the_entity, $attr );
449
	}
450
451
	/**
452
	 * Get the ID of the entity.
453
	 *
454
	 * @since 2.1.0
455
	 *
456
	 * @return mixed The ID of the entity.
457
	 */
458
	public function get_the_id() {
459
460
		$the_id = $this->get_the_value();
461
462
		if ( $this->id_is_int && null !== $the_id ) {
463
			$the_id = wordpoints_posint( $the_id );
464
		}
465
466
		return $the_id;
467
	}
468
469
	/**
470
	 * Get the human ID of the entity.
471
	 *
472
	 * @since 2.1.0
473
	 *
474
	 * @see self::get_entity_human_id()
475
	 *
476
	 * @return string|int|float|null The human identifier for the entity, or null.
477
	 */
478
	public function get_the_human_id() {
479
		return $this->get_entity_human_id( $this->the_entity );
480
	}
481
482
	/**
483
	 * Get the context in which the current entity exists.
484
	 *
485
	 * @since 2.1.0
486
	 *
487
	 * @see wordpoints_entities_get_current_context_id()
488
	 *
489
	 * @return array|null The context values indexed by context slugs.
490
	 */
491
	public function get_the_context() {
492
		return $this->the_context;
493
	}
494
495
	/**
496
	 * Get the Globally Unique ID of the entity.
497
	 *
498
	 * The GUID is an array of values that includes the GUID of the entity context
499
	 * in addition to the ID of the entity itself.
500
	 *
501
	 * The entity ID is first in the array, then the context IDs in ascending
502
	 * hierarchical order.
503
	 *
504
	 * @since 2.1.0
505
	 *
506
	 * @return array|false|null The GUID, false if it could not be determined, or
507
	 *                          null if the value isn't set.
508
	 */
509
	public function get_the_guid() {
510
511
		$guid = $this->get_the_context();
512
513
		if ( ! is_array( $guid ) ) {
514
			return $guid;
515
		}
516
517
		$guid = array( $this->slug => $this->get_the_id() ) + $guid;
518
519
		return $guid;
520
	}
521
}
522
523
// EOF
524