-
Notifications
You must be signed in to change notification settings - Fork 172
/
TgLog.php
217 lines (188 loc) · 6.11 KB
/
TgLog.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
<?php
declare(strict_types = 1);
namespace unreal4u;
use \GuzzleHttp\Client;
use unreal4u\Abstracts\TelegramTypes;
use unreal4u\InternalFunctionality\TelegramDocument;
use unreal4u\Abstracts\TelegramMethods;
use unreal4u\Telegram\Types\File;
/**
* The main API which does it all
*/
class TgLog
{
/**
* Stores the token
* @var string
*/
private $botToken = '';
/**
* Stores the API URL from Telegram
* @var string
*/
private $apiUrl = '';
/**
* With this flag we'll know what type of request to send to Telegram
*
* 'application/x-www-form-urlencoded' is the "normal" one, which is simpler and quicker.
* 'multipart/form-data' should be used only to upload documents, photos, etc.
*
* @var string
*/
private $formType = 'application/x-www-form-urlencoded';
/**
* Stores the last method name used
* @var string
*/
protected $methodName = '';
/**
* TelegramLog constructor.
* @param string $botToken
*/
public function __construct(string $botToken)
{
$this->botToken = $botToken;
$this->constructApiUrl();
}
/**
* Prepares and sends an API request to Telegram
*
* @param mixed $method
* @return mixed
*/
public function performApiRequest(TelegramMethods $method): TelegramTypes
{
$this->resetObjectValues();
$jsonDecoded = $this->sendRequestToTelegram($method, $this->constructFormData($method));
$returnObject = 'unreal4u\\Telegram\\Types\\' . $method::bindToObjectType();
return new $returnObject($jsonDecoded['result']);
}
/**
* Will download a file from the Telegram server. Before calling this function, you have to call the getFile method!
*
* @see unreal4u\Telegram\Types\File
* @see unreal4u\Telegram\Methods\GetFile
*
* @param File $file
* @return TelegramDocument
*/
public function downloadFile(File $file): TelegramDocument
{
$url = $this->apiUrl . $file->file_path;
$client = new Client();
return new TelegramDocument($client->get($url));
}
/**
* Builds up the Telegram API url
* @return TgLog
*/
final private function constructApiUrl(): TgLog
{
$this->apiUrl = 'https://api.telegram.org/bot' . $this->botToken . '/';
return $this;
}
/**
* This is the method that actually makes the call, which can be easily overwritten so that our unit tests can work
*
* @param TelegramMethods $method
* @param array $formData
* @return array
*/
protected function sendRequestToTelegram(TelegramMethods $method, array $formData): array
{
$client = new Client();
$response = $client->post($this->composeApiMethodUrl($method), $formData);
return json_decode((string)$response->getBody(), true);
}
private function resetObjectValues(): TgLog
{
$this->formType = 'application/x-www-form-urlencoded';
$this->methodName = '';
return $this;
}
private function constructFormData(TelegramMethods $method): array
{
$result = $this->checkSpecialConditions($method);
switch ($this->formType) {
case 'application/x-www-form-urlencoded':
$formData = [
'form_params' => get_object_vars($method),
];
break;
case 'multipart/form-data':
$formData = $this->buildMultipartFormData(get_object_vars($method), $result['id'], $result['stream']);
break;
default:
$formData = [];
break;
}
return $formData;
}
/**
* Can perform any special checks needed to be performed before sending the actual request to Telegram
*
* This will return an array with data that will be different in each case (for now). This can be changed in the
* future.
*
* @param TelegramMethods $method
* @return array
*/
private function checkSpecialConditions(TelegramMethods $method): array
{
$method->performSpecialConditions();
$return = [false];
foreach ($method as $key => $value) {
if (is_object($value)) {
if (get_class($value) == 'unreal4u\\Telegram\\Types\\Custom\\InputFile') {
// If we are about to send a file, we must use the multipart/form-data way
$this->formType = 'multipart/form-data';
$return = [
'id' => $key,
'stream' => $value->getStream(),
];
}
}
}
return $return;
}
/**
* Builds up the URL with which we can work with
*
* @param TelegramMethods $call
* @return string
*/
protected function composeApiMethodUrl(TelegramMethods $call): string
{
$completeClassName = get_class($call);
$this->methodName = lcfirst(substr($completeClassName, strrpos($completeClassName, '\\') + 1));
return $this->apiUrl . $this->methodName;
}
/**
* Builds up a multipart form-like array for Guzzle
*
* @param array $data The original object in array form
* @param string $fileKeyName A file handler will be sent instead of a string, state here which field it is
* @param resource $stream The actual file handler
* @return array Returns the actual formdata to be sent
*/
private function buildMultipartFormData(array $data, string $fileKeyName, $stream): array
{
$formData = [
'multipart' => [],
];
foreach ($data as $id => $value) {
// Always send as a string unless it's a file
$multiPart = [
'name' => $id,
'contents' => null,
];
if ($id === $fileKeyName) {
$multiPart['contents'] = $stream;
} else {
$multiPart['contents'] = (string)$value;
}
$formData['multipart'][] = $multiPart;
}
return $formData;
}
}