Passed
Push — master ( 4758b5...bdbbd2 )
by
unknown
02:21
created

Client::run()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 6
c 0
b 0
f 0
ccs 0
cts 5
cp 0
rs 9.4285
cc 2
eloc 3
nc 2
nop 0
crap 6
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 \TelegramBot\Api\BotApi
24
     */
25
    protected $api;
26
27
    /**
28
     * @var \TelegramBot\Api\Events\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
     * Use this method to add command. Parameters will be automatically parsed and passed to closure.
46
     *
47
     * @param string $name
48
     * @param \Closure $action
49
     *
50
     * @return \TelegramBot\Api\Client
51
     */
52
    public function command($name, Closure $action)
53
    {
54
        return $this->on(self::getEvent($action), self::getChecker($name));
55
    }
56
57
    public function editedMessage(Closure $action)
58
    {
59
        return $this->on(self::getEditedMessageEvent($action), self::getEditedMessageChecker());
60
    }
61
62
    public function channelPost(Closure $action)
63
    {
64
        return $this->on(self::getChannelPostEvent($action), self::getChannelPostChecker());
65
    }
66
67
    public function editedChannelPost(Closure $action)
68
    {
69
        return $this->on(self::getEditedChannelPostEvent($action), self::getEditedChannelPostChecker());
70
    }
71
72
    public function inlineQuery(Closure $action)
73
    {
74
        return $this->on(self::getInlineQueryEvent($action), self::getInlineQueryChecker());
75
    }
76
77
    public function chosenInlineResult(Closure $action)
78
    {
79
        return $this->on(self::getChosenInlineResultEvent($action), self::getChosenInlineResultChecker());
80
    }
81
82
    public function shippingQuery(Closure $action)
83
    {
84
        return $this->on(self::getShippingQueryEvent($action), self::getShippingQueryChecker());
85
    }
86
87
    public function preCheckoutQuery(Closure $action)
88
    {
89
        return $this->on(self::getPreCheckoutQueryEvent($action), self::getPreCheckoutQueryChecker());
90
    }
91
92
    /**
93
     * Use this method to add an event.
94
     * If second closure will return true (or if you are passed null instead of closure), first one will be executed.
95
     *
96
     * @param \Closure $event
97
     * @param \Closure|null $checker
98
     *
99
     * @return \TelegramBot\Api\Client
100
     */
101 1
    public function on(Closure $event, Closure $checker = null)
102
    {
103 1
        $this->events->add($event, $checker);
104
105 1
        return $this;
106
    }
107
108
    /**
109
     * Handle updates
110
     *
111
     * @param Update[] $updates
112
     */
113 4
    public function handle(array $updates)
114
    {
115 4
        foreach ($updates as $update) {
116
            /* @var \TelegramBot\Api\Types\Update $update */
117 4
            $this->events->handle($update);
118 4
        }
119 4
    }
120
121
    /**
122
     * Webhook handler
123
     *
124
     * @return array
125
     * @throws \TelegramBot\Api\InvalidJsonException
126
     */
127
    public function run()
128
    {
129
        if ($data = BotApi::jsonValidate($this->getRawBody(), true)) {
130
            $this->handle([Update::fromResponse($data)]);
131
        }
132
    }
133
134
    public function getRawBody()
135
    {
136
        return file_get_contents('php://input');
137
    }
138
139
    /**
140
     * Returns event function to handling the command.
141
     *
142
     * @param \Closure $action
143
     *
144
     * @return \Closure
145
     */
146 4
    protected static function getEvent(Closure $action)
147
    {
148
        return function (Update $update) use ($action) {
149 4
            $message = $update->getMessage();
150 4
            if (!$message) {
151 1
                return true;
152
            }
153
154 3
            preg_match(self::REGEXP, $message->getText(), $matches);
155
156 3
            if (isset($matches[3]) && !empty($matches[3])) {
157 1
                $parameters = str_getcsv($matches[3], chr(32));
158 1
            } else {
159 2
                $parameters = [];
160
            }
161
162 3
            array_unshift($parameters, $message);
163
164 3
            $action = new ReflectionFunction($action);
165
166 3
            if (count($parameters) >= $action->getNumberOfRequiredParameters()) {
167 3
                $action->invokeArgs($parameters);
168 3
            }
169
170 3
            return false;
171 4
        };
172
    }
173
174 View Code Duplication
    protected static function getEditedMessageEvent(Closure $action)
175
    {
176
        return function (Update $update) use ($action) {
177
            if (!$update->getEditedMessage()) {
178
                return true;
179
            }
180
181
            $reflectionAction = new ReflectionFunction($action);
182
            $reflectionAction->invokeArgs([$update->getEditedMessage()]);
183
            return false;
184
        };
185
    }
186
187 View Code Duplication
    protected static function getChannelPostEvent(Closure $action)
188
    {
189
        return function (Update $update) use ($action) {
190
            if (!$update->getChannelPost()) {
191
                return true;
192
            }
193
194
            $reflectionAction = new ReflectionFunction($action);
195
            $reflectionAction->invokeArgs([$update->getChannelPost()]);
196
            return false;
197
        };
198
    }
