Voter::isPublished()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 9
ccs 5
cts 5
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
/*
4
 * This file is part of the MsalsasVotingBundle package.
5
 *
6
 * (c) Manolo Salsas
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Msalsas\VotingBundle\Service;
13
14
15
use Doctrine\ORM\EntityManagerInterface;
16
use Msalsas\VotingBundle\Entity\ReferenceVotes;
17
use Msalsas\VotingBundle\Entity\VoteNegative;
18
use Msalsas\VotingBundle\Entity\VotePositive;
19
use Symfony\Component\Finder\Exception\AccessDeniedException;
20
use Symfony\Component\HttpFoundation\Request;
21
use Symfony\Component\HttpFoundation\RequestStack;
22
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
23
use Symfony\Component\Security\Core\User\UserInterface;
24
use Symfony\Component\Translation\TranslatorInterface;
25
26
class Voter
27
{
28
    /**
29
     * @var EntityManagerInterface
30
     */
31
    protected $em;
32
33
    /**
34
     * @var TokenStorageInterface
35
     */
36
    protected $token;
37
38
    /**
39
     * @var Request
40
     */
41
    protected $request;
42
43
    /**
44
     * @var TranslatorInterface
45
     */
46
    protected $translator;
47
48
    /**
49
     * @var integer
50
     */
51
    protected $anonPercentAllowed;
52
53
    /**
54
     * @var integer
55
     */
56
    protected $anonMinAllowed;
57
58
    /**
59
     * @var array
60
     */
61
    protected $negativeReasons;
62
63 23
    public function __construct(EntityManagerInterface $em, TokenStorageInterface $token, RequestStack $requestStack, TranslatorInterface $translator, $anonPercentAllowed, $anonMinAllowed, $negativeReasons = array())
64
    {
65 23
        $this->em = $em;
66 23
        $this->token = $token;
67 23
        $this->request = $requestStack->getCurrentRequest();
68 23
        $this->translator = $translator;
69 23
        $this->anonPercentAllowed = $anonPercentAllowed;
70 23
        $this->anonMinAllowed = $anonMinAllowed;
71 23
        $this->negativeReasons = $negativeReasons;
72 23
    }
73
74 6
    public function getPositiveVotes($referenceId)
75
    {
76
        /** @var \Msalsas\VotingBundle\Entity\ReferenceVotes|null $referenceVotes */
77 6
        $referenceVotes = $this->em->getRepository(ReferenceVotes::class)->findOneBy(array('reference' => $referenceId));
78 6
        if (!$referenceVotes) {
79 4
            $referenceVotes = new ReferenceVotes();
80 4
            $referenceVotes->setReference($referenceId);
81
        }
82
83 6
        return $referenceVotes->getPositiveVotes();
84
    }
85
86 5
    public function getNegativeVotes($referenceId)
87
    {
88
        /** @var \Msalsas\VotingBundle\Entity\ReferenceVotes|null $referenceVotes */
89 5
        $referenceVotes = $this->em->getRepository(ReferenceVotes::class)->findOneBy(array('reference' => $referenceId));
90 5
        if (!$referenceVotes) {
91 4
            $referenceVotes = new ReferenceVotes();
92 4
            $referenceVotes->setReference($referenceId);
93
        }
94
95 5
        return $referenceVotes->getNegativeVotes();
96
    }
97
98 2
    public function getUserPositiveVotes($referenceId)
99
    {
100
        /** @var \Msalsas\VotingBundle\Entity\ReferenceVotes|null $referenceVotes */
101 2
        $referenceVotes = $this->em->getRepository(ReferenceVotes::class)->findOneBy(array('reference' => $referenceId));
102 2
        if (!$referenceVotes) {
103 1
            $referenceVotes = new ReferenceVotes();
104 1
            $referenceVotes->setReference($referenceId);
105
        }
106
107 2
        return $referenceVotes->getUserVotes();
108
    }
109
110 2
    public function getAnonymousVotes($referenceId)
