Passed
Push — hotfix/fix_counts_manager ( 20120a )
by Paul
06:22 queued 01:24
created

CountsManager::setCounts()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
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 LIMIT = 500;
18
	const META_AVERAGE = '_glsr_average';
19
	const META_COUNT = '_glsr_count';
20
	const META_RANKING = '_glsr_ranking';
21
22
	/**
23
	 * @return array
24
	 */
25 1
	public function buildCounts()
26
	{
27 1
		return $this->build();
28
	}
29
30
	/**
31
	 * @param int $postId
32
	 * @return array
33
	 */
34
	public function buildPostCounts( $postId )
35
	{
36
		return $this->build( ['post_id' => $postId] );
37
	}
38
39
	/**
40
	 * @param int $termTaxonomyId
41
	 * @return array
42
	 */
43
	public function buildTermCounts( $termTaxonomyId )
44
	{
45
		return $this->build( ['term_taxonomy_id' => $termTaxonomyId] );
46
	}
47
48
	/**
49
	 * @return void
50
	 */
51
	public function decrease( Review $review )
52
	{
53
		$this->decreaseCounts( $review );
54
		$this->decreasePostCounts( $review );
55
		$this->decreaseTermCounts( $review );
56
	}
57
58
	/**
59
	 * @return void
60
	 */
61
	public function decreaseCounts( Review $review )
62
	{
63
		$this->setCounts( $this->decreaseRating(
64
			$this->getCounts(),
65
			$review->review_type,
66
			$review->rating
67
		));
68
	}
69
70
	/**
71
	 * @return void
72
	 */
73
	public function decreasePostCounts( Review $review )
74
	{
75
		if( empty( $counts = $this->getPostCounts( $review->assigned_to )))return;
76
		$counts = $this->decreaseRating( $counts, $review->review_type, $review->rating );
77
		$this->setPostCounts( $review->assigned_to, $counts );
78
	}
79
80
	/**
81
	 * @return void
82
	 */
83
	public function decreaseTermCounts( Review $review )
84
	{
85
		foreach( $review->term_ids as $termId ) {
86
			if( empty( $counts = $this->getTermCounts( $termId )))continue;
87
			$counts = $this->decreaseRating( $counts, $review->review_type, $review->rating );
88
			$this->setTermCounts( $termId, $counts );
89
		}
90
	}
91
92
	/**
93
	 * @return array
94
	 */
95
	public function flatten( array $reviewCounts, array $args = [] )
96
	{
97
		$counts = [];
98
		array_walk_recursive( $reviewCounts, function( $num, $index ) use( &$counts ) {
99
			$counts[$index] = $num + intval( glsr_get( $counts, $index, 0 ));
0 ignored issues
show
Bug introduced by
The function glsr_get was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

99
			$counts[$index] = $num + intval( /** @scrutinizer ignore-call */ glsr_get( $counts, $index, 0 ));
Loading history...
100
		});
101
		$args = wp_parse_args( $args, [
102
			'max' => Rating::MAX_RATING,
103
			'min' => Rating::MIN_RATING,
104
		]);
105
		foreach( $counts as $index => &$num ) {
106
			if( $index >= intval( $args['min'] ) && $index <= intval( $args['max'] ))continue;
107
			$num = 0;
108
		}
109
		return $counts;
110
	}
111
112
	/**
113
	 * @return array
114
	 */
115
	public function get( array $args = [] )
116
	{
117
		$args = $this->normalizeArgs( $args );
118
119
		if( !empty( $args['post_ids'] ) && !empty( $args['term_ids'] )) {
120
			$counts = [$this->build( $args )];
121
		}
122
		else {
123
			$counts = [];
124
			foreach( $args['post_ids'] as $postId ) {
125
				// reviews can only be assigned to a single post...:)
126
				$counts[] = $this->getPostCounts( $postId );
127
			}
128
			foreach( $args['term_ids'] as $termId ) {
129
				// reviews can be assigned to many terms...:(
130
				// @todo if multiple ids are provided, a query must be used!
131
				$counts[] = $this->getTermCounts( $termId );
132
			}
133
			if( empty( $counts )) {
134
				$counts[] = $this->getCounts();
135
			}
136
		}
137
		return in_array( $args['type'], ['', 'all'] )
138
			? $this->normalize( [$this->flatten( $counts )] )
139
			: $this->normalize( glsr_array_column( $counts, $args['type'] ));
140
	}
141
142
	/**
143
	 * @return array
144
	 */
145 1
	public function getCounts()
146
	{
147 1
		$counts = glsr( OptionManager::class )->get( 'counts', [] );
148 1
		if( !is_array( $counts )) {
149
			glsr_log()->error( '$counts is not an array' )->debug( $counts );
150
			return [];
151
		}
152 1
		return $counts;
153
	}
154
155
	/**
156
	 * @param int $postId
157
	 * @return array
158
	 */
159
	public function getPostCounts( $postId )
160
	{
161
		return array_filter( (array)get_post_meta( $postId, static::META_COUNT, true ));
162
	}
163
164
	/**
165
	 * @param int $termId
166
	 * @return array
167
	 */
168
	public function getTermCounts( $termId )
169
	{
170
		return array_filter( (array)get_term_meta( $termId, static::META_COUNT, true ));
171
	}
172
173
	/**
174
	 * @return void
175
	 */
176 1
	public function increase( Review $review )
