Passed
Push — master ( 68f720...5e727b )
by Paul
10:53
created

ReviewController::isEditedReview()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
eloc 6
c 0
b 0
f 0
dl 0
loc 10
ccs 0
cts 7
cp 0
rs 10
cc 4
nc 4
nop 2
crap 20
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Controllers;
4
5
use GeminiLabs\SiteReviews\Commands\AssignPosts;
6
use GeminiLabs\SiteReviews\Commands\AssignTerms;
7
use GeminiLabs\SiteReviews\Commands\AssignUsers;
8
use GeminiLabs\SiteReviews\Commands\CreateReview;
9
use GeminiLabs\SiteReviews\Commands\ToggleStatus;
10
use GeminiLabs\SiteReviews\Commands\UnassignPosts;
11
use GeminiLabs\SiteReviews\Commands\UnassignTerms;
12
use GeminiLabs\SiteReviews\Commands\UnassignUsers;
13
use GeminiLabs\SiteReviews\Database;
14
use GeminiLabs\SiteReviews\Database\Cache;
15
use GeminiLabs\SiteReviews\Database\Query;
16
use GeminiLabs\SiteReviews\Database\ReviewManager;
17
use GeminiLabs\SiteReviews\Database\TaxonomyManager;
18
use GeminiLabs\SiteReviews\Defaults\RatingDefaults;
19
use GeminiLabs\SiteReviews\Helper;
20
use GeminiLabs\SiteReviews\Helpers\Arr;
21
use GeminiLabs\SiteReviews\Helpers\Cast;
22
use GeminiLabs\SiteReviews\Review;
23
24
class ReviewController extends Controller
25
{
26
    /**
27
     * @return void
28
     * @action admin_action_approve
29
     */
30
    public function approve()
31
    {
32
        if (glsr()->id == filter_input(INPUT_GET, 'plugin')) {
33
            check_admin_referer('approve-review_'.($postId = $this->getPostId()));
0 ignored issues
show
Bug introduced by
The function check_admin_referer 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

33
            /** @scrutinizer ignore-call */ 
34
            check_admin_referer('approve-review_'.($postId = $this->getPostId()));
Loading history...
34
            $this->execute(new ToggleStatus($postId, 'publish'));
35
            wp_safe_redirect(wp_get_referer());
0 ignored issues
show
Bug introduced by
The function wp_get_referer 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

35
            wp_safe_redirect(/** @scrutinizer ignore-call */ wp_get_referer());
Loading history...
Bug introduced by
The function wp_safe_redirect 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

35
            /** @scrutinizer ignore-call */ 
36
            wp_safe_redirect(wp_get_referer());
Loading history...
36
            exit;
37
        }
38
    }
39
40
    /**
41
     * @param array $posts
42
     * @return array
43
     * @filter the_posts
44
     */
45
    public function filterPostsToCacheReviews($posts)
46
    {
47
        $reviews = array_filter($posts, function ($post) {
48
            return glsr()->post_type === $post->post_type;
49
        });
50
        if ($postIds = wp_list_pluck($reviews, 'ID')) {
0 ignored issues
show
Bug introduced by
The function wp_list_pluck 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

50
        if ($postIds = /** @scrutinizer ignore-call */ wp_list_pluck($reviews, 'ID')) {
Loading history...
51
            glsr(Query::class)->reviews([], $postIds); // this caches the associated Review objects
52
        }
53
        return $posts;
54
    }
55
56
    /**
57
     * @param string $operator
58
     * @return string
59
     * @filter site-reviews/query/sql/clause/operator
60
     */
61 7
    public function filterSqlClauseOperator($operator)
62
    {
63 7
        $operators = ['loose' => 'OR', 'strict' => 'AND'];
64 7
        return Arr::get($operators, glsr_get_option('reviews.assignment', 'strict', 'string'), $operator);
65
    }
66
67
    /**
68
     * Triggered when one or more categories are added or removed from a review.
69
     *
70
     * @param int $postId
71
     * @param array $terms
72
     * @param array $newTTIds
73
     * @param string $taxonomy
74
     * @param bool $append
75
     * @param array $oldTTIds
76
     * @return void
77
     * @action set_object_terms
78
     */
79 12
    public function onAfterChangeAssignedTerms($postId, $terms, $newTTIds, $taxonomy, $append, $oldTTIds)
80
    {
81 12
        if (Review::isReview($postId)) {
82 2
            $review = glsr(Query::class)->review($postId);
83 2
            $diff = $this->getAssignedDiffs($oldTTIds, $newTTIds);
84 2
            $this->execute(new UnassignTerms($review, $diff['old']));
85 2
            $this->execute(new AssignTerms($review, $diff['new']));
86
        }
87 12
    }
88
89
    /**
90
     * Triggered when a post status changes or when a review is approved|unapproved|trashed.
91
     *
92
     * @param string $oldStatus
93
     * @param string $newStatus
94
     * @param \WP_Post $post
95
     * @return void
96
     * @action transition_post_status
97
     */
98 15
    public function onAfterChangeStatus($newStatus, $oldStatus, $post)
99
    {
100 15
        if (in_array($oldStatus, ['new', $newStatus])) {
101 15
            return;
102
        }
103
        $isPublished = 'publish' === $newStatus;
104
        if (Review::isReview($post)) {
105
            glsr(ReviewManager::class)->update($post->ID, ['is_approved' => $isPublished]);
106
        } else {
107
            glsr(ReviewManager::class)->updateAssignedPost($post->ID, $isPublished);
108
        }
109
    }
110
111
    /**
112
     * Triggered when a review's assigned post IDs are updated.
113
     *
114
     * @return void
115
     * @action site-reviews/review/updated/post_ids
116
     */
117
    public function onChangeAssignedPosts(Review $review, array $postIds = [])
118
    {
119
        $diff = $this->getAssignedDiffs($review->assigned_posts, $postIds);
120
        $this->execute(new UnassignPosts($review, $diff['old']));
121
        $this->execute(new AssignPosts($review, $diff['new']));
122
    }
123
124
    /**
125
     * Triggered when a review's assigned users IDs are updated.
126
     *
127
     * @return void
128
     * @action site-reviews/review/updated/user_ids
129
     */
130
    public function onChangeAssignedUsers(Review $review, array $userIds = [])
131
    {
132
        $diff = $this->getAssignedDiffs($review->assigned_users, $userIds);
133
        $this->execute(new UnassignUsers($review, $diff['old']));
134
        $this->execute(new AssignUsers($review, $diff['new']));
135
    }
136
137
    /**
138
     * Triggered after a review is created.
139
     *
140
     * @return void
141
     * @action site-reviews/review/created
142
     */
143 13
    public function onCreatedReview(Review $review, CreateReview $command)
144
    {
145 13
        $this->execute(new AssignPosts($review, $command->assigned_posts));
146 13
        $this->execute(new AssignUsers($review, $command->assigned_users));
147 13
    }
148
149
    /**
150
     * Triggered when a review is created.
151
     *
152
     * @param int $postId
153
     * @return void
154
     * @action site-reviews/review/create
155
     */
156 13
    public function onCreateReview($postId, CreateReview $command)
157
    {
158 13
        $values = glsr()->args($command->toArray()); // this filters the values
159 13
        $data = glsr(RatingDefaults::class)->restrict($values->toArray());
160 13
        $data['review_id'] = $postId;
161 13
        $data['is_approved'] = 'publish' === get_post_status($postId);
0 ignored issues
show
Bug introduced by
The function get_post_status 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

161
        $data['is_approved'] = 'publish' === /** @scrutinizer ignore-call */ get_post_status($postId);
Loading history...
162 13
        if (false === glsr(Database::class)->insert('ratings', $data)) {
163
            wp_delete_post($postId, true); // remove post as review was not created
0 ignored issues
show
Bug introduced by
The function wp_delete_post 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

163
            /** @scrutinizer ignore-call */ 
164
            wp_delete_post($postId, true); // remove post as review was not created
Loading history...
164
            return;
165
        }
166 13
        if (!empty($values->response)) {
167
            glsr(Database::class)->metaSet($postId, 'response', $values->response); // save the response if one is provided
168
        }
169 13
        glsr(TaxonomyManager::class)->setTerms($postId, $values->assigned_terms); // terms are assigned with the set_object_terms hook
170 13
        foreach ($values->custom as $key => $value) {
171
            glsr(Database::class)->metaSet($postId, 'custom_'.$key, $value);
172
        }
173 13
    }
174
175
    /**
176
     * Triggered when a review or other post type is deleted and the posts table uses the MyISAM engine.
177
     * @param int $postId
178
     * @param \WP_Post $post
179
     * @return void
180
     * @action deleted_post
181
     */
182
    public function onDeletePost($postId, $post)
183
    {
184
        if (glsr()->post_type === $post->post_type) {
185
            $this->onDeleteReview($postId);
186
            return;
187
        }
188
        $reviews = glsr(Query::class)->reviews([
189
            'assigned_posts' => $postId,
190
            'per_page' => -1,
191
            'status' => 'all',
192
        ]);
193
        if (glsr(Database::class)->delete('assigned_posts', ['post_id' => $postId])) {
194
            array_walk($reviews, function ($review) {
195
                glsr(Cache::class)->delete($review->ID, 'reviews');
196
            });
197
        }
198
    }
199
200
    /**
201
     * Triggered when a review is deleted and the posts table uses the MyISAM engine.
202
     * @param int $reviewId
203
     * @return void
204
     * @see $this->onDeletePost()
205
     */
206
    public function onDeleteReview($reviewId)
207
    {
208
        if (glsr(Database::class)->delete('ratings', ['review_id' => $reviewId])) {
209
            glsr(Cache::class)->delete($reviewId, 'reviews');
210
        }
211
    }
212
213
    /**
214
     * Triggered when a user is deleted and the users table uses the MyISAM engine.
215
     * @param int $userId
216
     * @return void
217
     * @action deleted_user
218
     */
219
    public function onDeleteUser($userId)
220
    {
221
        $reviews = glsr(Query::class)->reviews([
222
            'assigned_users' => $userId,
223
            'per_page' => -1,
224
            'status' => 'all',
225
        ]);
226
        if (glsr(Database::class)->delete('assigned_users', ['user_id' => $userId])) {
227
            array_walk($reviews, function ($review) {
228
                glsr(Cache::class)->delete($review->ID, 'reviews');
229
            });
230
        }
231
    }
232
233
    /**
234
     * Triggered when a review is edited or trashed.
235
     * It's unnecessary to trigger a term recount as this is done by the set_object_terms hook
236
     * We need to use "edit_post" to support revisions (vs "save_post").
237
     *
238
     * @param int $postId
239
     * @param \WP_Post $post
240
     * @param \WP_Post $oldPost
241
     * @return void
242
     * @action post_updated
243
     */
244
    public function onEditReview($postId, $post, $oldPost)
245
    {
246
        if (!glsr()->can('edit_posts') || !$this->isEditedReview($post, $oldPost)) {
247
            return;
248
        }
249
        $review = glsr(Query::class)->review($postId);
250
        if ('post' === glsr_current_screen()->base) {
251
            $this->updateReview($review);
252
        } else {
253
            $this->bulkUpdateReview($review);
254
        }
255
    }
256
257
    /**
258
     * @return void
259
     * @action admin_action_unapprove
260
     */
261
    public function unapprove()
262
    {
263
        if (glsr()->id == filter_input(INPUT_GET, 'plugin')) {
264
            check_admin_referer('unapprove-review_'.($postId = $this->getPostId()));
0 ignored issues
show
Bug introduced by
The function check_admin_referer 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

264
            /** @scrutinizer ignore-call */ 
265
            check_admin_referer('unapprove-review_'.($postId = $this->getPostId()));
Loading history...
265
            $this->execute(new ToggleStatus($postId, 'pending'));
266
            wp_safe_redirect(wp_get_referer());
0 ignored issues
show
Bug introduced by
The function wp_get_referer 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

266
            wp_safe_redirect(/** @scrutinizer ignore-call */ wp_get_referer());
Loading history...
Bug introduced by
The function wp_safe_redirect 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

266
            /** @scrutinizer ignore-call */ 
267
            wp_safe_redirect(wp_get_referer());
Loading history...
267
            exit;
268
        }
269
    }
270
271
    /**
272
     * @return void
273
     */
274
    protected function bulkUpdateReview(Review $review)
275
    {
276
        if ($assignedPostIds = filter_input(INPUT_GET, 'post_ids', FILTER_SANITIZE_NUMBER_INT, FILTER_FORCE_ARRAY)) {
277
            glsr()->action('review/updated/post_ids', $review, Cast::toArray($assignedPostIds)); // trigger a recount of assigned posts
278
        }
279
        if ($assignedUserIds = filter_input(INPUT_GET, 'user_ids', FILTER_SANITIZE_NUMBER_INT, FILTER_FORCE_ARRAY)) {
280
            glsr()->action('review/updated/user_ids', $review, Cast::toArray($assignedUserIds)); // trigger a recount of assigned users
281
        }
282
        $review = glsr(Query::class)->review($review->ID); // get a fresh copy of the review
283
        glsr()->action('review/saved', $review, []); // pass an empty array since review values are unchanged
284
    }
285
286
    /**
287
     * @return array
288
     */
289 2
    protected function getAssignedDiffs(array $existing, array $replacements)
290
    {
291 2
        sort($existing);
292 2
        sort($replacements);
293 2
        $new = $old = [];
294 2
        if ($existing !== $replacements) {
295 2
            $ignored = array_intersect($existing, $replacements);
296 2
            $new = array_diff($replacements, $ignored);
297 2
            $old = array_diff($existing, $ignored);
298
        }
299
        return [
300 2
            'new' => $new,
301 2
            'old' => $old,
302
        ];
303
    }
304
305
    /**
306
     * @param \WP_Post $post
307
     * @param \WP_Post $oldPost
308
     * @return bool
309
     */
310
    protected function isEditedReview($post, $oldPost)
311
    {
312
        if (glsr()->post_type !== $post->post_type) {
313
            return false;
314
        }
315
        if (in_array('trash', [$post->post_status, $oldPost->post_status])) {
316
            return false; // trashed posts cannot be edited
317
        }
318
        $input = 'edit' === glsr_current_screen()->base ? INPUT_GET : INPUT_POST;
319
        return 'glsr_action' !== filter_input($input, 'action'); // abort if not a proper post update (i.e. approve/unapprove)
320
    }
321
322
    /**
323
     * @return void
324
     */
325
    protected function updateReview(Review $review)
326
    {
327
        $assignedPostIds = filter_input(INPUT_POST, 'post_ids', FILTER_SANITIZE_NUMBER_INT, FILTER_FORCE_ARRAY);
328
        $assignedUserIds = filter_input(INPUT_POST, 'user_ids', FILTER_SANITIZE_NUMBER_INT, FILTER_FORCE_ARRAY);
329
        glsr()->action('review/updated/post_ids', $review, Cast::toArray($assignedPostIds)); // trigger a recount of assigned posts
330
        glsr()->action('review/updated/user_ids', $review, Cast::toArray($assignedUserIds)); // trigger a recount of assigned users
331
        glsr(MetaboxController::class)->saveResponseMetabox($review);
332
        $submittedValues = Helper::filterInputArray(glsr()->id);
333
        if (Arr::get($submittedValues, 'is_editing_review')) {
334
            $submittedValues['rating'] = Arr::get($submittedValues, 'rating');
335
            glsr(ReviewManager::class)->update($review->ID, $submittedValues);
336
            glsr(ReviewManager::class)->updateCustom($review->ID, $submittedValues);
337
        }
338
        $review = glsr(Query::class)->review($review->ID); // get a fresh copy of the review
339
        glsr()->action('review/saved', $review, $submittedValues);
340
    }
341
}
342