111
    {
112
        /** @var \Msalsas\VotingBundle\Entity\ReferenceVotes|null $referenceVotes */
113 2
        $referenceVotes = $this->em->getRepository(ReferenceVotes::class)->findOneBy(array('reference' => $referenceId));
114 2
        if (!$referenceVotes) {
115 1
            $referenceVotes = new ReferenceVotes();
116 1
            $referenceVotes->setReference($referenceId);
117
        }
118
119 2
        return $referenceVotes->getAnonymousVotes();
120
    }
121
122 8
    public function votePositive($referenceId)
123
    {
124 8
        $user = $this->token->getToken() ? $this->token->getToken()->getUser() : null;
125
126 8
        $this->validateVote($user, $referenceId);
127
128 5
        $user = $user instanceof UserInterface ? $user : null;
129
130 5
        $vote = new VotePositive();
131 5
        $vote->setReference($referenceId);
132 5
        $vote->setUser($user);
133 5
        $vote->setUserIP($this->request ? $this->request->getClientIp() : null);
134
135
        /** @var \Msalsas\VotingBundle\Entity\ReferenceVotes $referenceVotes */
136 5
        $referenceVotes = $this->addReferenceVote($referenceId, true, !$user);
137
138 5
        $this->em->persist($vote);
139 5
        $this->em->persist($referenceVotes);
140 5
        $this->em->flush();
141
142 5
        return $referenceVotes->getPositiveVotes();
143
    }
144
145 4
    public function voteNegative($referenceId, $reason)
146
    {
147 4
        $user = $this->token->getToken() ? $this->token->getToken()->getUser() : null;
148
149 4
        if (!$reason || !is_string($reason) || $reason === '0') {
150 1
            throw new AccessDeniedException($this->translator->trans('msalsas_voting.errors.invalid_reason'));
151
        }
152
153 3
        $this->validateVote($user, $referenceId);
154
155 3
        if (!$user instanceof UserInterface) {
156 1
            throw new AccessDeniedException($this->translator->trans('msalsas_voting.errors.anon_cannot_vote_negative'));
157
        }
158
159 2
        $vote = new VoteNegative();
160 2
        $vote->setReference($referenceId);
161 2
        $vote->setReason($reason);
162 2
        $vote->setUser($user);
163 2
        $vote->setUserIP($this->request->getClientIp());
164
165
        /** @var \Msalsas\VotingBundle\Entity\ReferenceVotes $referenceVotes */
166 2
        $referenceVotes = $this->addReferenceVote($referenceId, false, !$user);
167
168 2
        $this->em->persist($referenceVotes);
169 2
        $this->em->persist($vote);
170 2
        $this->em->flush();
171
172 2
        return $referenceVotes->getNegativeVotes();
173
    }
174
175 4
    public function getUserVote($referenceId)
176
    {
177 4
        $user = $this->token->getToken()->getUser();
178 4
        $user = $user instanceof UserInterface ? $user : null;
179 4
        $votePositiveRepository = $this->em->getRepository(VotePositive::class);
180 4
        $voteNegativeRepository = $this->em->getRepository(VoteNegative::class);
181
182 4
        if ($user && $vote = $votePositiveRepository->findOneBy(array('user' => $user, 'reference' => $referenceId))) {
183 1
            return $vote;
184 3
        } else if (!$user && $vote = $votePositiveRepository->findOneBy(array('user' => $user, 'reference' => $referenceId, 'userIP' => $this->request->getClientIp()))) {
185 1
            return $vote;
186 2
        } else if ($vote = $voteNegativeRepository->findOneBy(array('user' => $user, 'reference' => $referenceId))) {
187 1
            return $vote;
188
        }
189
190 1
        return false;
191
    }
192
193 8
    public function getNegativeReasons()
194
    {
195 8
        return $this->negativeReasons;
196
    }
197
198 4
    public function userCanVoteNegative($referenceId)
199
    {
200 4
        $user = $this->token->getToken()->getUser();
201 4
        if (!$user instanceof UserInterface) {
202 1
            return false;
203
        }
204
205 3
        return !$this->userHasVoted($user, $referenceId);
206
    }
207
208 2
    public function isPublished($referenceId)
209
    {
210
        /** @var \Msalsas\VotingBundle\Entity\ReferenceVotes|null $referenceVotes */
211 2
        $referenceVotes = $this->em->getRepository(ReferenceVotes::class)->findOneBy(array('reference' => $referenceId));
212 2
        if (!$referenceVotes) {
213 1
            return false;
214
        }
215
216 1
        return $referenceVotes->isPublished();
217
    }
