zend-blog-3-backend

Форк
0
273 строки · 6.9 Кб
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: morontt
5
 * Date: 24.09.17
6
 * Time: 10:29
7
 */
8

9
namespace Xelbot\Telegram;
10

11
use Psr\Log\LoggerInterface;
12
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
13
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
14
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
15
use Symfony\Component\Serializer\Serializer;
16
use Xelbot\Telegram\Command\AbstractAdminCommand;
17
use Xelbot\Telegram\Command\TelegramCommandInterface;
18
use Xelbot\Telegram\Entity\Message;
19
use Xelbot\Telegram\Entity\Update;
20
use Xelbot\Telegram\Exception\AccessDeniedTelegramException;
21
use Xelbot\Telegram\Exception\TelegramException;
22

23
class Robot
24
{
25
    public const EMOJI_ROBOT = '&#x1F916;';
26
    public const EMOJI_THINKING_FACE = '&#x1F914;';
27

28
    protected string $token = '';
29

30
    protected string $botName = '';
31

32
    protected int $adminId;
33

34
    /**
35
     * @var TelegramRequester
36
     */
37
    protected $requester;
38

39
    /**
40
     * @var LoggerInterface|null
41
     */
42
    protected $logger = null;
43

44
    /**
45
     * @var TelegramCommandInterface[]
46
     */
47
    protected $commands = [];
48

49
    /**
50
     * @var UpdatesManagerInterface|null
51
     */
52
    private $updatesManager;
53

54
    /**
55
     * @param string $token
56
     * @param string $botName
57
     * @param int $adminId
58
     *
59
     * @throws TelegramException
60
     */
61
    public function __construct(string $token, string $botName, int $adminId)
62
    {
63
        if (!$token) {
64
            throw new TelegramException('API KEY not defined');
65
        }
66

67
        if (!preg_match('/\d+\:[\w\-]+/', $token)) {
68
            throw new TelegramException('Invalid API KEY');
69
        }
70

71
        $this->token = $token;
72
        $this->adminId = $adminId;
73

74
        if ($botName) {
75
            $this->botName = $botName;
76
        }
77

78
        $this->requester = new TelegramRequester($token);
79
    }
80

81
    /**
82
     * @param LoggerInterface|null $logger
83
     */
84
    public function setLogger(LoggerInterface $logger = null): void
85
    {
86
        $this->logger = $logger;
87
        $this->requester->setLogger($logger);
88
    }
89

90
    /**
91
     * @param UpdatesManagerInterface $updatesManager
92
     */
93
    public function setUpdatesManager(UpdatesManagerInterface $updatesManager): void
94
    {
95
        $this->updatesManager = $updatesManager;
96
    }
97

98
    /**
99
     * @param TelegramCommandInterface $command
100
     */
101
    public function addCommand(TelegramCommandInterface $command): void
102
    {
103
        $command->setRequester($this->requester);
104

105
        if ($command instanceof AbstractAdminCommand) {
106
            $command->setAdminId($this->adminId);
107
        }
108

109
        $this->commands[$command->getCommandName()] = $command;
110
    }
111

112
    /**
113
     * @param string $message
114
     * @param int|null $chatId
115
     *
116
     * @return TelegramResponse
117
     */
118
    public function sendMessage(string $message, int $chatId = null): TelegramResponse
119
    {
120
        if ($chatId === null) {
121
            $chatId = $this->adminId;
122
        }
123

124
        return $this->requester->sendMessage([
125
            'chat_id' => $chatId,
126
            'text' => $message,
127
        ]);
128
    }
129

130
    /**
131
     * @param string $url
132
     * @param string|null $certificate
133
     *
134
     * @throws TelegramException
135
     *
136
     * @return TelegramResponse
137
     */
138
    public function setWebhook(string $url, string $certificate = null): TelegramResponse
139
    {
140
        $data = [
141
            'url' => $url,
142
        ];
143

144
        if ($certificate) {
145
            $data['certificate'] = $this->getResource($certificate);
146
        }
147

148
        return $this->requester->setWebhook($data);
149
    }
150

151
    /**
152
     * @return TelegramResponse
153
     */
154
    public function getWebhookInfo(): TelegramResponse
155
    {
156
        return $this->requester->getWebhookInfo();
157
    }
158

159
    /**
160
     * @return TelegramResponse
161
     */
162
    public function deleteWebhook(): TelegramResponse
163
    {
164
        return $this->requester->deleteWebhook();
165
    }
166

167
    /**
168
     * @param array $requestData
169
     *
170
     * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface
171
     */
172
    public function handle(array $requestData): void
173
    {
174
        if ($this->logger) {
175
            $this->logger->info('Webhook: ', $requestData);
176
        }
177

178
        $normalizer = new ObjectNormalizer(
179
            null,
180
            new CamelCaseToSnakeCaseNameConverter(),
181
            null,
182
            new ReflectionExtractor()
183
        );
184

185
        $serializer = new Serializer([$normalizer]);
186
        $obj = $serializer->denormalize($requestData, Update::class);
187

188
        if ($this->updatesManager) {
189
            $this->updatesManager->saveUpdate($obj, $requestData);
190
        }
191

192
        if ($message = $obj->getMessage()) {
193
            foreach ($message->getEntities() as $entity) {
194
                if ($entity['type'] === 'bot_command') {
195
                    $this->executeCommand($message, $entity);
196
                }
197
            }
198
        }
199
    }
200

201
    /**
202
     * @param string $file
203
     *
204
     * @throws TelegramException
205
     *
206
     * @return resource
207
     */
208
    protected function getResource(string $file)
209
    {
210
        $fp = fopen($file, 'rb');
211
        if ($fp === false) {
212
            throw new TelegramException('Cannot open ' . $file);
213
        }
214

215
        return $fp;
216
    }
217

218
    /**
219
     * @param Message $message
220
     * @param array $entity
221
     */
222
    protected function executeCommand(Message $message, array $entity): void
223
    {
224
        if (!$message->getChat()) {
225
            $this->logger->error('message without chat', ['message' => serialize($message)]);
226

227
            return;
228
        }
229

230
        $commandName = mb_substr($message->getText(), $entity['offset'] + 1, $entity['length'] - 1);
231
        try {
232
            if (isset($this->commands[$commandName])) {
233
                $this->commands[$commandName]->execute($message);
234
            } else {
235
                //TODO Null pointer exception may occur here
236
                $this->requester->sendMessage([
237
                    'chat_id' => $message->getChat()->getId(),
238
                    'text' => sprintf(
239
                        'Не знаю такую команду%s %s ',
240
                        $this->appealTo($message->getFrom()->getId()),
241
                        self::EMOJI_ROBOT
242
                    ),
243
                    'parse_mode' => 'HTML',
244
                ]);
245
            }
246
        } catch (AccessDeniedTelegramException $e) {
247
            $this->requester->sendMessage([
248
                'chat_id' => $message->getChat()->getId(),
249
                'text' => 'Кто вы? ' . self::EMOJI_THINKING_FACE,
250
                'parse_mode' => 'HTML',
251
            ]);
252

253
            $this->logger->notice($e->getMessage());
254
        } catch (\Throwable $e) {
255
            $this->logger->error($e->getMessage());
256
        }
257
    }
258

259
    /**
260
     * @param int $idFrom
261
     *
262
     * @return string
263
     */
264
    private function appealTo(int $idFrom): string
265
    {
266
        $text = '';
267
        if ($idFrom === $this->adminId) {
268
            $text = ', хозяин';
269
        }
270

271
        return $text;
272
    }
273
}
274

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.