• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vjik / telegram-bot-api / 13240978115

10 Feb 2025 12:35PM UTC coverage: 99.982% (-0.02%) from 100.0%
13240978115

Pull #143

github

web-flow
Merge 574b2eb54 into c5d0aeb26
Pull Request #143: Change `FailResult::$errorCode` type to `int|null`

2 of 3 new or added lines in 1 file covered. (66.67%)

5532 of 5533 relevant lines covered (99.98%)

27.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.73
/src/Api.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Vjik\TelegramBot\Api;
6

7
use JsonException;
8
use Psr\Log\LoggerInterface;
9
use Vjik\TelegramBot\Api\ParseResult\ResultFactory;
10
use Vjik\TelegramBot\Api\ParseResult\TelegramParseResultException;
11
use Vjik\TelegramBot\Api\Transport\ApiResponse;
12
use Vjik\TelegramBot\Api\Transport\TransportInterface;
13
use Vjik\TelegramBot\Api\Type\ResponseParameters;
14

15
use function array_key_exists;
16
use function is_array;
17
use function is_bool;
18
use function is_int;
19
use function is_string;
20
use function json_decode;
21

22
/**
23
 * @internal
24
 */
25
final readonly class Api
26
{
27
    private ResultFactory $resultFactory;
28

29
    public function __construct(
852✔
30
        private TransportInterface $transport,
31
    ) {
32
        $this->resultFactory = new ResultFactory();
852✔
33
    }
34

35
    /**
36
     * @see https://core.telegram.org/bots/api#making-requests
37
     *
38
     * @psalm-template TValue
39
     * @psalm-param MethodInterface<TValue> $method
40
     * @psalm-return TValue|FailResult
41
     */
42
    public function call(MethodInterface $method, ?LoggerInterface $logger): mixed
852✔
43
    {
44
        $logger?->info(
852✔
45
            'Send ' . $method->getHttpMethod()->value . '-request "' . $method->getApiMethod() . '".',
852✔
46
            LogContextFactory::sendRequest($method),
852✔
47
        );
852✔
48
        $response = $this->transport->send(
852✔
49
            $method->getApiMethod(),
852✔
50
            $method->getData(),
852✔
51
            $method->getHttpMethod(),
852✔
52
        );
852✔
53

54
        try {
55
            $decodedBody = json_decode($response->body, true, flags: JSON_THROW_ON_ERROR);
852✔
56
        } catch (JsonException $e) {
3✔
57
            $logger?->error(
3✔
58
                'Failed to decode JSON from telegram response.',
3✔
59
                LogContextFactory::parseResultError($response->body),
3✔
60
            );
3✔
61
            throw new TelegramParseResultException(
3✔
62
                'Failed to decode JSON response. Status code: ' . $response->statusCode . '.',
3✔
63
                previous: $e,
3✔
64
            );
3✔
65
        }
66

67
        if (!is_array($decodedBody)) {
849✔
68
            $logger?->error(
3✔
69
                'Incorrect telegram response.',
3✔
70
                LogContextFactory::parseResultError($response->body),
3✔
71
            );
3✔
72
            throw new TelegramParseResultException(
3✔
73
                'Expected telegram response as array. Got "' . get_debug_type($decodedBody) . '".',
3✔
74
            );
3✔
75
        }
76

77
        if (!isset($decodedBody['ok']) || !is_bool($decodedBody['ok'])) {
846✔
78
            $logger?->error(
6✔
79
                'Incorrect "ok" field in telegram response.',
6✔
80
                LogContextFactory::parseResultError($response->body),
6✔
81
            );
6✔
82
            throw new TelegramParseResultException(
6✔
83
                'Incorrect "ok" field in response. Status code: ' . $response->statusCode . '.',
6✔
84
            );
6✔
85
        }
86

87
        if ($decodedBody['ok']) {
840✔
88
            $result = $this->prepareSuccessResult($method, $response, $decodedBody, $logger);
831✔
89
            $logger?->info(
822✔
90
                'On "' . $method->getApiMethod() . '" request Telegram Bot API returned successful result.',
822✔
91
                LogContextFactory::successResult($method, $response, $decodedBody),
822✔
92
            );
822✔
93
        } else {
94
            $result = $this->prepareFailResult($method, $response, $decodedBody);
9✔
95
            $logger?->warning(
9✔
96
                'On "' . $method->getApiMethod() . '" request Telegram Bot API returned fail result.',
9✔
97
                LogContextFactory::failResult($method, $response, $decodedBody),
9✔
98
            );
9✔
99
        }
100

101
        return $result;
831✔
102
    }
103

104
    /**
105
     * @psalm-template TValue
106
     * @psalm-param MethodInterface<TValue> $method
107
     * @psalm-return TValue
108
     */
109
    private function prepareSuccessResult(
831✔
110
        MethodInterface $method,
111
        ApiResponse $response,
112
        array $decodedBody,
113
        ?LoggerInterface $logger,
114
    ): mixed {
115
        if (!array_key_exists('result', $decodedBody)) {
831✔
116
            $logger?->error(
3✔
117
                'Not found "result" field in telegram response.',
3✔
118
                LogContextFactory::parseResultError($response->body),
3✔
119
            );
3✔
120
            throw new TelegramParseResultException(
3✔
121
                'Not found "result" field in response. Status code: ' . $response->statusCode . '.',
3✔
122
            );
3✔
123
        }
124

125
        $resultType = $method->getResultType();
828✔
126

127
        try {
128
            return $this->resultFactory->create($decodedBody['result'], $resultType);
828✔
129
        } catch (TelegramParseResultException $exception) {
6✔
130
            $logger?->error(
6✔
131
                'Failed to parse telegram result. ' . $exception->getMessage(),
6✔
132
                LogContextFactory::parseResultError($response->body),
6✔
133
            );
6✔
134
            throw $exception;
6✔
135
        }
136
    }
137

138
    private function prepareFailResult(
9✔
139
        MethodInterface $method,
140
        ApiResponse $response,
141
        array $decodedBody,
142
    ): FailResult {
143
        return new FailResult(
9✔
144
            $method,
9✔
145
            $response,
9✔
146
            (isset($decodedBody['description']) && is_string($decodedBody['description']))
9✔
147
                ? $decodedBody['description']
6✔
148
                : null,
9✔
149
            ResponseParameters::fromDecodedBody($decodedBody),
9✔
150
            (isset($decodedBody['error_code']) && is_int($decodedBody['error_code']))
9✔
NEW
151
                ? $decodedBody['error_code']
×
152
                : null,
9✔
153
        );
9✔
154
    }
155
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc