Passed
Push — master ( e99773...aaffa2 )
by Paul
03:44
created

CountsManager::increase()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
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 in_array( $args['type'], ['', 'all'] )
137
			? $this->normalize( [$this->flatten( $counts )] )
138
			: $this->normalize( array_column( $counts, $args['type'] ));
139
	}
140
141
	/**
142
	 * @return array
143
	 */
144 1
	public function getCounts()
145
	{
146 1
		$counts = glsr( OptionManager::class )->get( 'counts', [] );
147 1
		if( !is_array( $counts )) {
148
			glsr_log()->error( 'CountsManager: counts is not an array' )->debug( $counts );
149
			return [];
150
		}
151 1
		return $counts;
152
	}
153
154
	/**
155
	 * @param int $postId
156
	 * @return array
157
	 */
158
	public function getPostCounts( $postId )
159
	{
160
		return array_filter( (array)get_post_meta( $postId, static::META_COUNT, true ));
161
	}
162
163
	/**
164
	 * @param int $termId
165
	 * @return array
166
	 */
167
	public function getTermCounts( $termId )
168
	{
169
		return array_filter( (array)get_term_meta( $termId, static::META_COUNT, true ));
170
	}
171
172
	/**
173
	 * @return void
174
	 */
175 1
	public function increase( Review $review )
176
	{
177 1
		$this->increaseCounts( $review );
178 1
		$this->increasePostCounts( $review );
179 1
		$this->increaseTermCounts( $review );
180 1
	}
181
182
	/**
183
	 * @return void
184
	 */
185 1
	public function increaseCounts( Review $review )
186
	{
187 1
		if( empty( $counts = $this->getCounts() )) {
188 1
			$counts = $this->buildCounts();
189
		}
190 1
		$this->setCounts( $this->increaseRating(
191 1
			$counts,
192 1
			$review->review_type,
193 1
			$review->rating
194
		));
195 1
	}
196
197
	/**
198
	 * @return void
199
	 */
200 1
	public function increasePostCounts( Review $review )
201
	{
202 1
		if( !( get_post( $review->assigned_to ) instanceof WP_Post ))return;
203
		$counts = $this->getPostCounts( $review->assigned_to );
204
		$counts = empty( $counts )
205
			? $this->buildPostCounts( $review->assigned_to )
206
			: $this->increaseRating( $counts, $review->review_type, $review->rating );
207
		$this->setPostCounts( $review->assigned_to, $counts );
208
	}
209
210
	/**
211
	 * @return void
212
	 */
213 1
	public function increaseTermCounts( Review $review )
214
	{
215 1
		$termIds = glsr( ReviewManager::class )->normalizeTerms( implode( ',', $review->term_ids ));
216 1
		foreach( $termIds as $termId ) {
217
			$counts = $this->getTermCounts( $termId );
218
			$counts = empty( $counts )
219
				? $this->buildTermCounts( $termId )
220
				: $this->increaseRating( $counts, $review->review_type, $review->rating );
221
			$this->setTermCounts( $termId, $counts );
222
		}
223 1
	}
224
225
	/**
226
	 * @return void
227
	 */
228 1
	public function setCounts( array $reviewCounts )
229
	{
230 1
		glsr( OptionManager::class )->set( 'counts', $reviewCounts );
231 1
	}
232
233
	/**
234
	 * @param int $postId
235
	 * @return void
236
	 */
237
	public function setPostCounts( $postId, array $reviewCounts )
238
	{
239
		$ratingCounts = $this->flatten( $reviewCounts );
240
		update_post_meta( $postId, static::META_COUNT, $reviewCounts );
241
		update_post_meta( $postId, static::META_AVERAGE, glsr( Rating::class )->getAverage( $ratingCounts ));
242
		update_post_meta( $postId, static::META_RANKING, glsr( Rating::class )->getRanking( $ratingCounts ));
243
	}
244
245
	/**
246
	 * @param int $termId
247
	 * @return void
248
	 */
249
	public function setTermCounts( $termId, array $reviewCounts )
