Skip to content

Upgrading from v2 to v3

Camilo Sperberg edited this page Aug 2, 2017 · 7 revisions

v3 is a major change in direction for this API.

Breaking changes

Change of order in parameters within constructor

The TgLog class did change the order it receives the parameters. It used to be "Bot token" - "Logger" - "Request handler", and now it is "Bot token" - "Request handler" - "Logger".

Request Handlers

New in this release are so-called Request Handlers. A Request Handler is, simply said, a class that handles the talking to Telegram.

It is now required to pass a Request Handler to the TgLog object when constructing it:

<?php

// Old style:
$tgLog = new \unreal4u\TelegramAPI\TgLog(BOT_TOKEN);

// New style:
$loop = \React\EventLoop\Factory::create();
$handler = new \unreal4u\TelegramAPI\HttpClientRequestHandler($loop);
$tgLog = new \unreal4u\TelegramAPI\TgLog(BOT_TOKEN, $handler);

The added benefit of this structure is that it will be possible to swap out a backend for another backend. For example, the new non-blocking React\HttpClient backend may be swapped out for a blocking backend, powered by a different client, such as the old Guzzle client.

Asynchronous (async) working style

Version 3 of the API will work in an async manner, meaning that a request will not block other work going on. While PHP is not async by design, it can be emulated by doing parts of the work on every tick. It uses ReactPHP components like its event loop and HttpClient to achieve this.

While at first a simple call to TgLog::performApiRequest was sufficient to get the appropriate Telegram reply object, it will now return a React\Promise\PromiseInterface (more on promises here), which you can pass a pair of callbacks (onFulfilled and onRejected respectively). Consider the following code for an example (note that this code will NOT execute):

<?php

declare(strict_types = 1);

use unreal4u\TelegramAPI\InternalFunctionality\TelegramDocument;
use unreal4u\TelegramAPI\Telegram\Methods\GetFile;
use unreal4u\TelegramAPI\Telegram\Types\File;
use unreal4u\TelegramAPI\TgLog;

// ----- CHANGE THIS CODE: -----
$tgLog = new TgLog(BOT_TOKEN);

// ----- TO THIS: -----
$loop = \React\EventLoop\Factory::create();
$handler = new \unreal4u\TelegramAPI\HttpClientRequestHandler($loop);
$tgLog = new TgLog(BOT_TOKEN, $handler);

$getFile = new GetFile();
$getFile->file_id = A_FILE_ID;

// ----- THE FOLLOWING WILL NO LONGER WORK: -----
/** @var File $file */
/** @var TelegramDocument $document */
$file = $tgLog->performApiRequest($getFile);
$document = $tgLog->downloadFile($file);

// ----- INSTEAD, TO MAKE IT ASYNC, USE: -----
$filePromise = $tgLog->performApiRequest($getFile);
$filePromise->then(
    function (File $file) use ($tgLog) {
        $documentPromise = $tgLog->downloadFile($file);
        
        $documentPromise->then(function (TelegramDocument $document) {
            echo '<pre>';
            var_dump($document);
            echo '</pre>';
        });
    }
);

$loop->run();

However, any code where you do not process the reply passed back by performApiRequest will still work, e.g.:

$tgLog->performApiRequest(new GetMe());

Given that you provide enough time for the request to end before your script ends.

Custom -Array types now implement IteratorAggregate

Array types (like UpdatesArray) now implement the IteratorAggregate interface. This means that they expose a getIterator() method, which can be used to get an object you can iterate over and interact with.

This replaces the old traverseObject() method, which would yield all individual array elements.

Better exceptions

Instead of an exception with a generic \stdClass() object, every unsuccessful request at Telegram will now throw a ClientException, which will contain more information about the specific error that is being thrown.

Under-the-hood changes

Replaced Guzzle with React\HttpClient

Guzzle does not fit well in an async nature. While it appears to have methods for async requests, this functionality is still blocking. Therefore it was deemed a better choice to use the React\HttpClient backend instead, which is async by design.