ListenerResolver::resolveListeners()   C
last analyzed

Complexity

Conditions 12
Paths 6

Size

Total Lines 68
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 12
eloc 45
c 2
b 1
f 0
nc 6
nop 1
dl 0
loc 68
rs 6.9666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Zanzara\Listener;
6
7
use React\Promise\Deferred;
8
use React\Promise\PromiseInterface;
9
use Zanzara\ConversationManager;
10
use Zanzara\Telegram\Type\CallbackQuery;
11
use Zanzara\Telegram\Type\Message;
12
use Zanzara\Telegram\Type\Update;
13
14
/**
15
 *
16
 */
17
abstract class ListenerResolver extends ListenerCollector
18
{
19
20
    /**
21
     * @var ConversationManager
22
     */
23
    protected $conversationManager;
24
25
    /**
26
     * @param Update $update
27
     * @return PromiseInterface
28
     */
29
    public function resolveListeners(Update $update): PromiseInterface
30
    {
31
        $deferred = new Deferred();
32
        $listeners = [];
33
        $updateType = $update->getUpdateType();
34
        $this->mergeListenersByType($listeners, $updateType);
35
        $this->mergeListenersByType($listeners, Update::class);
36
37
        switch ($updateType) {
38
39
            case CallbackQuery::class:
40
                $chatId = $update->getEffectiveChat() ? $update->getEffectiveChat()->getId() : null;
41
                $callbackQuery = $update->getCallbackQuery();
42
                $text = $callbackQuery->getMessage() ? $callbackQuery->getMessage()->getText() : null;
43
                $this->conversationManager->getConversationHandler($chatId)
44
                    ->then(function ($handlerInfo) use ($deferred, $callbackQuery, $text, &$listeners) {
45
                        if (!$handlerInfo) { // if we are not in a conversation, call the listeners as usual
46
                            if ($text) {
47
                                $this->findListenerAndPush($listeners, 'cb_query_texts', $text);
48
                            }
49
                            if ($callbackQuery->getData()) {
50
                                $this->findListenerAndPush($listeners, 'cb_query_data', $callbackQuery->getData());
51
                            }
52
                        } else { // if we are in a conversation, redirect it only to the conversation step
53
                            $listeners[] = new Listener($handlerInfo[0], $this->container);
54
                        }
55
                        $deferred->resolve($listeners);
56
                    })->otherwise(function ($e) use ($deferred) {
0 ignored issues
show
Bug introduced by
The method otherwise() does not exist on React\Promise\PromiseInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Zanzara\Test\PromiseWrapper\ZanzaraPromise or React\Promise\CancellablePromiseInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

56
                    })->/** @scrutinizer ignore-call */ otherwise(function ($e) use ($deferred) {
Loading history...
57
                        // if something goes wrong, reject the promise
58
                        $deferred->reject($e);
59
                    });
60
                break;
61
62
            case Message::class:
63
                $text = $update->getMessage()->getText();
64
                $chatId = $update->getEffectiveChat()->getId();
65
                $this->conversationManager->getConversationHandler($chatId)
66
                    ->then(function ($handlerInfo) use ($chatId, $text, $deferred, &$listeners) {
67
                        if (!$handlerInfo) { // if we are not in a conversation, call the listeners as usual
68
                            $this->findListenerAndPush($listeners, 'messages', $text);
69
                        } elseif (!$handlerInfo[1] && $text) {
70
                            // if we are in a conversation, and listeners are not skipped by the step call,
71
                            // try to call the matching listeners
72
                            $listener = $this->findListenerAndPush($listeners, 'messages', $text, true);
73
                            if (!$listener) {
74
                                // if no listeners are found, call the next conversation step
75
                                $listeners[] = new Listener($handlerInfo[0], $this->container);
76
                            } else {
77
                                // if listener is found, escape the conversation
78
                                $this->conversationManager->deleteConversationCache($chatId);
79
                            }
80
                        } else {
81
                            // if the coversation is forcing only the conversation handlers,
82
                            // skip the other listeners
83
                            $listeners[] = new Listener($handlerInfo[0], $this->container);
84
                        }
85
                        $deferred->resolve($listeners);
86
                    })->otherwise(function ($e) use ($deferred) {
87
                        // if something goes wrong, reject the promise
88
                        $deferred->reject($e);
89
                    });
90
                break;
91
92
            default:
93
                $deferred->resolve($listeners);
94
        }
95
96
        return $deferred->promise();
97
    }
98
99
    /**
100
     * @param Listener[] $listeners
101
     * @param string $listenerType
102
     * @param string|null $listenerId
103
     * @param bool $skipFallback
104
     * @return Listener|null
105
     */
106
    private function findListenerAndPush(array &$listeners, string $listenerType, ?string $listenerId = null, bool $skipFallback = false): ?Listener
107
    {
108
        if ($listenerId !== null) {
109
            $typedListeners = $this->listeners[$listenerType] ?? [];
110
            foreach ($typedListeners as $regex => $listener) {
111
                $regexMatched = (bool) preg_match($regex, $listenerId, $matches, PREG_UNMATCHED_AS_NULL);
112
                if ($regexMatched) {
113
                    $parameters = array_unique(array_values(array_slice($matches, 1)));
114
                    $listeners[] = $listener->setParameters($parameters);
115
                    return $listener;
116
                }
117
            }
118
        }
119
120
        if (isset($this->listeners['fallback']) && !$skipFallback) {
121
            $listeners[] = $this->listeners['fallback'];
122
            return $this->listeners['fallback'];
123
        }
124
125
        return null;
126
    }
127
128
    /**
129
     * @param Listener[] $listeners
130
     * @param string $listenerType
131
     */
132
    private function mergeListenersByType(array &$listeners, string $listenerType)
133
    {
134
        $toMerge = $this->listeners[$listenerType] ?? null;
135
        if ($toMerge) {
136
            $listeners = array_merge($listeners, $toMerge);
137
        }
138
    }
139
140
}
141