Passed
Push — develop ( d90f78...c22f56 )
by Michele
42s queued 10s
created

ListenerCollector::fallback()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Zanzara\Listener;
6
7
use DI\DependencyException;
8
use DI\NotFoundException;
9
use Psr\Container\ContainerInterface;
10
use Zanzara\Middleware\MiddlewareCollector;
11
use Zanzara\Middleware\MiddlewareInterface;
12
use Zanzara\Telegram\Type\CallbackQuery;
13
use Zanzara\Telegram\Type\ChannelPost;
14
use Zanzara\Telegram\Type\ChosenInlineResult;
15
use Zanzara\Telegram\Type\EditedChannelPost;
16
use Zanzara\Telegram\Type\EditedMessage;
17
use Zanzara\Telegram\Type\InlineQuery;
18
use Zanzara\Telegram\Type\Message;
19
use Zanzara\Telegram\Type\Passport\PassportData;
20
use Zanzara\Telegram\Type\Poll\Poll;
21
use Zanzara\Telegram\Type\Poll\PollAnswer;
22
use Zanzara\Telegram\Type\ReplyToMessage;
23
use Zanzara\Telegram\Type\Shipping\PreCheckoutQuery;
24
use Zanzara\Telegram\Type\Shipping\ShippingQuery;
25
use Zanzara\Telegram\Type\Shipping\SuccessfulPayment;
26
use Zanzara\Telegram\Type\Update;
27
28
/**
29
 * Class ListenerCollector
30
 * @package Zanzara\Listener
31
 */
