Passed
Pull Request — master (#292)
by
unknown
01:51
created

Client::getEvent()   A

Complexity

Conditions 5
Paths 1

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 28
ccs 16
cts 16
cp 1
rs 9.1608
c 0
b 0
f 0
cc 5
nc 1
nop 1
crap 5
1
<?php
2
3
namespace TelegramBot\Api;
4
5
use Closure;
6
use ReflectionFunction;
7
use TelegramBot\Api\Events\EventCollection;
8
use TelegramBot\Api\Types\Update;
9
10
/**
11
 * Class Client
12
 *
13
 * @package TelegramBot\Api
14
 */
15
class Client
16
{
17
    /**
18
     * RegExp for bot commands
19
     */
20
    const REGEXP = '/^(?:@\w+\s)?\/([^\s@]+)(@\S+)?\s?(.*)$/';
21
22
    /**
23
     * @var BotApi
24
     */
25
    protected $api;
26
27
    /**
28
     * @var EventCollection
29
     */
30
    protected $events;
31
32
    /**
33
     * Client constructor
34
     *
35
     * @param string      $token        Telegram Bot API token
36
     * @param string|null $trackerToken Yandex AppMetrica application api_key
37
     */
38 7
    public function __construct($token, $trackerToken = null)
39
    {
40 7
        $this->api = new BotApi($token);
41 7
        $this->events = new EventCollection($trackerToken);
42 7
    }
43
44
    /**
45
     * @param       $name
46
     * @param array $arguments
47
     * @return mixed
48
     * @throws BadMethodCallException
49
     */
50 1
    public function __call($name, array $arguments)
51
    {
52 1
        if (method_exists($this, $name)) {
53
            return call_user_func_array([$this, $name], $arguments);
54 1
        } elseif (method_exists($this->api, $name)) {
55
            return call_user_func_array([$this->api, $name], $arguments);
56
        }
57
58 1
        throw new BadMethodCallException("Method {$name} not exists");
59
    }
60
61
    /**
62
     * Use this method to add an event.
63
     * If second closure will return true (or if you are passed null instead of closure), first one will be executed.
64
     *
65
     * @param Closure      $event
66
     * @param Closure|null $checker
67
     * @return Client
68
     */
69 1
    public function on(Closure $event, Closure $checker = null)
70
    {
71 1
        $this->events->add($event, $checker);
72
73 1
        return $this;
74
    }
75
76
    /**
77
     * Handle updates
78
     *
79
     * @param Update[] $updates
80
     */
81 4
    public function handle(array $updates)
82
    {
83 4
        foreach ($updates as $update) {
84
            /* @var Update $update */
85 4
            $this->events->handle($update);
86 4
        }
87 4
    }
88
89
    /**
90
     * Webhook handler
91
     *
92
     * @return void
93
     * @throws InvalidJsonException
94
     */
95
    public function run()
96
    {
97
        if ($data = BotApi::jsonValidate($this->getRawBody(), true)) {
0 ignored issues
show
Security Bug introduced by
It seems like $this->getRawBody() targeting TelegramBot\Api\Client::getRawBody() can also be of type false; however, TelegramBot\Api\BotApi::jsonValidate() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
98
            $this->handle([Update::fromResponse($data)]);
99
        }
100
    }
101
102
    /**
103
     * @return false|string
104
     */
105
    public function getRawBody()
106
    {
107
        return file_get_contents('php://input');
108
    }
109
110
    /**
111
     * @param Closure $action
112
     * @return $this
113
     */
114
    public function anyUpdate(Closure $action)
115
    {
116
        $this->on(self::getMessageEvent($action), self::getMessageChecker());
117
        $this->on(self::getEditedMessageEvent($action), self::getEditedMessageChecker());
118
        $this->on(self::getCallbackQueryEvent($action), self::getCallbackQueryChecker());
119
        $this->on(self::getChannelPostEvent($action), self::getChannelPostChecker());
120
        $this->on(self::getEditedChannelPostEvent($action), self::getEditedChannelPostChecker());
121
        $this->on(self::getInlineQueryEvent($action), self::getInlineQueryChecker());
122
        $this->on(self::getChosenInlineResultEvent($action), self::getChosenInlineResultChecker());
123
        $this->on(self::getShippingQueryEvent($action), self::getShippingQueryChecker());
124
        $this->on(self::getPreCheckoutQueryEvent($action), self::getPreCheckoutQueryChecker());
125
126
        return $this;
127
    }
128
129
    /**
130
     * Use this method to add command. Parameters will be automatically parsed and passed to closure.
131
     *
132
     * @param string  $name
133
     * @param Closure $action
134
     * @return Client
135
     */
136
    public function command($name, Closure $action)
137
    {
138
        return $this->on(self::getEvent($action), self::getChecker($name));
139
    }
140
141
    public function message(Closure $action)
142
    {
143
        return $this->on(self::getMessageEvent($action), self::getMessageChecker());
144
    }
145
146
    public function editedMessage(Closure $action)
147
    {
148
        return $this->on(self::getEditedMessageEvent($action), self::getEditedMessageChecker());
149
    }
150
151
    public function callbackQuery(Closure $action)
152
    {
153
        return $this->on(self::getCallbackQueryEvent($action), self::getCallbackQueryChecker());
154
    }
155
156
    public function channelPost(Closure $action)
157
    {
158
        return $this->on(self::getChannelPostEvent($action), self::getChannelPostChecker());
159
    }
160
161
    public function editedChannelPost(Closure $action)
162
    {
163
        return $this->on(self::getEditedChannelPostEvent($action), self::getEditedChannelPostChecker());
164
    }
165
166
    public function inlineQuery(Closure $action)
167
    {
168
        return $this->on(self::getInlineQueryEvent($action), self::getInlineQueryChecker());
169
    }
170
171
    public function chosenInlineResult(Closure $action)
172
    {
173
        return $this->on(self::getChosenInlineResultEvent($action), self::getChosenInlineResultChecker());
174
    }
175
176
    public function shippingQuery(Closure $action)
177
    {
178
        return $this->on(self::getShippingQueryEvent($action), self::getShippingQueryChecker());
179
    }
180
181
    public function preCheckoutQuery(Closure $action)
182
    {
183
        return $this->on(self::getPreCheckoutQueryEvent($action), self::getPreCheckoutQueryChecker());
184
    }
185
186
    /**
187
     * Returns event function to handling the command.
188
     *
189
     * @param Closure $action
190
     * @return Closure
191
     */
192 4
    protected static function getEvent(Closure $action)
193
    {
194
        return function (Update $update) use ($action) {
195 4
            $message = $update->getMessage();
196
197 4
            if (!$message) {
198 1
                return true;
199
            }
200
201 3
            preg_match(self::REGEXP, $message->getText(), $matches);
202
203 3
            if (isset($matches[3]) && !empty($matches[3])) {
204 1
                $parameters = str_getcsv($matches[3], chr(32));
205 1
            } else {
206 2
                $parameters = [];
207
            }
208
209 3
            array_unshift($parameters, $message);
210
211 3
            $action = new ReflectionFunction($action);
212
213 3
            if (count($parameters) >= $action->getNumberOfRequiredParameters()) {
214 3
                $action->invokeArgs($parameters);
215 3
            }
216
217 3
            return false;
218 4
        };
219
    }
220
221 View Code Duplication
    protected static function getMessageEvent(Closure $action)
222
    {
223
        return function (Update $update) use ($action) {
224
            if (!$update->getMessage()) {
225
                return true;
226
            }
227
228
            $reflectionAction = new ReflectionFunction($action);
229
            $reflectionAction->invokeArgs([$update->getMessage()]);
230
            return false;
231
        };
232
    }
233
234 View Code Duplication
    protected static function getEditedMessageEvent(Closure $action)
235
    {
236
        return function (Update $update) use ($action) {
237
            if (!$update->getEditedMessage()) {
238
                return true;
239
            }
240
241
            $reflectionAction = new ReflectionFunction($action);
242
            $reflectionAction->invokeArgs([$update->getEditedMessage()]);
243
            return false;
244
        };
245
    }
246
247 View Code Duplication
    protected static function getChannelPostEvent(Closure $action)
248
    {
249
        return function (Update $update) use ($action) {
250
            if (!$update->getChannelPost()) {
251
                return true;
252
            }
253
254
            $reflectionAction = new ReflectionFunction($action);
255
            $reflectionAction->invokeArgs([$update->getChannelPost()]);
256
            return false;
257
        };
258
    }
259
260 View Code Duplication
    protected static function getCallbackQueryEvent(Closure $action)
261
    {
262
        return function (Update $update) use ($action) {
263
            if (!$update->getCallbackQuery()) {
264
                return true;
265
            }
266
267
            $reflectionAction = new ReflectionFunction($action);
268
            $reflectionAction->invokeArgs([$update->getCallbackQuery()]);
269
            return false;
270
        };
271
    }
272
273 View Code Duplication
    protected static function getEditedChannelPostEvent(Closure $action)
274
    {
275
        return function (Update $update) use ($action) {
276
            if (!$update->getEditedChannelPost()) {
277
                return true;
278
            }
279
280
            $reflectionAction = new ReflectionFunction($action);
281
            $reflectionAction->invokeArgs([$update->getEditedChannelPost()]);
282
            return false;
283
        };
284
    }
285
286 4 View Code Duplication
    protected static function getInlineQueryEvent(Closure $action)
287
    {
288
        return function (Update $update) use ($action) {
289 4
            if (!$update->getInlineQuery()) {
290 3
                return true;
291
            }
292
293 1
            $reflectionAction = new ReflectionFunction($action);
294 1
            $reflectionAction->invokeArgs([$update->getInlineQuery()]);
295 1
            return false;
296 4
        };
297
    }
298
299 View Code Duplication
    protected static function getChosenInlineResultEvent(Closure $action)
300
    {
301
        return function (Update $update) use ($action) {
302
            if (!$update->getChosenInlineResult()) {
303
                return true;
304
            }
305
306
            $reflectionAction = new ReflectionFunction($action);
307
            $reflectionAction->invokeArgs([$update->getChosenInlineResult()]);
308
            return false;
309
        };
310
    }
311
312 View Code Duplication
    protected static function getShippingQueryEvent(Closure $action)
313
    {
314
        return function (Update $update) use ($action) {
315
            if (!$update->getShippingQuery()) {
316
                return true;
317
            }
318
319
            $reflectionAction = new ReflectionFunction($action);
320
            $reflectionAction->invokeArgs([$update->getShippingQuery()]);
321
            return false;
322
        };
323
    }
324
325 View Code Duplication
    protected static function getPreCheckoutQueryEvent(Closure $action)
326
    {
327
        return function (Update $update) use ($action) {
328
            if (!$update->getPreCheckoutQuery()) {
329
                return true;
330
            }
331
332
            $reflectionAction = new ReflectionFunction($action);
333
            $reflectionAction->invokeArgs([$update->getPreCheckoutQuery()]);
334
            return false;
335
        };
336
    }
337
338
    /**
339
     * Returns check function to handling the command.
340
     *
341
     * @param string $name
342
     * @return Closure
343
     */
344 4
    protected static function getChecker($name)
345
    {
346
        return function (Update $update) use ($name) {
347 4
            $message = $update->getMessage();
348 4
            if (is_null($message) || !strlen($message->getText())) {
349 1
                return false;
350
            }
351
352 3
            preg_match(self::REGEXP, $message->getText(), $matches);
353
354 3
            return !empty($matches) && $matches[1] == $name;
355 4
        };
356
    }
357
358
    /**
359
     * Returns check function to handling the message.
360
     *
361
     * @return Closure
362
     */
363
    protected static function getMessageChecker()
364
    {
365
        return function (Update $update) {
366
            return !is_null($update->getMessage());
367
        };
368
    }
369
370
    /**
371
     * Returns check function to handling the edited message.
372
     *
373
     * @return Closure
374
     */
375
    protected static function getEditedMessageChecker()
376
    {
377
        return function (Update $update) {
378
            return !is_null($update->getEditedMessage());
379
        };
380
    }
381
382
    /**
383
     * Returns check function to handling the channel post.
384
     *
385
     * @return Closure
386
     */
387
    protected static function getChannelPostChecker()
388
    {
389
        return function (Update $update) {
390
            return !is_null($update->getChannelPost());
391
        };
392
    }
393
394
    /**
395
     * Returns check function to handling the callbackQuery.
396
     *
397
     * @return Closure
398
     */
399
    protected static function getCallbackQueryChecker()
400
    {
401
        return function (Update $update) {
402
            return !is_null($update->getCallbackQuery());
403
        };
404
    }
405
406
    /**
407
     * Returns check function to handling the edited channel post.
408
     *
409
     * @return Closure
410
     */
411
    protected static function getEditedChannelPostChecker()
412
    {
413
        return function (Update $update) {
414
            return !is_null($update->getEditedChannelPost());
415
        };
416
    }
417
418
    /**
419
     * Returns check function to handling the chosen inline result.
420
     *
421
     * @return Closure
422
     */
423
    protected static function getChosenInlineResultChecker()
424
    {
425
        return function (Update $update) {
426
            return !is_null($update->getChosenInlineResult());
427
        };
428
    }
429
430
    /**
431
     * Returns check function to handling the inline queries.
432
     *
433
     * @return Closure
434
     */
435 4
    protected static function getInlineQueryChecker()
436
    {
437
        return function (Update $update) {
438 4
            return !is_null($update->getInlineQuery());
439 4
        };
440
    }
441
442
    /**
443
     * Returns check function to handling the shipping queries.
444
     *
445
     * @return Closure
446
     */
447
    protected static function getShippingQueryChecker()
448
    {
449
        return function (Update $update) {
450
            return !is_null($update->getShippingQuery());
451
        };
452
    }
453
454
    /**
455
     * Returns check function to handling the pre checkout queries.
456
     *
457
     * @return Closure
458
     */
459
    protected static function getPreCheckoutQueryChecker()
460
    {
461
        return function (Update $update) {
462
            return !is_null($update->getPreCheckoutQuery());
463
        };
464
    }
465
}
466