Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emit UpdateEvent event similar to SDK v4 #998

Merged
merged 8 commits into from
Aug 20, 2022
37 changes: 37 additions & 0 deletions src/Events/UpdateEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace Telegram\Bot\Events;

use League\Event\AbstractEvent;
use Telegram\Bot\Api;
use Telegram\Bot\Objects\Update;

final class UpdateEvent extends AbstractEvent
{
public const NAME = 'update';

/**
* @deprecated Will be removed in SDK v4
* @var string
*/
private $name;

/** @var \Telegram\Bot\Api */
public $telegram;

/** @var \Telegram\Bot\Objects\Update */
public $update;

public function __construct(Api $telegram, Update $update, string $name = self::NAME)
{
$this->telegram = $telegram;
$this->update = $update;
$this->name = $name;
}

/** @inheritDoc */
public function getName(): string
{
return $this->name;
}
}
25 changes: 25 additions & 0 deletions src/Methods/Update.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace Telegram\Bot\Methods;

use League\Event\EmitterInterface;
use Psr\Http\Message\RequestInterface;
use Telegram\Bot\Events\UpdateEvent;
use Telegram\Bot\Events\UpdateWasReceived;
use Telegram\Bot\Exceptions\TelegramSDKException;
use Telegram\Bot\FileUpload\InputFile;
Expand Down Expand Up @@ -56,6 +58,7 @@ public function getUpdates(array $params = [], $shouldEmitEvents = true): array
if ($shouldEmitEvents) {
$this->emitEvent(new UpdateWasReceived($update, $this));
}
$this->dispatchUpdateEvent($update);

return $update;
})
Expand Down Expand Up @@ -165,6 +168,7 @@ public function getWebhookUpdate($shouldEmitEvent = true, ?RequestInterface $req
if ($shouldEmitEvent) {
$this->emitEvent(new UpdateWasReceived($update, $this));
}
$this->dispatchUpdateEvent($update);

return $update;
}
Expand Down Expand Up @@ -220,4 +224,25 @@ private function getRequestBody(?RequestInterface $request)

return json_decode($rawBody, true);
}

/** Dispatch Update Event. */
private function dispatchUpdateEvent(UpdateObject $update): void
{
if (! property_exists($this, 'eventEmitter') || ! $this->eventEmitter instanceof EmitterInterface) {
return;
}

$eventEmitter = $this->eventEmitter;

$eventEmitter->emit(new UpdateEvent($this, $update));
$updateType = $update->objectType();
if (is_string($updateType)) {
$eventEmitter->emit(new UpdateEvent($this, $update, $updateType));

$messageType = $update->getMessage()->objectType();
if (null !== $messageType) {
$eventEmitter->emit(new UpdateEvent($this, $update, "$updateType.$messageType"));
}
}
}
}
51 changes: 50 additions & 1 deletion tests/Integration/TelegramApiTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@

use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Stream;
use League\Event\AbstractListener;
use League\Event\Emitter;
use League\Event\EventInterface;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Telegram\Bot\Api;
use Telegram\Bot\Commands\CommandBus;
use Telegram\Bot\Events\UpdateEvent;
use Telegram\Bot\Events\UpdateWasReceived;
use Telegram\Bot\Exceptions\CouldNotUploadInputFile;
use Telegram\Bot\Exceptions\TelegramResponseException;
Expand Down Expand Up @@ -46,6 +49,12 @@ protected function getApi($client = null, $token = 'TELEGRAM_TOKEN', $async = fa
return new Api($token, $async, $client);
}

/** Create Request to emulate income Request from Telegram. */
private function createIncomeWebhookRequestInstance(array $updateData): Request
{
return new Request('POST', 'any', [], json_encode($updateData, \JSON_THROW_ON_ERROR));
}

/**
* @test
*/
Expand Down Expand Up @@ -543,7 +552,34 @@ public function check_the_webhook_works_and_can_emmit_an_event()
//We can't pass test data to the webhook because it relies on the read only stream php://input
$this->assertEmpty($update);
$this->assertInstanceOf(Update::class, $update);
$emitter->emit(Argument::type(UpdateWasReceived::class))->shouldHaveBeenCalled();
$emitter->emit(Argument::type(UpdateWasReceived::class))->shouldHaveBeenCalledOnce();
}

/** @test */
public function it_emits_3_events_of_update_event_type()
{
$emitter = new Emitter();
$listener = $this->createSpyListener();
$emitter->addListener('*', $listener);

$api = $this->getApi();
$api->setEventEmitter($emitter);

$incomeWebhookRequest = $this->createIncomeWebhookRequestInstance([
'message' => [ // to help SDK to detect Update of "message" type and send 2nd event (with name "message")
'text' => 'any', // to help SDK to detect message type and send 3rd event (with name "message.text")
],
]);

$api->getWebhookUpdate(true, $incomeWebhookRequest);
$allEvents = $listener->events;

$this->assertArrayHasKey(UpdateEvent::NAME, $allEvents);
$this->assertArrayHasKey('message', $allEvents);
$this->assertArrayHasKey('message.text', $allEvents);
$this->assertCount(1, $allEvents[UpdateEvent::NAME]);
$this->assertCount(1, $allEvents['message']);
$this->assertCount(1, $allEvents['message.text']);
alies-dev marked this conversation as resolved.
Show resolved Hide resolved
}

/** @test */
Expand Down Expand Up @@ -621,4 +657,17 @@ private function streamFor($resource)

throw new \RuntimeException('Not found "streamFor" implementation');
}

private function createSpyListener(): \League\Event\ListenerInterface
{
return new class extends AbstractListener {
/** @var array<string, list<\League\Event\EventInterface>> */
public $events = [];

public function handle(EventInterface $event)
{
$this->events[$event->getName()][] = $event;
}
};
}
}