218
219 2
    public function setPublished($referenceId)
220
    {
221
        /** @var \Msalsas\VotingBundle\Entity\ReferenceVotes|null $referenceVotes */
222 2
        $referenceVotes = $this->em->getRepository(ReferenceVotes::class)->findOneBy(array('reference' => $referenceId));
223 2
        if (!$referenceVotes) {
224 1
            throw new \Exception($this->translator->trans('msalsas_voting.errors.ref_does_not_exist', array('%reference%' => $referenceId)));
225
        }
226
227 1
        $referenceVotes->setPublished(true);
228 1
    }
229
230 11
    protected function validateVote($user, $referenceId)
231
    {
232 11
        if (!$user instanceof UserInterface && (!$this->request || !$this->request->getClientIp())) {
233 1
            throw new AccessDeniedException($this->translator->trans('msalsas_voting.errors.no_ip_defined_for_anon'));
234
        }
235
236 10
        if ($this->userHasVoted($user, $referenceId)) {
237 1
            throw new AccessDeniedException($this->translator->trans('msalsas_voting.errors.already_voted'));
238
        }
239
240 9
        if (!$user instanceof UserInterface) {
241 5
            $referenceVotes = $this->em->getRepository(ReferenceVotes::class)->findOneBy(array('reference' => $referenceId));
242 5
            if ($referenceVotes instanceof ReferenceVotes && !$this->anonymousIsAllowed($referenceVotes)) {
243 1
                throw new AccessDeniedException($this->translator->trans('msalsas_voting.errors.too_much_anon_votes'));
244
            }
245
        }
246 8
    }
247
248 13
    protected function userHasVoted($user, $referenceId)
249
    {
250 13
        $votePositiveRepository = $this->em->getRepository(VotePositive::class);
251 13
        $voteNegativeRepository = $this->em->getRepository(VoteNegative::class);
252
253 13
        if ($user instanceof UserInterface) {
254 7
            if ($votePositiveRepository->findOneBy(
255
                array(
256 7
                    'user' => $user,
257 7
                    'reference' => $referenceId
258
                )
259
            )) {
260 1
                return true;
261 6
            } else if ($voteNegativeRepository->findOneBy(
262
                array(
263 6
                    'user' => $user,
264 6
                    'reference' => $referenceId
265
                )
266
            )) {
267 6
                return true;
268
            }
269
        } else {
270 6
            if ($votePositiveRepository->findOneBy(
271
                array(
272 6
                    'user' => null,
273 6
                    'userIP' => $this->request->getClientIp(),
274 6
                    'reference' => $referenceId
275
                )
276
            )) {
277 1
                return true;
278
            }
279
        }
280
281 10
        return false;
282
    }
283
284 7
    protected function addReferenceVote($referenceId, $positive, $anonymous = true)
285
    {
286
        /** @var \Msalsas\VotingBundle\Entity\ReferenceVotes|null $referenceVotes */
287 7
        $referenceVotes = $this->em->getRepository(ReferenceVotes::class)->findOneBy(array('reference' => $referenceId));
288 7
        if ($referenceVotes) {
289 4
            $referenceVotes->addVote($positive, $anonymous);
290
        } else {
291 3
            $referenceVotes = new ReferenceVotes();
292 3
            $referenceVotes->setReference($referenceId);
293 3
            $referenceVotes->addVote($positive, $anonymous);
294
        }
295
296 7
        return $referenceVotes;
297
    }
298
299 3
    protected function anonymousIsAllowed(ReferenceVotes $referenceVotes)
300
    {
301 3
        $anonVotes = $referenceVotes->getAnonymousVotes();
302 3
        $userVotes = $referenceVotes->getUserVotes();
303
304 3
        if ($anonVotes < $this->anonMinAllowed) {
305 1
            return true;
306
        }
307
308 2
        $anonPercent = $anonVotes ? ($anonVotes / ($userVotes + $anonVotes)) * 100 : 0;
309 2
        if ($anonPercent < $this->anonPercentAllowed) {
310 1
            return true;
311
        }
312
313 1
        return false;
314
    }
315
}