Passed
Push — master ( a42385...9b46a7 )
by Paul
04:14
created

CountsManager   C

Complexity

Total Complexity 54

Size/Duplication

Total Lines 323
Duplicated Lines 0 %

Test Coverage

Coverage 9.59%

Importance

Changes 0
Metric Value
eloc 116
dl 0
loc 323
ccs 14
cts 146
cp 0.0959
rs 6.4799
c 0
b 0
f 0
wmc 54

24 Methods

Rating   Name   Duplication   Size   Complexity  
A decreaseCounts() 0 6 1
A decreaseRating() 0 6 2
A get() 0 18 4
A getTermCounts() 0 3 1
A decreaseTermCounts() 0 6 3
A setTermCounts() 0 7 2
A decreasePostCounts() 0 5 2
A buildTermCounts() 0 3 1
A buildCounts() 0 3 1
A flatten() 0 17 5
A decrease() 0 5 1
A setCounts() 0 3 1
A getPostCounts() 0 3 1
A setPostCounts() 0 6 1
A queryReviews() 0 11 4
A buildPostCounts() 0 3 1
A increaseRating() 0 11 3
A increase() 0 5 1
A increasePostCounts() 0 8 3
A getCounts() 0 3 1
A increaseCounts() 0 9 2
A build() 0 16 5
A normalize() 0 13 5
A increaseTermCounts() 0 9 3

How to fix   Complexity   

Complex Class

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

