Completed
Push — master ( e20ad5...726df6 )
by Kirill
02:22
created

GameService::checkAnswer()   D

Complexity

Conditions 9
Paths 9

Size

Total Lines 115
Code Lines 75

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 115
rs 4.8196
c 0
b 0
f 0
cc 9
eloc 75
nc 9
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Chrl\AppBundle\Service;
4
5
use Chrl\AppBundle\Entity\PointLog;
6
use Chrl\AppBundle\Entity\Question;
7
use Doctrine\ORM\EntityManager;
8
use Doctrine\ORM\EntityManagerInterface;
9
use Chrl\AppBundle\Entity\Game;
10
use Chrl\AppBundle\Entity\User;
11
use Chrl\AppBundle\BuktopuhaBotApi;
12
13
/**
14
 * Game service
15
 *
16
 * @category Symfony
17
 * @package  Chrl_Buktopuha
18
 * @author   Kirill Kholodilin <[email protected]>
19
 * @license  http://www.gnu.org/copyleft/gpl.html GNU General Public License
20
 * @link     https://take2.ru/
21
 */
22
23
class GameService
24
{
25
    /** @var EntityManager */
26
    public $em;
27
    /** @var BuktopuhaBotApi */
28
    private $botApi;
29
30
    private $config;
31
32
    public function __construct(BuktopuhaBotApi $telegramBotApi, $config, EntityManagerInterface $entityManager)
33
    {
34
        $this->em = $entityManager;
0 ignored issues
show
Documentation Bug introduced by
$entityManager is of type object<Doctrine\ORM\EntityManagerInterface>, but the property $em was declared to be of type object<Doctrine\ORM\EntityManager>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
35
        $this->botApi = $telegramBotApi;
36
        $this->config = $config;
37
    }
38
39
40
    /**
41
     * @return Game
42
     */
43
    public function findGame(array $message)
44
    {
45
        $game = $this->em->getRepository('AppBundle:Game')->findOneBy(['chatId'=>$message['chat']['id']]);
46
        if (!$game) {
47
            // create game
48
            $game = new Game();
49
            $game->status = 0;
50
            $game->chatId = $message['chat']['id'];
51
            $game->title = isset($message['chat']['title'])
52
                ? $message['chat']['title']
53
                : 'No title';
54
55
            $this->em->persist($game);
56
            $this->em->flush();
57
        }
58
        return $game;
59
    }
60
61
62
    public function getCurrentUser(array $message)
63
    {
64
        $user = $this->em->getRepository('AppBundle:User')->findOneBy(['tgId'=>$message['from']['id']]);
65
        if (!$user) {
66
            $user = new User();
67
            $user->setName(
68
                (
69
                    isset($message['from']['first_name'])
70
                    ? $message['from']['first_name']
71
                    : ''
72
                )
73
                .' '.
74
                (
75
                isset($message['from']['last_name'])
76
                    ? $message['from']['last_name']
77
                    : ''
78
                )
79
            );
80
            $user->setAlias(isset($message['from']['username'])? $message['from']['username']:'username');
81
            $user->setTgId($message['from']['id']);
82
            $user->setGame($this->findGame($message));
83
            $user->setChatId($message['chat']['id']);
84
            $user->setPoints(0);
85
86
            $this->em->persist($user);
87
            $this->em->flush();
88
        }
89
        return $user;
90
    }
91
92
    public function getActiveGames()
93
    {
94
        $games = $this->em->getRepository('AppBundle:Game')->findBy(['status'=>1]);
95
        return $games;
96
    }
97
    public function getInactiveGames()
98
    {
99
        $games = $this->em->getRepository('AppBundle:Game')->findBy(['status'=>0]);
100
        return $games;
101
    }
102
103
104
    /**
105
     * Checks if the answer is correct, and asks next question
106
     *
107
     * @param array $message
108
     */
109
    public function checkAnswer($message)
110
    {
111
        $game = $this->findGame($message);
112
        $user = $this->getCurrentUser($message);
113
114
        if ($game->status == 1) {
115
            /** @var Question $question */
116
            $question = $this->em->getRepository('AppBundle:Question')->find($game->lastQuestion);
117
118
            if (!$question) {
119
                return;
120
            }
121
122
            if (mb_strtoupper($question->a1, 'UTF-8') == mb_strtoupper($message['text'], 'UTF-8')) {
123
                // Correct answer!
124
125
                $user->setPoints($user->getPoints()+$question->price);
126
                $this->em->persist($user);
127
128
                // Log points
129
130
                $pl = new PointLog();
131
                $pl->date = new \DateTime("now");
132
                $pl->day = date('d');
133
                $pl->month = date('m');
134
                $pl->year = date('Y');
135
                $pl->points = $question->price;
136
                $pl->userId = $user->getId();
137
                $pl->gameId = $game->getId();
138
139
                $this->em->persist($pl);
140
141
                $seconds = new \Datetime('now');
142
                $seconds = $seconds->getTimestamp() - $game->lastQuestionTime->getTimestamp();
143
144
                $this->botApi->sendMessage(
145
                    $game->chatId,
146
                    json_decode('"\ud83d\udc4d"').' Correct in *'.$seconds.'* secs! @'.$user->getAlias().' gets *'.
147
                    $question->price.'* and now has *'.$user->getPoints().'* points!',
148
                    'markdown',
149
                    false,
150
                    $message['message_id']
151
                );
152
153
                $question->correct++;
154
                $this->em->persist($question);
155
156
                if ($user->fastestAnswer > $seconds) {
157
                    $user->fastestAnswer = $seconds;
158
                    $user->setPoints($user->getPoints() + 50);
159
160
                    $this->em->persist($user);
161
162
                    $pl = new PointLog();
163
                    $pl->date = new \DateTime("now");
164
                    $pl->day = date('d');
165
                    $pl->month = date('m');
166
                    $pl->year = date('Y');
167
                    $pl->points = 50;
168
                    $pl->userId = $user->getId();
169
                    $pl->gameId = $game->getId();
170
171
                    $this->em->persist($pl);
172
173
                    $this->botApi->sendMessage(
174
                        $game->chatId,
175
                        '@'.$user->getAlias().' gets additional *50* points for his fastest answer ever!',
176
                        'markdown',
177
                        false
178
                    );
179
                }
180
181
                $this->askQuestion($game);
182
            } else {
183
                // Incorrect answer
184
                $game->incorrectTries++;
185
                $hint = $game->hint;
186
187
                if (mb_substr_count($hint, '*', 'UTF-8') >= mb_strlen($hint, 'UTF-8')/2) {
188
                    //tell hint
189
190
                    for ($t = 0; $t< mb_strlen($hint); $t++) {
191
                        if (mb_substr($hint, $t, 1, 'UTF-8') == '*') {
192
                            if (rand(0, 1)==1) {
193
                                $hint = mb_substr($hint, 0, $t, 'UTF-8')
194
                                        .mb_substr($question->a1, $t, 1)
195
                                        .mb_substr($hint, $t+1);
196
                                break;
197
                            }
198
                        }
199
                    }
200
201
                    $game->hint = $hint;
202
203
                    $this->botApi->sendMessage(
204
                        $game->chatId,
205
                        '<b>Hint</b>: '.$hint,
206
                        'html'
207
                    );
208
                } else {
209
                    $this->botApi->sendMessage(
210
                        $game->chatId,
211
                        'Noone answered, correct answer was: *'.$question->a1.'*',
212
                        'markdown'
213
                    );
214
                    $this->em->persist($game);
215
                    $this->em->flush();
216
                    $this->askQuestion($game);
217
                }
218
            }
219
220
            $this->em->persist($game);
221
            $this->em->flush();
222
        }
223
    }
224
225
    /**
226
     * Asks question in the game
227
     *
228
     * @param Game $game
229
     */
230
231
    public function askQuestion(Game $game)
232
    {
233
        $question = $this->getRandomQuestion();
234
235
        $question->played++;
236
237
        $game->lastQuestion = $question->getId();
238
        $game->lastQuestionTime = new \DateTime('now');
239
        $game->incorrectTries = 0;
240
        $game->hint = str_repeat('*', mb_strlen($question->a1, 'UTF-8'));
241
242
        $this->em->persist($game);
243
        $this->em->persist($question);
244
        $this->em->flush();
245
246
        $this->botApi->sendMessage(
247
            $game->chatId,
248
            '*[question]* '.
249
            $question->text.' _('.mb_strlen($question->a1, 'UTF-8'). ' letters)_',
250
            'markdown'
251
        );
252
    }
253
254
    /**
255
     * Gets random question from database
256
     *
257
     * @return Question
258
     * @throws \Doctrine\ORM\NoResultException
259
     * @throws \Doctrine\ORM\NonUniqueResultException
260
     */
261
    public function getRandomQuestion()
262
    {
263
        $count = $this->em->createQueryBuilder()
264
            ->select('COUNT(u)')->from('AppBundle:Question', 'u')
265
            ->getQuery()
266
            ->getSingleScalarResult();
267
268
        return $this->em->createQuery('SELECT c FROM AppBundle:Question c ORDER BY c.id ASC')
269
            ->setFirstResult(rand(0, $count - 1))
270
            ->setMaxResults(1)
271
            ->getSingleResult();
272
    }
273
274
    public function getTopUsers()
275
    {
276
        $top = $this->em->createQueryBuilder()
277
            ->select(
278
                array(
279
                    'SUM(u.points) points',
280
                    'u.name',
281
                )
282
            )->from('AppBundle:User', 'u')
283
            ->groupBy('u.id')
284
            ->orderBy('u.points', 'desc')
285
            ->setMaxResults(10)
286
            ->getQuery()
287
            ->getArrayResult();
288
289
        return $top;
290
    }
291
}
292