32
abstract class ListenerCollector
33
{
34
35
    /**
36
     * Associative array for listeners.
37
     * Key is always the listener type that can be either a simple string (eg. messages, cb_query_texts) or the class
38
     * name of the Update type, @see Update::detectUpdateType().
39
     * Value can be an ordered array of @see Listener or another associative array where the key
40
     * is the listenerId and the value the actual @see Listener.
41
     *
42
     * Eg.
43
     * [
44
     *      'messages' => [
45
     *          '/start' => Listener(),
46
     *          'Simple text' => Listener(),
47
     *      ],
48
     *      'Zanzara\Telegram\Type\CallbackQuery' => [
49
     *          Listener(),
50
     *          Listener(),
51
     *          Listener()
52
     *      ]
53
     * ]
54
     *
55
     * @var array
56
     */
57
    protected $listeners = [];
58
59
    /**
60
     * @var Listener
61
     */
62
    protected $fallbackListener;
63
64
    /**
65
     * @var ContainerInterface
66
     */
67
    protected $container;
68
69
    /**
70
     * @var array
71
     */
72
    protected $middleware = [];
73
74
    /**
75
     * Listen for the specified command.
76
     * Eg. $bot->onCommand('start', function(Context $ctx) {});
77
     *
78
     * @param  string  $command
79
     * @param $callback
80
     * @return MiddlewareCollector
81
     * @throws DependencyException
82
     * @throws NotFoundException
83
     */
84
    public function onCommand(string $command, $callback): MiddlewareCollector
85
    {
86
        $command = "/^\/$command$/";
87
        $listener = new Listener($callback, $this->container, $command);
88
        $this->listeners['messages'][$command] = $listener;
89
        return $listener;
90
    }
91
92
    /**
93
     * Listen for a message with the specified text.
94
     * Eg. $bot->onText('What time is it?', function(Context $ctx) {});
95
     *
96
     * Text is a regex, so you could also do something like:
97
     * $bot->onText('[a-zA-Z]{15}?', function(Context $ctx) {});
98
     *
99
     * @param  string  $text
100
     * @param  $callback
101
     * @return MiddlewareCollector
102
     * @throws DependencyException
103
     * @throws NotFoundException
104
     */
105
    public function onText(string $text, $callback): MiddlewareCollector
106
    {
107
        $text = "/$text/";
108
        $listener = new Listener($callback, $this->container, $text);
109
        $this->listeners['messages'][$text] = $listener;
110
        return $listener;
111
    }
112
113
    /**
114
     * Listen for a generic message.
115
     * You can call this function more than once, every callback will be executed.
116
     *
117
     * Eg. $bot->onMessage(function(Context $ctx) {});
118
     *
119
     * @param  $callback
120
     * @return MiddlewareCollector
121
     * @throws DependencyException
122
     * @throws NotFoundException
123
     */
124
    public function onMessage($callback): MiddlewareCollector
125
    {
126
        $listener = new Listener($callback, $this->container);
127
        $this->listeners[Message::class][] = $listener;
128
        return $listener;
129
    }
130
131
    /**
132
     * Listen for a message that is a reply of another message.
133
     * You can call this function more than once, every callback will be executed.
134
     *
135
     * Eg. $bot->onReplyToMessage(function(Context $ctx) {});
136
     *
137
     * @param  $callback
138
     * @return MiddlewareCollector
139
     * @throws DependencyException
140
     * @throws NotFoundException
141
     */
142
    public function onReplyToMessage($callback): MiddlewareCollector
143
    {
144
        $listener = new Listener($callback, $this->container);
145
        $this->listeners[ReplyToMessage::class][] = $listener;
146
        return $listener;
147
    }
148
149
    /**
150
     * Listen for an edited message.
151
     * You can call this function more than once, every callback will be executed.
152
     *
153
     * Eg. $bot->onEditedMessage(function(Context $ctx) {});
154
     *
155
     * @param  $callback
156
     * @return MiddlewareCollector
157
     * @throws DependencyException
158
     * @throws NotFoundException
159
     */
160
    public function onEditedMessage($callback): MiddlewareCollector
161
    {
162
        $listener = new Listener($callback, $this->container);
163
        $this->listeners[EditedMessage::class][] = $listener;
164
        return $listener;
165
    }
166
167
    /**
168
     * Listen for a callback query with the specified message text.
169
     *
170
     * Eg. $bot->onCbQueryText('How many apples do you want?', function(Context $ctx) {});
171
     *
172
     * Text is a regex, so you could also do something like:
173
     * $bot->onCbQueryText('[a-zA-Z]{27}?', function(Context $ctx) {});
174
     *
175
     * @param  string  $text
176
     * @param  $callback
177
     * @return MiddlewareCollector
178
     * @throws DependencyException
179
     * @throws NotFoundException
180
     */
181
    public function onCbQueryText(string $text, $callback): MiddlewareCollector
182
    {
183
        $text = "/$text/";
184
        $listener = new Listener($callback, $this->container, $text);
185
        $this->listeners['cb_query_texts'][$text] = $listener;
186
        return $listener;
187
    }
188
189
    /**
190
     * Listen for a callback query with the specified callback data.
191
     *
192
     * Eg. $bot->onCbQueryData(['accept', 'refuse'], function(Context $ctx) {});
193
     *
194
     * Data values are a regex, so you could also do something like:
195
     * $bot->onCbQueryData(['acc.'], function(Context $ctx) {});
196
     *
197
     * @param  array  $data
198
     * @param  $callback
199
     * @return MiddlewareCollector
200
     * @throws DependencyException
201
     * @throws NotFoundException
202
     */
203
    public function onCbQueryData(array $data, $callback): MiddlewareCollector
204
    {
205
        // merge values with "|" (eg. "accept|refuse|later"), then ListenerResolver will check the callback data
206
        // against that regex.
207
        $id = '/'.implode('|', $data).'/';
208
        $listener = new Listener($callback, $this->container, $id);
209
        $this->listeners['cb_query_data'][$id] = $listener;
210
        return $listener;
211
    }
212
213
    /**
214
     * Listen for a generic callback query.
215
     * You can call this function more than once, every callback will be executed.
216
     *
217
     * Eg. $bot->onCbQuery(function(Context $ctx) {});
218
     *
219
     * @param  $callback
220
     * @return MiddlewareCollector
221
     * @throws DependencyException
222
     * @throws NotFoundException
223
     */
224
    public function onCbQuery($callback): MiddlewareCollector
225
    {
226
        $listener = new Listener($callback, $this->container);
227
        $this->listeners[CallbackQuery::class][] = $listener;
228
        return $listener;
229
    }
230
231
    /**
232
     * Listener for a shipping query.
233
     * You can call this function more than once, every callback will be executed.
234
     *
235
     * Eg. $bot->onShippingQuery(function(Context $ctx) {});
236
     *
237
     * @param  $callback
238
     * @return MiddlewareCollector
239
     * @throws DependencyException
240
     * @throws NotFoundException
241
     */
242
    public function onShippingQuery($callback): MiddlewareCollector
243
    {
244
        $listener = new Listener($callback, $this->container);
245
        $this->listeners[ShippingQuery::class][] = $listener;
246
        return $listener;
247
    }
248
249
    /**
250
     * Listen for a pre checkout query.
251
     * You can call this function more than once, every callback will be executed.
252
     *
253
     * Eg. $bot->onPreCheckoutQuery(function(Context $ctx) {});
254
     *
255
     * @param  $callback
256
     * @return MiddlewareCollector
257
     * @throws DependencyException
258
     * @throws NotFoundException
259
     */
260
    public function onPreCheckoutQuery($callback): MiddlewareCollector
261
    {
262
        $listener = new Listener($callback, $this->container);
263
        $this->listeners[PreCheckoutQuery::class][] = $listener;
264
        return $listener;
265
    }
266
267
    /**
268
     * Listen for a successful payment.
269
     * You can call this function more than once, every callback will be executed.
270
     *
271
     * Eg. $bot->onSuccessfulPayment(function(Context $ctx) {});
272
     *
273
     * @param  $callback
274
     * @return MiddlewareCollector
275
     * @throws DependencyException
276
     * @throws NotFoundException
277
     */
278
    public function onSuccessfulPayment($callback): MiddlewareCollector
279
    {
280
        $listener = new Listener($callback, $this->container);
281
        $this->listeners[SuccessfulPayment::class][] = $listener;
282
        return $listener;
283
    }
284
285
    /**
286
     * Listen for a passport data message.
287
     * You can call this function more than once, every callback will be executed.
288
     *
289
     * Eg. $bot->onPassportData(function(Context $ctx) {});
290
     *
291
     * @param  $callback
292
     * @return MiddlewareCollector
293
     * @throws DependencyException
294
     * @throws NotFoundException
295
     */
296
    public function onPassportData($callback): MiddlewareCollector
297
    {
298
        $listener = new Listener($callback, $this->container);
299
        $this->listeners[PassportData::class][] = $listener;
300
        return $listener;
301
    }
302
303
    /**
304
     * Listen for an inline query.
305
     * You can call this function more than once, every callback will be executed.
306
     *
307
     * Eg. $bot->onInlineQuery(function(Context $ctx) {});
308
     *
309
     * @param  $callback
310
     * @return MiddlewareCollector
311
     * @throws DependencyException
312
     * @throws NotFoundException
313
     */
314
    public function onInlineQuery($callback): MiddlewareCollector
315
    {
316
        $listener = new Listener($callback, $this->container);
317
        $this->listeners[InlineQuery::class][] = $listener;
318
        return $listener;
319
    }
320
321
    /**
322
     * Listen for a chosen inline result.
323
     * You can call this function more than once, every callback will be executed.
324
     *
325
     * Eg. $bot->onChosenInlineResult(function(Context $ctx) {});
326
     *
327
     * @param  $callback
328
     * @return MiddlewareCollector
329
     * @throws DependencyException
330
     * @throws NotFoundException
331
     */
332
    public function onChosenInlineResult($callback): MiddlewareCollector
333
    {
334
        $listener = new Listener($callback, $this->container);
335
        $this->listeners[ChosenInlineResult::class][] = $listener;
336
        return $listener;
337
    }
338
339
    /**
340
     * Listen for a channel post.
341
     * You can call this function more than once, every callback will be executed.
342
     *
343
     * Eg. $bot->onChannelPost(function(Context $ctx) {});
344
     *
345
     * @param  $callback
346
     * @return MiddlewareCollector
347
     * @throws DependencyException
348
     * @throws NotFoundException
349
     */
350
    public function onChannelPost($callback): MiddlewareCollector
351
    {
352
        $listener = new Listener($callback, $this->container);
353
        $this->listeners[ChannelPost::class][] = $listener;
354
        return $listener;
355
    }
356
357
    /**
358
     * Listen for an edited channel post.
359
     * You can call this function more than once, every callback will be executed.
360
     *
361
     * Eg. $bot->onEditedChannelPost(function(Context $ctx) {});
362
     *
363
     * @param  $callback
364
     * @return MiddlewareCollector
365
     * @throws DependencyException
366
     * @throws NotFoundException
367
     */
368
    public function onEditedChannelPost($callback): MiddlewareCollector
369
    {
370
        $listener = new Listener($callback, $this->container);
371
        $this->listeners[EditedChannelPost::class][] = $listener;
372
        return $listener;
373
    }
374
375
    /**
376
     * Listen for a poll.
377
     * You can call this function more than once, every callback will be executed.
378
     *
379
     * Eg. $bot->onPoll(function(Context $ctx) {});
380
     *
381
     * @param  $callback
382
     * @return MiddlewareCollector
383
     * @throws DependencyException
384
     * @throws NotFoundException
385
     */
386
    public function onPoll($callback): MiddlewareCollector
387
    {
388
        $listener = new Listener($callback, $this->container);
389
        $this->listeners[Poll::class][] = $listener;
390
        return $listener;
391
    }
392
393
    /**
394
     * Listen for a poll answer.
395
     * You can call this function more than once, every callback will be executed.
396
     *
397
     * Eg. $bot->onPollAnswer(function(Context $ctx) {});
398
     *
399
     * @param  $callback
400
     * @return MiddlewareCollector
401
     * @throws DependencyException
402
     * @throws NotFoundException
403
     */
404
    public function onPollAnswer($callback): MiddlewareCollector
405
    {
406
        $listener = new Listener($callback, $this->container);
407
        $this->listeners[PollAnswer::class][] = $listener;
408
        return $listener;
409
    }
410
411
    /**
412
     * Listen for a generic update.
413
     * You can call this function more than once, every callback will be executed.
414
     *
415
     * Eg. $bot->onUpdate(function(Context $ctx) {});
416
     *
417
     * @param  $callback
418
     * @return MiddlewareCollector
419
     * @throws DependencyException
420
     * @throws NotFoundException
421
     */
422
    public function onUpdate($callback): MiddlewareCollector
423
    {
424
        $listener = new Listener($callback, $this->container);
425
        $this->listeners[Update::class][] = $listener;
426
        return $listener;
427
    }
428
429
    /**
430
     * If no listener matches the current update, this listener will be called if specified.
431
     *
432
     * @param $callback
433
     * @return MiddlewareCollector
434
     * @throws DependencyException
435
     * @throws NotFoundException
436
     */
437
    public function fallback($callback): MiddlewareCollector
438
    {
439
        $listener = new Listener($callback, $this->container);
440
        $this->fallbackListener = $listener;
441
        return $listener;
442
    }
443
444
    /**
445
     * Define a middleware that will be executed for every listener function and before listener-specific middleware.
446
     *
447
     * Eg:
448
     * $bot = new Zanzara($_ENV['BOT_TOKEN']);
449
     * $bot->middleware(new GenericMiddleware());
450
     *
451
     * $bot->onCommand('start', function(Context $ctx) {
452
     *      $ctx->sendMessage('Hello');
453
     * })->middleware(new SpecificMiddleware());
454
     *
455
     * In this case GenericMiddleware will be executed before SpecificMiddleware.
456
     *
457
     * @param  MiddlewareInterface|callable  $middleware
458
     * @return self
459
     */
460
    public function middleware($middleware): self
461
    {
462
        array_unshift($this->middleware, $middleware);
463
        return $this;
464
    }
465
466
    /**
467
     * Add cross-request middleware to each listener middleware chain.
468
     *
469
     */
470
    protected function feedMiddlewareStack()
471
    {
472
        array_walk_recursive($this->listeners, function ($value) {
473
            if ($value instanceof Listener) {
474
                foreach ($this->middleware as $m) {
475
                    $value->middleware($m);
476
                }
477
            }
478
        });
479
    }
480
}
481