Passed
Push — master ( 56ba7b...1156c5 )
by Alexander
02:22
created

VoteAction::run()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 32
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 32
rs 8.439
cc 5
eloc 22
nc 4
nop 0
1
<?php
2
3
namespace hauntd\vote\actions;
4
5
use hauntd\vote\models\Vote;
6
use hauntd\vote\models\VoteAggregate;
7
use hauntd\vote\models\VoteForm;
8
use hauntd\vote\Module;
9
use hauntd\vote\events\VoteActionEvent;
10
use hauntd\vote\traits\ModuleTrait;
11
use Yii;
12
use yii\base\Action;
13
use yii\web\MethodNotAllowedHttpException;
14
use yii\web\Response;
15
16
/**
17
 * Class VoteAction
18
 * @package hauntd\vote\actions
19
 */
20
class VoteAction extends Action
21
{
22
    use ModuleTrait;
23
24
    const EVENT_BEFORE_VOTE = 'beforeVote';
25
    const EVENT_AFTER_VOTE = 'afterVote';
26
27
    /**
28
     * @return array
29
     * @throws MethodNotAllowedHttpException
30
     */
31
    public function run()
32
    {
33
        if (!Yii::$app->request->getIsAjax() || !Yii::$app->request->getIsPost()) {
34
            throw new MethodNotAllowedHttpException(Yii::t('vote', 'Forbidden method'), 405);
35
        }
36
37
        Yii::$app->response->format = Response::FORMAT_JSON;
38
        $module = $this->getModule();
39
        $form = new VoteForm();
40
        $form->load(Yii::$app->request->post());
41
        $this->trigger(self::EVENT_BEFORE_VOTE, $event = $this->createEvent($form, $response = []));
42
43
        if ($form->validate()) {
44
            $settings = $module->getSettingsForEntity($form->entity);
45
            if ($settings['type'] == Module::TYPE_VOTING) {
46
                $response = $this->processVote($form);
47
            } else {
48
                $response = $this->processToggle($form);
49
            }
50
            $response = array_merge($event->responseData, $response);
51
            $response['aggregate'] = VoteAggregate::findOne([
52
                'entity' => $module->encodeEntity($form->entity),
53
                'target_id' => $form->targetId
54
            ]);
55
        } else {
56
            $response = ['success' => false, 'errors' => $form->errors];
57
        }
58
59
        $this->trigger(self::EVENT_AFTER_VOTE, $event = $this->createEvent($form, $response));
60
61
        return $event->responseData;
62
    }
63
64
    /**
65
     * Processes a vote (+/-) request.
66
     *
67
     * @param VoteForm $form
68
     * @return array
69
     * @throws \Exception
70
     * @throws \yii\base\InvalidConfigException
71
     */
72
    protected function processVote(VoteForm $form)
73
    {
74
        /* @var $vote Vote */
75
        $module = $this->getModule();
76
        $response = ['success' => false];
77
        $searchParams = ['entity' => $module->encodeEntity($form->entity), 'target_id' => $form->targetId];
78
79
        if (Yii::$app->user->isGuest) {
80
            $vote = Vote::find()
81
                ->where($searchParams)
82
                ->andWhere(['user_ip' => Yii::$app->request->userIP])
83
                ->andWhere('UNIX_TIMESTAMP() - created_at < :limit', [':limit' => $module->guestTimeLimit])
84
                ->one();
85
        } else {
86
            $vote = Vote::findOne(array_merge($searchParams, ['user_id' => Yii::$app->user->id]));
87
        }
88
89
        if ($vote == null) {
90
            $response = $this->createVote($module->encodeEntity($form->entity), $form->targetId, $form->getValue());
91
        } else {
92
            if ($vote->value !== $form->getValue()) {
93
                $vote->value = $form->getValue();
94
                if ($vote->save()) {
95
                    $response = ['success' => true, 'changed' => true];
96
                }
97
            }
98
        }
99
100
        return $response;
101
    }
102
103
    /**
104
     * Processes a vote toggle request (like/favorite etc).
105
     *
106
     * @param VoteForm $form
107
     * @return array
108
     * @throws \Exception
109
     * @throws \yii\base\InvalidConfigException
110
     */
111
    protected function processToggle(VoteForm $form)
112
    {
113
        /* @var $vote Vote */
114
        $module = $this->getModule();
115
        $vote = Vote::findOne([
116
            'entity' => $module->encodeEntity($form->entity),
117
            'target_id' => $form->targetId,
118
            'user_id' => Yii::$app->user->id
119
        ]);
120
121
        if ($vote == null) {
122
            $response = $this->createVote($module->encodeEntity($form->entity), $form->targetId, $form->getValue());
123
            $response['toggleValue'] = 1;
124
        } else {
125
            $vote->delete();
0 ignored issues
show
Bug introduced by
The method delete cannot be called on $vote (of type array|boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
126
            $response = ['success' => true, 'toggleValue' => 0];
127
        }
128
129
        return $response;
130
    }
131
132
    /**
133
     * Creates new vote entry and returns response data.
134
     *
135
     * @param string $entity
136
     * @param integer $targetId
137
     * @param integer $value
138
     * @return array
139
     */
140
    protected function createVote($entity, $targetId, $value)
141
    {
142
        $vote = new Vote();
143
        $vote->entity = $entity;
144
        $vote->target_id = $targetId;
145
        $vote->value = $value;
146
147
        if ($vote->save()) {
148
            return ['success' => true];
149
        } else {
150
            return ['success' => false, 'errors' => $vote->errors];
151
        }
152
    }
153
154
    /**
155
     * @param VoteForm $voteForm
156
     * @param array $responseData
157
     * @return object
158
     * @throws \yii\base\InvalidConfigException
159
     */
160
    protected function createEvent(VoteForm $voteForm, array $responseData)
161
    {
162
        return Yii::createObject([
163
            'class' => VoteActionEvent::class,
164
            'voteForm' => $voteForm,
165
            'responseData' => $responseData
166
        ]);
167
    }
168
}
169