177
	{
178 1
		$this->increaseCounts( $review );
179 1
		$this->increasePostCounts( $review );
180 1
		$this->increaseTermCounts( $review );
181 1
	}
182
183
	/**
184
	 * @return void
185
	 */
186 1
	public function increaseCounts( Review $review )
187
	{
188 1
		if( empty( $counts = $this->getCounts() )) {
189 1
			$counts = $this->buildCounts();
190
		}
191 1
		$this->setCounts( $this->increaseRating( $counts, $review->review_type, $review->rating ));
192 1
	}
193
194
	/**
195
	 * @return void
196
	 */
197 1
	public function increasePostCounts( Review $review )
198
	{
199 1
		if( !( get_post( $review->assigned_to ) instanceof WP_Post ))return;
200
		$counts = $this->getPostCounts( $review->assigned_to );
201
		$counts = empty( $counts )
202
			? $this->buildPostCounts( $review->assigned_to )
203
			: $this->increaseRating( $counts, $review->review_type, $review->rating );
204
		$this->setPostCounts( $review->assigned_to, $counts );
205
	}
206
207
	/**
208
	 * @return void
209
	 */
210 1
	public function increaseTermCounts( Review $review )
211
	{
212 1
		$terms = glsr( ReviewManager::class )->normalizeTerms( implode( ',', $review->term_ids ));
213 1
		foreach( $terms as $term ) {
214
			$counts = $this->getTermCounts( $term['term_id'] );
215
			$counts = empty( $counts )
216
				? $this->buildTermCounts( $term['term_taxonomy_id'] )
217
				: $this->increaseRating( $counts, $review->review_type, $review->rating );
218
			$this->setTermCounts( $term['term_id'], $counts );
219
		}
220 1
	}
221
222
	/**
223
	 * @return void
224
	 */
225 1
	public function setCounts( array $reviewCounts )
226
	{
227 1
		glsr( OptionManager::class )->set( 'counts', $reviewCounts );
228 1
	}
229
230
	/**
231
	 * @param int $postId
232
	 * @return void
233
	 */
234
	public function setPostCounts( $postId, array $reviewCounts )
235
	{
236
		$ratingCounts = $this->flatten( $reviewCounts );
237
		update_post_meta( $postId, static::META_COUNT, $reviewCounts );
238
		update_post_meta( $postId, static::META_AVERAGE, glsr( Rating::class )->getAverage( $ratingCounts ));
239
		update_post_meta( $postId, static::META_RANKING, glsr( Rating::class )->getRanking( $ratingCounts ));
240
	}
241
242
	/**
243
	 * @param int $termId
244
	 * @return void
245
	 */
246
	public function setTermCounts( $termId, array $reviewCounts )
247
	{
248
		$term = get_term( $termId, Application::TAXONOMY );
249
		if( !isset( $term->term_id ))return;
250
		$ratingCounts = $this->flatten( $reviewCounts );
251
		update_term_meta( $termId, static::META_COUNT, $reviewCounts );
252
		update_term_meta( $termId, static::META_AVERAGE, glsr( Rating::class )->getAverage( $ratingCounts ));
253
		update_term_meta( $termId, static::META_RANKING, glsr( Rating::class )->getRanking( $ratingCounts ));
254
	}
255
256
	/**
257
	 * @param int $limit
258
	 * @return array
259
	 * @todo verify the additional type checks are needed
260
	 */
261 1
	protected function build( array $args = [] )
262
	{
263 1
		$counts = [];
264 1
		$lastPostId = 0;
265 1
		while( $reviews = $this->queryReviews( $args, $lastPostId )) {
266
			$types = array_keys( array_flip( glsr_array_column( $reviews, 'type' )));
267
			$types = array_unique( array_merge( ['local'], $types ));
268
			foreach( $types as $type ) {
269
				$type = $this->normalizeType( $type );
270
				if( isset( $counts[$type] ))continue;
271
				$counts[$type] = array_fill_keys( range( 0, Rating::MAX_RATING ), 0 );
272
			}
273
			foreach( $reviews as $review ) {
274
				$type = $this->normalizeType( $review->type );
275
				$counts[$type][$review->rating]++;
276
			}
277
			$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 1
			$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 1
				$counts[$index] = 0;
325
			}
326 1
			ksort( $counts );
327
		}
328 1
		return $reviewCounts;
329
	}
330
331
	/**
332
	 * @return array
333
	 */
334
	protected function normalizeArgs( array $args )
335
	{
336
		$args = wp_parse_args( array_filter( $args ), [
337
			'post_ids' => [],
338
			'term_ids' => [],
339
			'type' => 'local',
340
		]);
341
		$args['post_ids'] = glsr( Polylang::class )->getPostIds( $args['post_ids'] );
342
		$args['type'] = $this->normalizeType( $args['type'] );
343
		return $args;
344
	}
345
346
	/**
347
	 * @param string $type
348
	 * @return string
349
	 */
350
	protected function normalizeType( $type )
351
	{
352
		return empty( $type ) || !is_string( $type )
353
			? 'local'
354
			: $type;
355
	}
356
357
	/**
358
	 * @param int $lastPostId
359
	 * @return void|array
360
	 */
361 1
	protected function queryReviews( array $args = [], $lastPostId )
362
	{
363 1
		return glsr( SqlQueries::class )->getReviewCounts( $args, $lastPostId, static::LIMIT );
364
	}
365
}
366