250
	{
251
		if( !term_exists( $termId ))return;
252
		$ratingCounts = $this->flatten( $reviewCounts );
253
		update_term_meta( $termId, static::META_COUNT, $reviewCounts );
254
		update_term_meta( $termId, static::META_AVERAGE, glsr( Rating::class )->getAverage( $ratingCounts ));
255
		update_term_meta( $termId, static::META_RANKING, glsr( Rating::class )->getRanking( $ratingCounts ));
256
	}
257
258
	/**
259
	 * @param int $limit
260
	 * @return array
261
	 */
262 1
	protected function build( $limit, array $args = [] )
263
	{
264 1
		$counts = [];
265 1
		$lastPostId = 0;
266 1
		while( $reviews = $this->queryReviews( $args, $lastPostId, $limit )) {
267 1
			$types = array_keys( array_flip( array_column( $reviews, 'type' )));
268 1
			foreach( $types as $type ) {
269 1
				if( isset( $counts[$type] ))continue;
270 1
				$type = $this->normalizeType( $type );
271 1
				$counts[$type] = array_fill_keys( range( 0, Rating::MAX_RATING ), 0 );
272
			}
273 1
			foreach( $reviews as $review ) {
274 1
				$type = $this->normalizeType( $review->type );
275 1
				$counts[$type][$review->rating]++;
276
			}
277 1
			$lastPostId = end( $reviews )->ID;
278
		}
279 1
		return $counts;
280
	}
281
282
	/**
283
	 * @param string $type
284
	 * @param int $rating
285
	 * @return array
286
	 */
287
	protected function decreaseRating( array $reviewCounts, $type, $rating )
288
	{
289
		if( isset( $reviewCounts[$type][$rating] )) {
290
			$reviewCounts[$type][$rating] = max( 0, $reviewCounts[$type][$rating] - 1 );
291
		}
292
		return $reviewCounts;
293
	}
294
295
	/**
296
	 * @param string $type
297
	 * @param int $rating
298
	 * @return array
299
	 */
300 1
	protected function increaseRating( array $reviewCounts, $type, $rating )
301
	{
302 1
		if( !array_key_exists( $type, glsr()->reviewTypes )) {
303
			return $reviewCounts;
304
		}
305 1
		if( !array_key_exists( $type, $reviewCounts )) {
306
			$reviewCounts[$type] = [];
307
		}
308 1
		$reviewCounts = $this->normalize( $reviewCounts );
309 1
		$reviewCounts[$type][$rating] = intval( $reviewCounts[$type][$rating] ) + 1;
310 1
		return $reviewCounts;
311
	}
312
313
	/**
314
	 * @return array
315
	 */
316 1
	protected function normalize( array $reviewCounts )
317
	{
318 1
		if( empty( $reviewCounts )) {
319
			$reviewCounts = [[]];
320
		}
321 1
		foreach( $reviewCounts as &$counts ) {
322 1
			foreach( range( 0, Rating::MAX_RATING ) as $index ) {
323 1
				if( isset( $counts[$index] ))continue;
324
				$counts[$index] = 0;
325
			}
326 1
			ksort( $counts );
327
		}
328 1
		return $reviewCounts;
329
	}
330
331
	/**
332
	 * @param string $type
333
	 * @return string
334
	 */
335 1
	protected function normalizeType( $type )
336
	{
337 1
		return empty( $type ) || !is_string( $type )
338
			? 'local'
339 1
			: $type;
340
	}
341
342
	/**
343
	 * @param int $lastPostId
344
	 * @param int $limit
345
	 * @return void|array
346
	 */
347 1
	protected function queryReviews( array $args = [], $lastPostId, $limit )
348
	{
349 1
		$args = wp_parse_args( $args, array_fill_keys( ['post_id', 'term_id'], '' ));
350 1
		if( empty( array_filter( $args ))) {
351 1
			return glsr( SqlQueries::class )->getReviewCounts( $lastPostId, $limit );
352
		}
353
		if( !empty( $args['post_id'] )) {
354
			return glsr( SqlQueries::class )->getReviewPostCounts( $args['post_id'], $lastPostId, $limit );
355
		}
356
		if( !empty( $args['term_id'] )) {
357
			return glsr( SqlQueries::class )->getReviewTermCounts( $args['term_id'], $lastPostId, $limit );
358
		}
359
	}
360
}
361