199
200 View Code Duplication
    protected static function getEditedChannelPostEvent(Closure $action)
201
    {
202
        return function (Update $update) use ($action) {
203
            if (!$update->getEditedChannelPost()) {
204
                return true;
205
            }
206
207
            $reflectionAction = new ReflectionFunction($action);
208
            $reflectionAction->invokeArgs([$update->getEditedChannelPost()]);
209
            return false;
210
        };
211
    }
212
213 4 View Code Duplication
    protected static function getInlineQueryEvent(Closure $action)
214
    {
215
        return function (Update $update) use ($action) {
216 4
            if (!$update->getInlineQuery()) {
217 3
                return true;
218
            }
219
220 1
            $reflectionAction = new ReflectionFunction($action);
221 1
            $reflectionAction->invokeArgs([$update->getInlineQuery()]);
222 1
            return false;
223 4
        };
224
    }
225
226 View Code Duplication
    protected static function getChosenInlineResultEvent(Closure $action)
227
    {
228
        return function (Update $update) use ($action) {
229
            if (!$update->getChosenInlineResult()) {
230
                return true;
231
            }
232
233
            $reflectionAction = new ReflectionFunction($action);
234
            $reflectionAction->invokeArgs([$update->getChosenInlineResult()]);
235
            return false;
236
        };
237
    }
238
239 View Code Duplication
    protected static function getShippingQueryEvent(Closure $action)
240
    {
241
        return function (Update $update) use ($action) {
242
            if (!$update->getShippingQuery()) {
243
                return true;
244
            }
245
246
            $reflectionAction = new ReflectionFunction($action);
247
            $reflectionAction->invokeArgs([$update->getShippingQuery()]);
248
            return false;
249
        };
250
    }
251
252 View Code Duplication
    protected static function getPreCheckoutQueryEvent(Closure $action)
253
    {
254
        return function (Update $update) use ($action) {
255
            if (!$update->getPreCheckoutQuery()) {
256
                return true;
257
            }
258
259
            $reflectionAction = new ReflectionFunction($action);
260
            $reflectionAction->invokeArgs([$update->getPreCheckoutQuery()]);
261
            return false;
262
        };
263
    }
264
265
    /**
266
     * Returns check function to handling the command.
267
     *
268
     * @param string $name
269
     *
270
     * @return \Closure
271
     */
272 4
    protected static function getChecker($name)
273
    {
274
        return function (Update $update) use ($name) {
275 4
            $message = $update->getMessage();
276 4
            if (is_null($message) || !strlen($message->getText())) {
277 1
                return false;
278
            }
279
280 3
            preg_match(self::REGEXP, $message->getText(), $matches);
281
282 3
            return !empty($matches) && $matches[1] == $name;
283 4
        };
284
    }
285
286
    /**
287
     * Returns check function to handling the edited message.
288
     *
289
     * @return Closure
290
     */
291
    protected static function getEditedMessageChecker()
292
    {
293
        return function (Update $update) {
294
            return !is_null($update->getEditedMessage());
295
        };
296
    }
297
298
    /**
299
     * Returns check function to handling the channel post.
300
     *
301
     * @return Closure
302
     */
303
    protected static function getChannelPostChecker()
304
    {
305
        return function (Update $update) {
306
            return !is_null($update->getChannelPost());
307
        };
308
    }
309
310
    /**
311
     * Returns check function to handling the edited channel post.
312
     *
313
     * @return Closure
314
     */
315
    protected static function getEditedChannelPostChecker()
316
    {
317
        return function (Update $update) {
318
            return !is_null($update->getEditedChannelPost());
319
        };
320
    }
321
322
    /**
323
     * Returns check function to handling the chosen inline result.
324
     *
325
     * @return Closure
326
     */
327
    protected static function getChosenInlineResultChecker()
328
    {
329
        return function (Update $update) {
330
            return !is_null($update->getChosenInlineResult());
331
        };
332
    }
333
334
    /**
335
     * Returns check function to handling the inline queries.
336
     *
337
     * @return Closure
338
     */
339 4
    protected static function getInlineQueryChecker()
340
    {
341
        return function (Update $update) {
342 4
            return !is_null($update->getInlineQuery());
343 4
        };
344
    }
345
346
    /**
347
     * Returns check function to handling the shipping queries.
348
     *
349
     * @return Closure
350
     */
351
    protected static function getShippingQueryChecker()
352
    {
353
        return function (Update $update) {
354
            return !is_null($update->getShippingQuery());
355
        };
356
    }
357
358
    /**
359
     * Returns check function to handling the pre checkout queries.
360
     *
361
     * @return Closure
362
     */
363
    protected static function getPreCheckoutQueryChecker()
364
    {
365
        return function (Update $update) {
366
            return !is_null($update->getPreCheckoutQuery());
367
        };
368
    }
369
370 1
    public function __call($name, array $arguments)
371
    {
372 1
        if (method_exists($this, $name)) {
373
            return call_user_func_array([$this, $name], $arguments);
374 1
        } elseif (method_exists($this->api, $name)) {
375
            return call_user_func_array([$this->api, $name], $arguments);
376
        }
377 1
        throw new BadMethodCallException("Method {$name} not exists");
378
    }
379
}
380