1
<?php
2
3
namespace GeminiLabs\SiteReviews\Database;
4
5
use GeminiLabs\SiteReviews\Application;
6
use GeminiLabs\SiteReviews\Database\OptionManager;
7
use GeminiLabs\SiteReviews\Database\ReviewManager;
8
use GeminiLabs\SiteReviews\Database\SqlQueries;
9
use GeminiLabs\SiteReviews\Modules\Polylang;
10
use GeminiLabs\SiteReviews\Modules\Rating;
11
use GeminiLabs\SiteReviews\Review;
12
use WP_Post;
13
use WP_Term;
14
15
class CountsManager
16
{
17
	const META_AVERAGE = '_glsr_average';
18
	const META_COUNT = '_glsr_count';
19
	const META_RANKING = '_glsr_ranking';
20
21
	/**
22
	 * @param int $limit
23
	 * @return array
24
	 */
25 1
	public function buildCounts( $limit = 500 )
26
	{
27 1
		return $this->build( $limit );
28
	}
29
30
	/**
31
	 * @param int $postId
32
	 * @param int $limit
33
	 * @return array
34
	 */
35
	public function buildPostCounts( $postId, $limit = 500 )
36
	{
37
		return $this->build( $limit, ['post_id' => $postId] );
38
	}
39
40
	/**
41
	 * @param int $termId
42
	 * @param int $limit
43
	 * @return array
44
	 */
45
	public function buildTermCounts( $termId, $limit = 500 )
46
	{
47
		return $this->build( $limit, ['term_id' => $termId] );
48
	}
49
50
	/**
51
	 * @return void
52
	 */
53
	public function decrease( Review $review )
54
	{
55
		$this->decreaseCounts( $review );
56
		$this->decreasePostCounts( $review );
57
		$this->decreaseTermCounts( $review );
58
	}
59
60
	/**
61
	 * @return void
62
	 */
63
	public function decreaseCounts( Review $review )
64
	{
65
		$this->setCounts( $this->decreaseRating(
66
			$this->getCounts(),
67
			$review->review_type,
68
			$review->rating
69
		));
70
	}
71
72
	/**
73
	 * @return void
74
	 */
75
	public function decreasePostCounts( Review $review )
76
	{
77
		if( empty( $counts = $this->getPostCounts( $review->assigned_to )))return;
78
		$counts = $this->decreaseRating( $counts, $review->review_type, $review->rating );
79
		$this->setPostCounts( $review->assigned_to, $counts );
80
	}
81
82
	/**
83
	 * @return void
84
	 */
85
	public function decreaseTermCounts( Review $review )
86
	{
87
		foreach( $review->term_ids as $termId ) {
88
			if( empty( $counts = $this->getTermCounts( $termId )))continue;
89
			$counts = $this->decreaseRating( $counts, $review->review_type, $review->rating );
90
			$this->setTermCounts( $termId, $counts );
91
		}
92
	}
93
94
	/**
95
	 * @return array
96
	 */
97
	public function flatten( array $reviewCounts, array $args = [] )
98
	{
99
		$counts = [];
100
		array_walk_recursive( $reviewCounts, function( $num, $index ) use( &$counts ) {
101
			$counts[$index] = isset( $counts[$index] )
102
				? $num + $counts[$index]
103
				: $num;
104
		});
105
		$args = wp_parse_args( $args, [
106
			'max' => Rating::MAX_RATING,
107
			'min' => Rating::MIN_RATING,
108
		]);
109
		foreach( $counts as $index => &$num ) {
110
			if( $index >= intval( $args['min'] ) && $index <= intval( $args['max'] ))continue;
111
			$num = 0;
112
		}
113
		return $counts;
114
	}
115
116
	/**
117
	 * @return array
118
	 */
119
	public function get( array $args = [] )
120
	{
121
		$args = wp_parse_args( $args, [
122
			'post_ids' => [],
123
			'term_ids' => [],
124
			'type' => 'local',
125
		]);
126
		$counts = [];
127
		foreach( glsr( Polylang::class )->getPostIds( $args['post_ids'] ) as $postId ) {
128
			$counts[] = $this->getPostCounts( $postId );
129
		}
130
		foreach( $args['term_ids'] as $termId ) {
131
			$counts[] = $this->getTermCounts( $termId );
132
		}
133
		if( empty( $counts )) {
134
			$counts[] = $this->getCounts();
135
		}
136
		return $this->normalize( array_column( $counts, $args['type'] ));
137
	}
138
139
	/**
140
	 * @return array
141
	 */
142
	public function getCounts()
143
	{
144
		return glsr( OptionManager::class )->get( 'counts', [] );
145
	}
146
147
	/**
148
	 * @param int $postId
149
	 * @return array
150
	 */
151
	public function getPostCounts( $postId )
152
	{
153
		return array_filter( (array)get_post_meta( $postId, static::META_COUNT, true ));
154
	}
155
156
	/**
157
	 * @param int $termId
158
	 * @return array
159
	 */
160
	public function getTermCounts( $termId )
161
	{
162
		return array_filter( (array)get_term_meta( $termId, static::META_COUNT, true ));
163
	}
164
165
	/**
166
	 * @return void
167
	 */
168
	public function increase( Review $review )
169
	{
170
		$this->increaseCounts( $review );
171
		$this->increasePostCounts( $review );
172
		$this->increaseTermCounts( $review );
173
	}
174
175
	/**
176
	 * @return void
177
	 */
178
	public function increaseCounts( Review $review )
179
	{
180
		if( empty( $counts = $this->getCounts() )) {
181
			$counts = $this->buildCounts();
182
		}
183
		$this->setCounts( $this->increaseRating(
184
			$counts,
185
			$review->review_type,
186
			$review->rating
187
		));
188
	}
189
190
	/**
191
	 * @return void
192
	 */
193
	public function increasePostCounts( Review $review )
194
	{
195
		if( !( get_post( $review->assigned_to ) instanceof WP_Post ))return;
196
		$counts = $this->getPostCounts( $review->assigned_to );
197
		$counts = empty( $counts )
198
			? $this->buildPostCounts( $review->assigned_to )
199
			: $this->increaseRating( $counts, $review->review_type, $review->rating );
200
		$this->setPostCounts( $review->assigned_to, $counts );
201
	}
202
203
	/**
204
	 * @return void
205
	 */
206
	public function increaseTermCounts( Review $review )
207
	{
208
		$termIds = glsr( ReviewManager::class )->normalizeTerms( implode( ',', $review->term_ids ));
209
		foreach( $termIds as $termId ) {
210
			$counts = $this->getTermCounts( $termId );
211
			$counts = empty( $counts )
212
				? $this->buildTermCounts( $termId )
213
				: $this->increaseRating( $counts, $review->review_type, $review->rating );
214
			$this->setTermCounts( $termId, $counts );
215
		}
216
	}
217
218
	/**
219
	 * @return void
220
	 */
221 1
	public function setCounts( array $reviewCounts )
222
	{
223 1
		glsr( OptionManager::class )->set( 'counts', $reviewCounts );
224 1
	}
225
226
	/**
227
	 * @param int $postId
228
	 * @return void
229
	 */
230
	public function setPostCounts( $postId, array $reviewCounts )
231
	{
232
		$ratingCounts = glsr( CountsManager::class )->flatten( $reviewCounts );
233
		update_post_meta( $postId, static::META_COUNT, $reviewCounts );
234
		update_post_meta( $postId, static::META_AVERAGE, glsr( Rating::class )->getAverage( $ratingCounts ));
235
		update_post_meta( $postId, static::META_RANKING, glsr( Rating::class )->getRanking( $ratingCounts ));
236
	}
237
238
	/**
239
	 * @param int $termId
240
	 * @return void
241
	 */
242
	public function setTermCounts( $termId, array $reviewCounts )
243
	{
244
		if( !term_exists( $termId ))return;
245
		$ratingCounts = glsr( CountsManager::class )->flatten( $reviewCounts );
246
		update_term_meta( $termId, static::META_COUNT, $reviewCounts );
247
		update_term_meta( $termId, static::META_AVERAGE, glsr( Rating::class )->getAverage( $ratingCounts ));
248
		update_term_meta( $termId, static::META_RANKING, glsr( Rating::class )->getRanking( $ratingCounts ));
249
	}
250
251
	/**
252
	 * @param int $limit
253
	 * @return array
254
	 */
255 1
	protected function build( $limit, array $args = [] )
256
	{
257 1
		$counts = [];
258 1
		$lastPostId = 0;
259 1
		while( $reviews = $this->queryReviews( $args, $lastPostId, $limit )) {
260
			$types = array_keys( array_flip( array_column( $reviews, 'type' )));
261
			foreach( $types as $type ) {
262
				if( isset( $counts[$type] ))continue;
263
				$counts[$type] = array_fill_keys( range( 0, Rating::MAX_RATING ), 0 );
264
			}
265
			foreach( $reviews as $review ) {
266
				$counts[$review->type][$review->rating]++;
267
			}
268
			$lastPostId = end( $reviews )->ID;
269
		}
270 1
		return $counts;
271
	}
272
273
	/**
274
	 * @param string $type
275
	 * @param int $rating
276
	 * @return array
277
	 */
278
	protected function decreaseRating( array $reviewCounts, $type, $rating )
279
	{
280
		if( isset( $reviewCounts[$type][$rating] )) {
281
			$reviewCounts[$type][$rating] = max( 0, $reviewCounts[$type][$rating] - 1 );
282
		}
283
		return $reviewCounts;
284
	}
285
286
	/**
287
	 * @param string $type
288
	 * @param int $rating
289
	 * @return array
290
	 */
291
	protected function increaseRating( array $reviewCounts, $type, $rating )
292
	{
293
		if( !array_key_exists( $type, glsr()->reviewTypes )) {
294
			return $reviewCounts;
295
		}
296
		if( !array_key_exists( $type, $reviewCounts )) {
297
			$reviewCounts[$type] = [];
298
		}
299
		$reviewCounts = $this->normalize( $reviewCounts );
300
		$reviewCounts[$type][$rating] = intval( $reviewCounts[$type][$rating] ) + 1;
301
		return $reviewCounts;
302
	}
303
304
	/**
305
	 * @return array
306
	 */
307
	protected function normalize( array $reviewCounts )
308
	{
309
		if( empty( $reviewCounts )) {
310
			$reviewCounts = [[]];
311
		}
312
		foreach( $reviewCounts as &$counts ) {
313
			foreach( range( 0, Rating::MAX_RATING ) as $index ) {
314
				if( isset( $counts[$index] ))continue;
315
				$counts[$index] = 0;
316
			}
317
			ksort( $counts );
318
		}
319
		return $reviewCounts;
320
	}
321
322
	/**
323
	 * @param int $lastPostId
324
	 * @param int $limit
325
	 * @return void|array
326
	 */
327 1
	protected function queryReviews( array $args = [], $lastPostId, $limit )
328
	{
329 1
		$args = wp_parse_args( $args, array_fill_keys( ['post_id', 'term_id'], '' ));
330 1
		if( empty( array_filter( $args ))) {
331 1
			return glsr( SqlQueries::class )->getReviewCounts( $lastPostId, $limit );
332
		}
333
		if( !empty( $args['post_id'] )) {
334
			return glsr( SqlQueries::class )->getReviewPostCounts( $args['post_id'], $lastPostId, $limit );
335
		}
336
		if( !empty( $args['term_id'] )) {
337
			return glsr( SqlQueries::class )->getReviewTermCounts( $args['term_id'], $lastPostId, $limit );
338
		}
339
	}
340
}
341