Passed
Push — master ( ece31d...41b8a6 )
by Paul
10:20 queued 04:17
created

CountsManager::increaseRating()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.1406

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 7
c 1
b 0
f 0
nc 3
nop 3
dl 0
loc 11
ccs 6
cts 8
cp 0.75
crap 3.1406
rs 10
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Database;
4
5
use GeminiLabs\SiteReviews\Application;
6
use GeminiLabs\SiteReviews\Database;
7
use GeminiLabs\SiteReviews\Modules\Polylang;
8
use GeminiLabs\SiteReviews\Modules\Rating;
9
use GeminiLabs\SiteReviews\Review;
10
use WP_Post;
11
12
class CountsManager
13
{
14
    const LIMIT = 500;
15
    const META_AVERAGE = '_glsr_average';
16
    const META_COUNT = '_glsr_count';
17
    const META_RANKING = '_glsr_ranking';
18
19
    /**
20
     * @return array
21
     * @todo verify the additional type checks are needed
22
     */
23 1
    public function buildCounts(array $args = [])
24
    {
25 1
        $counts = [];
26 1
        $query = $this->queryReviews($args);
27 1
        while ($query) {
28 1
            $types = array_keys(array_flip(glsr_array_column($query->reviews, 'type')));
29 1
            $types = array_unique(array_merge(['local'], $types));
30 1
            foreach ($types as $type) {
31 1
                $type = $this->normalizeType($type);
32 1
                if (isset($counts[$type])) {
33
                    continue;
34
            }
35 1
                $counts[$type] = array_fill_keys(range(0, glsr()->constant('MAX_RATING', Rating::class)), 0);
36
            }
37 1
            foreach ($query->reviews as $review) {
38
                $type = $this->normalizeType($review->type);
39
                ++$counts[$type][$review->rating];
40
            }
41 1
            $query = $query->has_more
42
                ? $this->queryReviews($args, end($query->reviews)->ID)
43 1
                : false;
44
        }
45 1
        return $counts;
46
    }
47
48
    /**
49
     * @param int $postId
50
     * @return array
51
     */
52
    public function buildPostCounts($postId)
53
    {
54
        return $this->buildCounts(['post_ids' => [$postId]]);
55
    }
56
57
    /**
58
     * @param int $termTaxonomyId
59
     * @return array
60
     */
61
    public function buildTermCounts($termTaxonomyId)
62
    {
63
        return $this->buildCounts(['term_ids' => [$termTaxonomyId]]);
64
    }
65
66
    /**
67
     * @return void
68
     */
69 1
    public function countAll()
70
    {
71 1
        $terms = glsr(Database::class)->getTerms(['fields' => 'all']);
72 1
        foreach ($terms as $term) {
73
            $this->setTermCounts($term->term_id, $this->buildTermCounts($term->term_taxonomy_id));
74
        }
75 1
        $postIds = glsr(SqlQueries::class)->getReviewsMeta('assigned_to');
76 1
        foreach ($postIds as $postId) {
77
            $this->setPostCounts($postId, $this->buildPostCounts($postId));
78
        }
79 1
        $this->setCounts($this->buildCounts());
80 1
    }
81
82
    /**
83
     * @return void
84
     */
85
    public function decrease(Review $review)
86
    {
87
        $this->decreaseCounts($review);
88
        $this->decreasePostCounts($review);
89
        $this->decreaseTermCounts($review);
90
    }
91
92
    /**
93
     * @return void
94
     */
95
    public function decreaseCounts(Review $review)
96
    {
97
        $this->setCounts($this->decreaseRating(
98
            $this->getCounts(),
99
            $review->review_type,
100
            $review->rating
101
        ));
102
    }
103
104
    /**
105
     * @return void
106
     */
107
    public function decreasePostCounts(Review $review)
108
    {
109
        if (empty($counts = $this->getPostCounts($review->assigned_to))) {
110
            return;
111
        }
112
        $counts = $this->decreaseRating($counts, $review->review_type, $review->rating);
113
        $this->setPostCounts($review->assigned_to, $counts);
114
    }
115
116
    /**
117
     * @return void
118
     */
119
    public function decreaseTermCounts(Review $review)
120
    {
121
        foreach ($review->term_ids as $termId) {
122
            if (empty($counts = $this->getTermCounts($termId))) {
123
                continue;
124
            }
125
            $counts = $this->decreaseRating($counts, $review->review_type, $review->rating);
126
            $this->setTermCounts($termId, $counts);
127
        }
128
    }
129
130
    /**
131
     * @return array
132
     */
133
    public function flatten(array $reviewCounts, array $args = [])
134
    {
135
        $counts = [];
136
        array_walk_recursive($reviewCounts, function ($num, $index) use (&$counts) {
137
            $counts[$index] = $num + intval(glsr_get($counts, $index, 0));
138
        });
139
        $args = wp_parse_args($args, [
140
            'max' => glsr()->constant('MAX_RATING', Rating::class),
141
            'min' => glsr()->constant('MIN_RATING', Rating::class),
142
        ]);
143
        foreach ($counts as $index => &$num) {
144
            if ($index >= intval($args['min']) && $index <= intval($args['max'])) {
145
                continue;
146
            }
147
            $num = 0;
148
        }
149
        return $counts;
150
    }
151
152
    /**
153
     * @return array
154
     */
155
    public function get(array $args = [])
156
    {
157
        $args = $this->normalizeArgs($args);
158
        $counts = [];
159
        if ($this->isMixedCount($args)) {
160
            $counts = [$this->buildCounts($args)]; // force query the database
161
        } else {
162
            foreach ($args['post_ids'] as $postId) {
163
                $counts[] = $this->getPostCounts($postId);
164
        }
165
            foreach ($args['term_ids'] as $termId) {
166
                $counts[] = $this->getTermCounts($termId);
167
            }
168
            if (empty($counts)) {
169
                $counts[] = $this->getCounts();
170
            }
171
        }
172
        return in_array($args['type'], ['', 'all'])
173
            ? $this->normalize([$this->flatten($counts)])
174
            : $this->normalize(glsr_array_column($counts, $args['type']));
175
    }
176
177
    /**
178
     * @return array
179
     */
180 1
    public function getCounts()
181
    {
182 1
        $counts = glsr(OptionManager::class)->get('counts', []);
183 1
        if (!is_array($counts)) {
184
            glsr_log()->error('Review counts is not an array; possibly due to incorrectly imported reviews.')->debug($counts);
185
            return [];
186
        }
187 1
        return $counts;
188
    }
189
190
    /**
191
     * @param int $postId
192
     * @return array
193
     */
194
    public function getPostCounts($postId)
195
    {
196
        return array_filter((array) get_post_meta($postId, static::META_COUNT, true));
197
    }
198
199
    /**
200
     * @param int $termId
201
     * @return array
202
     */
203
    public function getTermCounts($termId)
204
    {
205
        return array_filter((array) get_term_meta($termId, static::META_COUNT, true));
206
    }
207
208
    /**
209
     * @return void
210
     */
211
    public function increase(Review $review)
212
    {
213
        $this->increaseCounts($review);
214
        $this->increasePostCounts($review);
215
        $this->increaseTermCounts($review);
216
    }
217
218
    /**
219
     * @return void
220
     */
221 1
    public function increaseCounts(Review $review)
222
    {
223 1
        if (empty($counts = $this->getCounts())) {
224
            $counts = $this->buildCounts();
225
        }
226 1
        $this->setCounts($this->increaseRating($counts, $review->review_type, $review->rating));
227 1
    }
228
229
    /**
230
     * @return void
231
     */
232 1
    public function increasePostCounts(Review $review)
233
    {
234 1
        if (!(get_post($review->assigned_to) instanceof WP_Post)) {
235 1
            return;
236
        }
237
        $counts = $this->getPostCounts($review->assigned_to);
238
        $counts = empty($counts)
239
            ? $this->buildPostCounts($review->assigned_to)
240
            : $this->increaseRating($counts, $review->review_type, $review->rating);
241
        $this->setPostCounts($review->assigned_to, $counts);
242
    }
243
244
    /**
245
     * @return void
246
     */
247
    public function increaseTermCounts(Review $review)
248
    {
249
        $terms = glsr(ReviewManager::class)->normalizeTerms(implode(',', $review->term_ids));
250
        foreach ($terms as $term) {
251
            $counts = $this->getTermCounts($term['term_id']);
252
            $counts = empty($counts)
253
                ? $this->buildTermCounts($term['term_taxonomy_id'])
254
                : $this->increaseRating($counts, $review->review_type, $review->rating);
255
            $this->setTermCounts($term['term_id'], $counts);
256
        }
257
    }
258
259
    /**
260
     * @return void
261
     */
262 1
    public function setCounts(array $reviewCounts)
263
    {
264 1
        glsr(OptionManager::class)->set('counts', $reviewCounts);
265 1
    }
266
267
    /**
268
     * @param int $postId
269
     * @return void
270
     */
271
    public function setPostCounts($postId, array $reviewCounts)
272
    {
273
        $ratingCounts = $this->flatten($reviewCounts);
274
        update_post_meta($postId, static::META_COUNT, $reviewCounts);
275
        update_post_meta($postId, static::META_AVERAGE, glsr(Rating::class)->getAverage($ratingCounts));
276
        update_post_meta($postId, static::META_RANKING, glsr(Rating::class)->getRanking($ratingCounts));
277
    }
278
279
    /**
280
     * @param int $termId
281
     * @return void
282
     */
283
    public function setTermCounts($termId, array $reviewCounts)
284
    {
285
        $term = get_term($termId, Application::TAXONOMY);
286
        if (!isset($term->term_id)) {
287
            return;
288
        }
289
        $ratingCounts = $this->flatten($reviewCounts);
290
        update_term_meta($termId, static::META_COUNT, $reviewCounts);
291
        update_term_meta($termId, static::META_AVERAGE, glsr(Rating::class)->getAverage($ratingCounts));
292
        update_term_meta($termId, static::META_RANKING, glsr(Rating::class)->getRanking($ratingCounts));
293
    }
294
295
    /**
296
     * @param string $type
297
     * @param int $rating
298
     * @return array
299
     */
300
    protected function decreaseRating(array $reviewCounts, $type, $rating)
301
    {
302
        if (isset($reviewCounts[$type][$rating])) {
303
            $reviewCounts[$type][$rating] = max(0, $reviewCounts[$type][$rating] - 1);
304
        }
305
        return $reviewCounts;
306
    }
307
308
    /**
309
     * @param string $type
310
     * @param int $rating
311
     * @return array
312
     */
313 1
    protected function increaseRating(array $reviewCounts, $type, $rating)
314
    {
315 1
        if (!array_key_exists($type, glsr()->reviewTypes)) {
316
            return $reviewCounts;
317
        }
318 1
        if (!array_key_exists($type, $reviewCounts)) {
319
            $reviewCounts[$type] = [];
320
        }
321 1
        $reviewCounts = $this->normalize($reviewCounts);
322 1
        $reviewCounts[$type][$rating] = intval($reviewCounts[$type][$rating]) + 1;
323 1
        return $reviewCounts;
324
    }
325
326
    /**
327
     * @return bool
328
     */
329
    protected function isMixedCount(array $args)
330
    {
331
        return !empty($args['post_ids']) && !empty($args['term_ids']);
332
    }
333
334
    /**
335
     * @return array
336
     */
337 1
    protected function normalize(array $reviewCounts)
338
    {
339 1
        if (empty($reviewCounts)) {
340
            $reviewCounts = [[]];
341
        }
342 1
        foreach ($reviewCounts as &$counts) {
343 1
            foreach (range(0, glsr()->constant('MAX_RATING', Rating::class)) as $index) {
344 1
                if (isset($counts[$index])) {
345 1
                    continue;
346
                }
347
                $counts[$index] = 0;
348
            }
349 1
            ksort($counts);
350
        }
351 1
        return $reviewCounts;
352
    }
353
354
    /**
355
     * @return array
356
     */
357
    protected function normalizeArgs(array $args)
358
    {
359
        $args = wp_parse_args(array_filter($args), [
360
            'post_ids' => [],
361
            'term_ids' => [],
362
            'type' => 'local',
363
        ]);
364
        $args['post_ids'] = glsr(Polylang::class)->getPostIds($args['post_ids']);
365
        $args['type'] = $this->normalizeType($args['type']);
366
        return $args;
367
    }
368
369
    /**
370
     * @param string $type
371
     * @return string
372
     */
373 1
    protected function normalizeType($type)
374
    {
375 1
        return empty($type) || !is_string($type)
376
            ? 'local'
377 1
            : $type;
378
    }
379
380
    /**
381
     * @param int $lastPostId
382
     * @return object
383
     */
384 1
    protected function queryReviews(array $args = [], $lastPostId = 0)
385
    {
386 1
        $reviews = glsr(SqlQueries::class)->getReviewCounts($args, $lastPostId, static::LIMIT);
387 1
        $hasMore = is_array($reviews)
388 1
            ? count($reviews) == static::LIMIT
389 1
            : false;
390
        return (object) [
391 1
            'has_more' => $hasMore,
392 1
            'reviews' => $reviews,
393
        ];
394
    }
395
}
396