Completed
Push — master ( f8b64c...b3b7dc )
by Kirill
02:31
created

GameService::getTopUsers()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 17
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 13
nc 1
nop 0
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
                $this->botApi->sendMessage(
142
                    $game->chatId,
143
                    'Correct! @'.$user->getAlias().' gets *'.
144
                    $question->price.'* and now has *'.$user->getPoints().'* points!',
145
                    'markdown',
146
                    false,
147
                    $message['message_id']
148
                );
149
150
                $question->correct++;
151
                $this->em->persist($question);
152
153
                $this->askQuestion($game);
154
            } else {
155
                // Incorrect answer
156
                $game->incorrectTries++;
157
                $hint = $game->hint;
158
159
                if (mb_substr_count($hint, '*', 'UTF-8') >= mb_strlen($hint, 'UTF-8')/2) {
160
                    //tell hint
161
162
                    for ($t = 0; $t< mb_strlen($hint); $t++) {
163
                        if (mb_substr($hint, $t, 1, 'UTF-8') == '*') {
164
                            if (rand(0, 1)==1) {
165
                                $hint = mb_substr($hint, 0, $t, 'UTF-8')
166
                                        .mb_substr($question->a1, $t, 1)
167
                                        .mb_substr($hint, $t+1);
168
                                break;
169
                            }
170
                        }
171
                    }
172
173
                    $game->hint = $hint;
174
175
                    $this->botApi->sendMessage(
176
                        $game->chatId,
177
                        '<b>Hint</b>: '.$hint,
178
                        'html'
179
                    );
180
                } else {
181
                    $this->botApi->sendMessage(
182
                        $game->chatId,
183
                        'Noone answered, correct answer was: *'.$question->a1.'*',
184
                        'markdown'
185
                    );
186
                    $this->em->persist($game);
187
                    $this->em->flush();
188
                    $this->askQuestion($game);
189
                }
190
            }
191
192
            $this->em->persist($game);
193
            $this->em->flush();
194
        }
195
    }
196
197
    /**
198
     * Asks question in the game
199
     *
200
     * @param Game $game
201
     */
202
203
    public function askQuestion(Game $game)
204
    {
205
        $question = $this->getRandomQuestion();
206
207
        $question->played++;
208
209
        $game->lastQuestion = $question->getId();
210
        $game->lastQuestionTime = new \DateTime('now');
211
        $game->incorrectTries = 0;
212
        $game->hint = str_repeat('*', mb_strlen($question->a1, 'UTF-8'));
213
214
        $this->em->persist($game);
215
        $this->em->persist($question);
216
        $this->em->flush();
217
218
        $this->botApi->sendMessage(
219
            $game->chatId,
220
            '*[question]* '.
221
            $question->text.' _('.mb_strlen($question->a1, 'UTF-8'). ' letters)_',
222
            'markdown'
223
        );
224
    }
225
226
    /**
227
     * Gets random question from database
228
     *
229
     * @return Question
230
     * @throws \Doctrine\ORM\NoResultException
231
     * @throws \Doctrine\ORM\NonUniqueResultException
232
     */
233
    public function getRandomQuestion()
234
    {
235
        $count = $this->em->createQueryBuilder()
236
            ->select('COUNT(u)')->from('AppBundle:Question', 'u')
237
            ->getQuery()
238
            ->getSingleScalarResult();
239
240
        return $this->em->createQuery('SELECT c FROM AppBundle:Question c ORDER BY c.id ASC')
241
            ->setFirstResult(rand(0, $count - 1))
242
            ->setMaxResults(1)
243
            ->getSingleResult();
244
    }
245
246
    public function getTopUsers()
247
    {
248
        $top = $this->em->createQueryBuilder()
249
            ->select(
250
                array(
251
                    'SUM(u.points) points',
252
                    'u.name',
253
                )
254
            )->from('AppBundle:User', 'u')
255
            ->groupBy('u.id')
256
            ->orderBy('u.points')
257
            ->setMaxResults(10)
258
            ->getQuery()
259
            ->getArrayResult();
260
261
        return $top;
262
    }
263
}
264