Post   C
last analyzed

Complexity

Total Complexity 61

Size/Duplication

Total Lines 475
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 4

Importance

Changes 4
Bugs 1 Features 1
Metric Value
dl 0
loc 475
rs 6.018
c 4
b 1
f 1
wmc 61
lcom 2
cbo 4

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 3
A init() 0 7 2
A get_object() 0 3 1
A can_edit() 0 10 3
A get_edit_url() 0 7 2
A get_attached_images() 0 20 2
A attached_images() 0 16 3
A get_first_attached_image_id() 0 22 2
A first_attached_image() 0 10 2
A thumbnail() 0 13 3
A get_title() 0 3 1
A title() 0 3 1
B get_content() 0 21 5
A content() 0 3 1
A get_post_type() 0 3 1
A get_permalink() 0 9 2
A permalink() 0 3 1
F get_preview() 0 79 22
B get_comments() 0 31 4

How to fix   Complexity   

Complex Class

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

1
<?php
2
/**
3
 * Wrapper for WP_Post.
4
 *
5
 * @package Classy\Models
6
 */
7
8
namespace Classy\Models;
9
10
use Classy\Basis;
11
use Classy\Comment;
12
use Classy\Helper;
13
14
/**
15
 * Class Post.
16
 */
17
class Post extends Basis {
18
19
	/**
20
	 * Current post id.
21
	 *
22
	 * @var int
23
	 */
24
	public $ID;
25
26
	/**
27
	 * Stores current post object.
28
	 *
29
	 * @var \WP_Post
30
	 */
31
	protected $object;
32
33
	/**
34
	 * Post title.
35
	 *
36
	 * @var string
37
	 */
38
	public $post_title;
39
40
	/**
41
	 * Post name.
42
	 *
43
	 * @var string
44
	 */
45
	public $post_name;
46
47
	/**
48
	 * Post content (raw).
49
	 *
50
	 * @var string
51
	 */
52
	public $post_content;
53
54
	/**
55
	 * Post type.
56
	 *
57
	 * @var string
58
	 */
59
	public $post_type;
60
61
	/**
62
	 * Post author id.
63
	 *
64
	 * @var int
65
	 */
66
	public $post_author;
67
68
	/**
69
	 * Post date. String as stored in the WP database, ex: 2012-04-23 08:11:23.
70
	 *
71
	 * @var string
72
	 */
73
	public $post_date;
74
75
	/**
76
	 * Post excerpt (raw).
77
	 *
78
	 * @var string
79
	 */
80
	public $post_excerpt;
81
82
	/**
83
	 * Post status. It can be draft, publish, pending, private, trash, etc.
84
	 *
85
	 * @var string
86
	 */
87
	public $post_status;
88
89
	/**
90
	 * Post permalink.
91
	 *
92
	 * @var string
93
	 */
94
	public $permalink;
95
96
	/**
97
	 * Main constructor function. If ID won't be provided we will try to find it, based on your query.
98
	 *
99
	 * @param object|int $post WP_Post or WP_Post.ID.
100
	 */
101
	public function __construct( $post = null ) {
102
		if ( is_integer( $post ) ) {
103
			$this->ID = $post;
104
			$this->init();
105
		} elseif ( is_a( $post, '\WP_Post' ) ) {
106
			$this->import( $post );
0 ignored issues
show
Bug introduced by
It seems like $post defined by parameter $post on line 101 can also be of type null; however, Classy\Basis::import() does only seem to accept object|array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
107
		}
108
	}
109
110
	/**
111
	 * Initialises Instance based on provided post id.
112
	 */
113
	protected function init() {
114
		$post = $this->get_object();
115
116
		if ( is_a( $post, '\WP_Post' ) ) {
117
			$this->import( $post );
118
		}
119
	}
120
121
	/**
122
	 * Returns post object.
123
	 *
124
	 * @return \WP_Post
125
	 */
126
	public function get_object() {
127
		return get_post( $this->ID );
128
	}
129
130
	/**
131
	 * Checks if current user can edit this post.
132
	 *
133
	 * @return boolean
134
	 */
135
	public function can_edit() {
136
		if ( ! function_exists( 'current_user_can' ) ) {
137
			return false;
138
		}
139
		if ( current_user_can( 'edit_post', $this->ID ) ) {
140
			return true;
141
		}
142
143
		return false;
144
	}
145
146
	/**
147
	 * Returns post edit url.
148
	 *
149
	 * @return string
150
	 */
151
	public function get_edit_url() {
152
		if ( $this->can_edit() ) {
153
			return get_edit_post_link( $this->ID );
154
		}
155
156
		return '';
157
	}
158
159
	/**
160
	 * Returns array of attached image ids.
161
	 *
162
	 * @return false|array of ids
163
	 */
164
	public function get_attached_images() {
165
		$attrs = array(
166
			'post_parent' => $this->ID,
167
			'post_status' => null,
168
			'post_type' => 'attachment',
169
			'post_mime_type' => 'image',
170
			'order' => 'ASC',
171
			'numberposts' => -1,
172
			'orderby' => 'menu_order',
173
			'fields' => 'ids',
174
		);
175
176
		$images = get_children( $attrs );
177
178
		if ( ! count( $images ) ) {
179
			return false;
180
		}
181
182
		return $images;
183
	}
184
185
	/**
186
	 * Returns array of attached images as Image objects.
187
	 *
188
	 * @return array of Image
189
	 */
190
	public function attached_images() {
191
		$_return = array();
192
193
		$images = $this->get_attached_images();
194
195
		if ( $images ) {
196
197
			foreach ( $images as $image_id ) {
198
199
				$_return[] = new Image( $image_id );
200
201
			}
202
		}
203
204
		return $_return;
205
	}
206
207
208
	/**
209
	 * Returns first attached image id.
210
	 *
211
	 * @return int|boolean
212
	 */
213
	public function get_first_attached_image_id() {
214
		$attrs = array(
215
			'post_parent' => $this->ID,
216
			'post_status' => null,
217
			'post_type' => 'attachment',
218
			'post_mime_type' => 'image',
219
			'order' => 'ASC',
220
			'numberposts' => 1,
221
			'orderby' => 'menu_order',
222
			'fields' => 'ids',
223
		);
224
225
		$images = get_children( $attrs );
226
227
		if ( ! count( $images ) ) {
228
			return false;
229
		}
230
231
		$images = array_values( $images );
232
233
		return $images[0];
234
	}
235
236
	/**
237
	 * Returns first attached image.
238
	 *
239
	 * @return Image
240
	 */
241
	public function first_attached_image() {
242
243
		$image_id = $this->get_first_attached_image_id();
244
245
		if ( $image_id ) {
246
			return new Image( $image_id );
0 ignored issues
show
Bug introduced by
It seems like $image_id defined by $this->get_first_attached_image_id() on line 243 can also be of type boolean; however, Classy\Models\Image::__construct() does only seem to accept integer|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
247
		}
248
249
		return new Image();
250
	}
251
252
	/**
253
	 * Returns post thumbnail.
254
	 *
255
	 * @return Image
256
	 */
257
	public function thumbnail() {
258
		if ( function_exists( 'get_post_thumbnail_id' ) ) {
259
			$image_id = get_post_thumbnail_id( $this->ID );
260
261
			if ( $image_id ) {
262
263
				return new Image( $image_id );
264
265
			}
266
		}
267
268
		return new Image();
269
	}
270
271
	/**
272
	 * Returns post title with filters applied.
273
	 *
274
	 * @return string
275
	 */
276
	public function get_title() {
277
		return apply_filters( 'the_title', $this->post_title, $this->ID );
278
	}
279
280
	/**
281
	 * Alias for get_title.
282
	 *
283
	 * @return string
284
	 */
285
	public function title() {
286
		return $this->get_title();
287
	}
288
289
	/**
290
	 * Returns the post content with filters applied.
291
	 *
292
	 * @param integer $page Page number, in case our post has <!--nextpage--> tags.
293
	 *
294
	 * @return string Post content
295
	 */
296
	public function get_content( $page = 0 ) {
297
		if ( 0 === absint( $page ) && $this->post_content ) {
298
			return apply_filters( 'the_content', $this->post_content );
299
		}
300
301
		$content = $this->post_content;
302
303
		if ( $page ) {
304
			$contents = explode( '<!--nextpage-->', $content );
305
306
			$page--;
307
308
			if ( count( $contents ) > $page ) {
309
				$content = $contents[ $page ];
310
			}
311
		}
312
313
		$content = apply_filters( 'the_content', ($content) );
314
315
		return $content;
316
	}
317
318
	/**
319
	 * Alias for get_content.
320
	 *
321
	 * @return string
322
	 */
323
	public function content() {
324
		return $this->get_content();
325
	}
326
327
	/**
328
	 * Returns post type object for current post.
329
	 *
330
	 * @return object
331
	 */
332
	public function get_post_type() {
333
		return get_post_type_object( $this->post_type );
334
	}
335
336
	/**
337
	 * Returns post permalink.
338
	 *
339
	 * @return string
340
	 */
341
	public function get_permalink() {
342
		if ( isset( $this->permalink ) ) {
343
			return $this->permalink;
344
		}
345
346
		$this->permalink = get_permalink( $this->ID );
347
348
		return $this->permalink;
349
	}
350
351
	/**
352
	 * Alias for get_permalink
353
	 *
354
	 * @return string
355
	 */
356
	public function permalink() {
357
		return $this->get_permalink();
358
	}
359
360
	/**
361
	 * Returns post preview of requested length.
362
	 * It will look for post_excerpt and will return it.
363
	 * If post contains <!-- more --> tag it will return content until it
364
	 *
365
	 * @param  integer $len      Number of words.
366
	 * @param  boolean $force    If is set to true it will cut your post_excerpt to desired $len length.
367
	 * @param  string  $readmore The text for 'readmore' link.
368
	 * @param  boolean $strip    Should we strip tags.
369
	 *
370
	 * @return string            Post preview.
371
	 */
372
	public function get_preview( $len = 50, $force = false, $readmore = 'Read More', $strip = true ) {
373
		$text = '';
374
		$trimmed = false;
375
376
		if ( isset( $this->post_excerpt ) && strlen( $this->post_excerpt ) ) {
377
378
			if ( $force ) {
379
				$text = Helper::trim_words( $this->post_excerpt, $len, false );
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string|null.

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...
380
				$trimmed = true;
381
			} else {
382
				$text = $this->post_excerpt;
383
			}
384
		}
385
386
		if ( ! strlen( $text ) && preg_match( '/<!--\s?more(.*?)?-->/', $this->post_content, $readmore_matches ) ) {
387
388
			$pieces = explode( $readmore_matches[0], $this->post_content );
389
			$text = $pieces[0];
390
391
			if ( $force ) {
392
				$text = Helper::trim_words( $text, $len, false );
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string|null.

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...
393
				$trimmed = true;
394
			}
395
396
			$text = do_shortcode( $text );
397
398
		}
399
400
		if ( ! strlen( $text ) ) {
401
402
			$text = Helper::trim_words( $this->get_content(), $len, false );
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string|null.

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...
403
			$trimmed = true;
404
405
		}
406
407
		if ( ! strlen( trim( $text ) ) ) {
408
409
			return trim( $text );
410
411
		}
412
413
		if ( $strip ) {
414
415
			$text = trim( strip_tags( $text ) );
416
417
		}
418
419
		if ( strlen( $text ) ) {
420
421
			$text = trim( $text );
422
			$last = $text[ strlen( $text ) - 1 ];
423
424
			if ( '.' !== $last && $trimmed ) {
425
				$text .= ' &hellip; ';
426
			}
427
428
			if ( ! $strip ) {
429
				$last_p_tag = strrpos( $text, '</p>' );
430
				if ( false !== $last_p_tag ) {
431
					$text = substr( $text, 0, $last_p_tag );
432
				}
433
				if ( '.' !== $last && $trimmed ) {
434
					$text .= ' &hellip; ';
435
				}
436
			}
437
438
			if ( $readmore && isset( $readmore_matches ) && ! empty( $readmore_matches[1] ) ) {
439
				$text .= ' <a href="' . $this->get_permalink() . '" class="read-more">' . trim( $readmore_matches[1] ) . '</a>';
440
			} elseif ( $readmore ) {
441
				$text .= ' <a href="' . $this->get_permalink() . '" class="read-more">' . trim( $readmore ) . '</a>';
442
			}
443
444
			if ( ! $strip ) {
445
				$text .= '</p>';
446
			}
447
		}
448
449
		return trim( $text );
450
	}
451
452
	/**
453
	 * Returns comments array
454
	 *
455
	 * @param string $status Comment status.
456
	 * @param string $order  Order for comments query.
457
	 *
458
	 * @return array
459
	 */
460
	public function get_comments( $status = 'approve', $order = 'DESC' ) {
461
462
		$_return = array();
463
464
		$args = array(
465
			'post_id' => $this->ID,
466
			'status' => $status,
467
			'order' => $order,
468
		);
469
470
		$comments = get_comments( $args );
471
472
		foreach ( $comments as $comment ) {
473
474
			$_return[ $comment->comment_ID ] = new Comment( $comment );
475
476
		}
477
478
		foreach ( $_return as $key => $comment ) {
479
480
			if ( $comment->has_parent() ) {
481
482
				$_return[ $comment->comment_parent ]->add_child( $comment );
483
484
				unset( $_return[ $key ] );
485
486
			}
487
		}
488
489
		return array_values( $_return );
490
	}
491
}
492