diff --git a/src/Zanzara/Context.php b/src/Zanzara/Context.php index c3a27ec..975eca9 100644 --- a/src/Zanzara/Context.php +++ b/src/Zanzara/Context.php @@ -488,4 +488,11 @@ public function getLoop(): LoopInterface return $this->container->get(LoopInterface::class); } + /** + * @return bool + */ + public function isCallbackQuery(): bool + { + return $this->getCallbackQuery() !== null; + } } diff --git a/src/Zanzara/Listener/ListenerCollector.php b/src/Zanzara/Listener/ListenerCollector.php index 6dd6830..1f3ff4b 100644 --- a/src/Zanzara/Listener/ListenerCollector.php +++ b/src/Zanzara/Listener/ListenerCollector.php @@ -56,11 +56,6 @@ abstract class ListenerCollector */ protected $listeners = []; - /** - * @var Listener - */ - protected $fallbackListener; - /** * @var ContainerInterface */ @@ -437,7 +432,7 @@ public function onUpdate($callback): MiddlewareCollector public function fallback($callback): MiddlewareCollector { $listener = new Listener($callback, $this->container); - $this->fallbackListener = $listener; + $this->listeners['fallback'] = $listener; return $listener; } diff --git a/src/Zanzara/Listener/ListenerResolver.php b/src/Zanzara/Listener/ListenerResolver.php index ecb2506..ec8f86c 100644 --- a/src/Zanzara/Listener/ListenerResolver.php +++ b/src/Zanzara/Listener/ListenerResolver.php @@ -37,29 +37,26 @@ public function resolveListeners(Update $update): PromiseInterface switch ($updateType) { case CallbackQuery::class: + $chatId = $update->getEffectiveChat() ? $update->getEffectiveChat()->getId() : null; $callbackQuery = $update->getCallbackQuery(); $text = $callbackQuery->getMessage() ? $callbackQuery->getMessage()->getText() : null; - if ($text) { - $this->findListenerAndPush($listeners, 'cb_query_texts', $text); - } - if ($callbackQuery->getData()) { - $this->findListenerAndPush($listeners, 'cb_query_data', $callbackQuery->getData()); - } - $chatId = $update->getEffectiveChat() ? $update->getEffectiveChat()->getId() : null; - if ($chatId) { - $this->conversationManager->getConversationHandler($chatId) - ->then(function ($handlerInfo) use ($deferred, &$listeners) { - if ($handlerInfo) { - $listeners[] = new Listener($handlerInfo[0], $this->container); + $this->conversationManager->getConversationHandler($chatId) + ->then(function ($handlerInfo) use ($deferred, $callbackQuery, $text, &$listeners) { + if (!$handlerInfo) { // if we are not in a conversation, call the listeners as usual + if ($text) { + $this->findListenerAndPush($listeners, 'cb_query_texts', $text); } - $deferred->resolve($listeners); - })->otherwise(function ($e) use ($deferred) { - // if something goes wrong, reject the promise - $deferred->reject($e); - }); - } else { - $deferred->resolve($listeners); - } + if ($callbackQuery->getData()) { + $this->findListenerAndPush($listeners, 'cb_query_data', $callbackQuery->getData()); + } + } else { // if we are in a conversation, redirect it only to the conversation step + $listeners[] = new Listener($handlerInfo[0], $this->container); + } + $deferred->resolve($listeners); + })->otherwise(function ($e) use ($deferred) { + // if something goes wrong, reject the promise + $deferred->reject($e); + }); break; case Message::class: @@ -67,29 +64,24 @@ public function resolveListeners(Update $update): PromiseInterface $chatId = $update->getEffectiveChat()->getId(); $this->conversationManager->getConversationHandler($chatId) ->then(function ($handlerInfo) use ($chatId, $text, $deferred, &$listeners) { - if (!$handlerInfo) { - if ($text) { - $this->findListenerAndPush($listeners, 'messages', $text); - } elseif ($this->fallbackListener) { - $listeners[] = $this->fallbackListener; - } - $deferred->resolve($listeners); - return; - } - - $skipListeners = $handlerInfo[1]; - - if (!$skipListeners && $text) { - $listener = $this->findListenerAndPush($listeners, 'messages', $text); + if (!$handlerInfo) { // if we are not in a conversation, call the listeners as usual + $this->findListenerAndPush($listeners, 'messages', $text); + } elseif (!$handlerInfo[1] && $text) { + // if we are in a conversation, and listeners are not skipped by the step call, + // try to call the matching listeners + $listener = $this->findListenerAndPush($listeners, 'messages', $text, true); if (!$listener) { + // if no listeners are found, call the next conversation step $listeners[] = new Listener($handlerInfo[0], $this->container); } else { + // if listener is found, escape the conversation $this->conversationManager->deleteConversationCache($chatId); } } else { + // if the coversation is forcing only the conversation handlers, + // skip the other listeners $listeners[] = new Listener($handlerInfo[0], $this->container); } - $deferred->resolve($listeners); })->otherwise(function ($e) use ($deferred) { // if something goes wrong, reject the promise @@ -107,22 +99,25 @@ public function resolveListeners(Update $update): PromiseInterface /** * @param Listener[] $listeners * @param string $listenerType - * @param string $listenerId + * @param string|null $listenerId + * @param bool $skipFallback * @return Listener|null */ - private function findListenerAndPush(array &$listeners, string $listenerType, string $listenerId): ?Listener + private function findListenerAndPush(array &$listeners, string $listenerType, ?string $listenerId = null, bool $skipFallback = false): ?Listener { - $typedListeners = $this->listeners[$listenerType] ?? []; - foreach ($typedListeners as $regex => $listener) { - if (preg_match($regex, $listenerId)) { - $listeners[] = $listener; - return $listener; + if ($listenerId !== null) { + $typedListeners = $this->listeners[$listenerType] ?? []; + foreach ($typedListeners as $regex => $listener) { + if (preg_match($regex, $listenerId)) { + $listeners[] = $listener; + return $listener; + } } } - if ($this->fallbackListener !== null) { - $listeners[] = $this->fallbackListener; - return $this->fallbackListener; + if (isset($this->listeners['fallback']) && !$skipFallback) { + $listeners[] = $this->listeners['fallback']; + return $this->listeners['fallback']; } return null; diff --git a/tests/Listener/CallbackQueryTest.php b/tests/Listener/CallbackQueryTest.php index 725002e..cd47aca 100644 --- a/tests/Listener/CallbackQueryTest.php +++ b/tests/Listener/CallbackQueryTest.php @@ -99,9 +99,9 @@ public function testCbQueryByInlineQuery() $this->assertSame('BAAAAHbYAAA4skAJl8HevRCfRb8', $cbQuery->getInlineMessageId()); $this->assertSame('777777777777777777', $cbQuery->getChatInstance()); $this->assertSame('ok', $cbQuery->getData()); + $this->assertTrue($ctx->isCallbackQuery()); }); $bot->run(); } - } diff --git a/tests/Middleware/MiddlewareTest.php b/tests/Middleware/MiddlewareTest.php index f938ab0..9d5ee59 100644 --- a/tests/Middleware/MiddlewareTest.php +++ b/tests/Middleware/MiddlewareTest.php @@ -44,4 +44,23 @@ public function testMiddleware() $bot->run(); } + public function testMiddlewareOnFallback() + { + $config = new Config(); + $config->setUpdateMode(Config::WEBHOOK_MODE); + $config->setUpdateStream(__DIR__ . '/../update_types/command.json'); + $bot = new Zanzara("test", $config); + + $bot->middleware(function (Context $ctx, $next) { + $ctx->set('exec', true); + $next($ctx); + }); + + $bot->fallback(function (Context $ctx) { + $this->assertNotNull($ctx->get('exec')); + }); + + $bot->run(); + } + }