1 | <?php |
||||
2 | |||||
3 | /** |
||||
4 | * This file is part of the TelegramBot package. |
||||
5 | * |
||||
6 | * (c) Avtandil Kikabidze aka LONGMAN <[email protected]> |
||||
7 | * |
||||
8 | * For the full copyright and license information, please view the LICENSE |
||||
9 | * file that was distributed with this source code. |
||||
10 | */ |
||||
11 | |||||
12 | namespace Longman\TelegramBot\Entities; |
||||
13 | |||||
14 | use Longman\TelegramBot\Entities\InlineQuery\InlineEntity; |
||||
15 | use Longman\TelegramBot\Entities\InputMedia\InputMedia; |
||||
16 | |||||
17 | /** |
||||
18 | * Class Entity |
||||
19 | * |
||||
20 | * This is the base class for all entities. |
||||
21 | * |
||||
22 | * @link https://core.telegram.org/bots/api#available-types |
||||
23 | * |
||||
24 | * @method array getRawData() Get the raw data passed to this entity |
||||
25 | * @method string getBotUsername() Return the bot name passed to this entity |
||||
26 | */ |
||||
27 | abstract class Entity implements \JsonSerializable |
||||
28 | { |
||||
29 | public static $fixThumbnailRename = true; |
||||
30 | |||||
31 | public $bot_username = ''; |
||||
32 | public $raw_data = []; |
||||
33 | |||||
34 | private $fields = []; |
||||
35 | |||||
36 | /** |
||||
37 | * Entity constructor. |
||||
38 | * |
||||
39 | * @todo Get rid of the $bot_username, it shouldn't be here! |
||||
40 | * |
||||
41 | * @param array $data |
||||
42 | * @param string $bot_username |
||||
43 | */ |
||||
44 | 76 | public function __construct(array $data, string $bot_username = '') |
|||
45 | { |
||||
46 | 76 | $this->bot_username = $bot_username; |
|||
47 | 76 | $this->raw_data = $data; |
|||
48 | |||||
49 | 76 | $this->assignMemberVariables($data); |
|||
50 | 76 | $this->validate(); |
|||
51 | } |
||||
52 | |||||
53 | /** |
||||
54 | * Dynamically set a field. |
||||
55 | * |
||||
56 | * @param string $name |
||||
57 | * @param mixed $value |
||||
58 | * @return void |
||||
59 | */ |
||||
60 | 74 | public function __set(string $name, $value): void |
|||
61 | { |
||||
62 | 74 | $this->fields[$name] = $value; |
|||
63 | } |
||||
64 | |||||
65 | /** |
||||
66 | * Gets a dynamic field. |
||||
67 | * |
||||
68 | * @param string $name |
||||
69 | * @return mixed|null |
||||
70 | */ |
||||
71 | 67 | public function __get(string $name) |
|||
72 | { |
||||
73 | 67 | return $this->fields[$name] ?? null; |
|||
74 | } |
||||
75 | |||||
76 | /** |
||||
77 | * Return the data that should be serialized for Telegram. |
||||
78 | * |
||||
79 | * @return array |
||||
80 | */ |
||||
81 | 2 | public function jsonSerialize(): array |
|||
82 | { |
||||
83 | 2 | return $this->fields; |
|||
84 | } |
||||
85 | |||||
86 | /** |
||||
87 | * Perform to json |
||||
88 | * |
||||
89 | * @return string |
||||
90 | */ |
||||
91 | 2 | public function toJson(): string |
|||
92 | { |
||||
93 | 2 | return json_encode($this); |
|||
94 | } |
||||
95 | |||||
96 | /** |
||||
97 | * Perform to string |
||||
98 | * |
||||
99 | * @return string |
||||
100 | */ |
||||
101 | public function __toString() |
||||
102 | { |
||||
103 | return $this->toJson(); |
||||
104 | } |
||||
105 | |||||
106 | /** |
||||
107 | * Helper to set member variables |
||||
108 | * |
||||
109 | * @param array $data |
||||
110 | */ |
||||
111 | 76 | protected function assignMemberVariables(array $data): void |
|||
112 | { |
||||
113 | 76 | foreach ($data as $key => $value) { |
|||
114 | 73 | $key = $this->fixThumbnailRename($key); |
|||
115 | 73 | $this->$key = $value; |
|||
116 | } |
||||
117 | } |
||||
118 | |||||
119 | /** |
||||
120 | * Get the list of the properties that are themselves Entities |
||||
121 | * |
||||
122 | * @return array |
||||
123 | */ |
||||
124 | 34 | protected function subEntities(): array |
|||
125 | { |
||||
126 | 34 | return []; |
|||
127 | } |
||||
128 | |||||
129 | /** |
||||
130 | * Perform any special entity validation |
||||
131 | */ |
||||
132 | 70 | protected function validate(): void |
|||
133 | { |
||||
134 | 70 | } |
|||
135 | |||||
136 | /** |
||||
137 | * Get a property from the current Entity |
||||
138 | * |
||||
139 | * @param string $property |
||||
140 | * @param mixed $default |
||||
141 | * |
||||
142 | * @return mixed |
||||
143 | */ |
||||
144 | 65 | public function getProperty(string $property, $default = null) |
|||
145 | { |
||||
146 | 65 | return $this->$property ?? $default; |
|||
147 | } |
||||
148 | |||||
149 | /** |
||||
150 | * Return the variable for the called getter or magically set properties dynamically. |
||||
151 | * |
||||
152 | * @param $method |
||||
153 | * @param $args |
||||
154 | * |
||||
155 | * @return mixed|null |
||||
156 | */ |
||||
157 | 57 | public function __call($method, $args) |
|||
158 | { |
||||
159 | 57 | $method = $this->fixThumbnailRename($method); |
|||
160 | |||||
161 | //Convert method to snake_case (which is the name of the property) |
||||
162 | 57 | $property_name = mb_strtolower(ltrim(preg_replace('/[A-Z]/', '_$0', substr($method, 3)), '_')); |
|||
163 | 57 | $property_name = $this->fixThumbnailRename($property_name); |
|||
164 | |||||
165 | 57 | $action = substr($method, 0, 3); |
|||
166 | 57 | if ($action === 'get') { |
|||
167 | 56 | $property = $this->getProperty($property_name); |
|||
168 | |||||
169 | 56 | if ($property !== null) { |
|||
170 | //Get all sub-Entities of the current Entity |
||||
171 | 53 | $sub_entities = $this->subEntities(); |
|||
172 | |||||
173 | 53 | if (isset($sub_entities[$property_name])) { |
|||
174 | 13 | $class = $sub_entities[$property_name]; |
|||
175 | |||||
176 | 13 | if (is_array($class)) { |
|||
177 | 1 | return $this->makePrettyObjectArray(reset($class), $property_name); |
|||
178 | } |
||||
179 | |||||
180 | 12 | return Factory::resolveEntityClass($class, $property, $this->getProperty('bot_username')); |
|||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
181 | } |
||||
182 | |||||
183 | 54 | return $property; |
|||
184 | } |
||||
185 | 2 | } elseif ($action === 'set') { |
|||
186 | // Limit setters to specific classes. |
||||
187 | 2 | if ($this instanceof InlineEntity || $this instanceof InputMedia || $this instanceof Keyboard || $this instanceof KeyboardButton) { |
|||
188 | 2 | $this->$property_name = $args[0]; |
|||
189 | 2 | $this->raw_data[$property_name] = $args[0]; |
|||
190 | |||||
191 | 2 | return $this; |
|||
192 | } |
||||
193 | } |
||||
194 | |||||
195 | 19 | return null; |
|||
196 | } |
||||
197 | |||||
198 | /** |
||||
199 | * BC for renamed thumb -> thumbnail methods and fields |
||||
200 | * |
||||
201 | * @todo Remove after a few versions. |
||||
202 | * |
||||
203 | * @param string $name |
||||
204 | * @return string |
||||
205 | */ |
||||
206 | 73 | protected function fixThumbnailRename(string $name): string |
|||
207 | { |
||||
208 | 73 | return self::$fixThumbnailRename ? preg_replace('/([Tt])humb(nail)?/', '$1humbnail', $name, -1, $count) : $name; |
|||
209 | |||||
210 | /*if ($count) { |
||||
211 | // Notify user that there are still outdated method calls? |
||||
212 | }*/ |
||||
213 | } |
||||
214 | |||||
215 | /** |
||||
216 | * Return an array of nice objects from an array of object arrays |
||||
217 | * |
||||
218 | * This method is used to generate pretty object arrays |
||||
219 | * mainly for PhotoSize and Entities object arrays. |
||||
220 | * |
||||
221 | * @param string $class |
||||
222 | * @param string $property_name |
||||
223 | * |
||||
224 | * @return array |
||||
225 | */ |
||||
226 | 1 | protected function makePrettyObjectArray(string $class, string $property_name): array |
|||
227 | { |
||||
228 | 1 | $objects = []; |
|||
229 | 1 | $bot_username = $this->getProperty('bot_username'); |
|||
230 | |||||
231 | 1 | $properties = array_filter($this->getProperty($property_name) ?: []); |
|||
232 | 1 | foreach ($properties as $property) { |
|||
233 | 1 | $objects[] = Factory::resolveEntityClass($class, $property, $bot_username); |
|||
0 ignored issues
–
show
It seems like
$bot_username can also be of type null ; however, parameter $bot_username of Longman\TelegramBot\Enti...y::resolveEntityClass() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
234 | } |
||||
235 | |||||
236 | 1 | return $objects; |
|||
237 | } |
||||
238 | |||||
239 | /** |
||||
240 | * Escape markdown (v1) special characters |
||||
241 | * |
||||
242 | * @see https://core.telegram.org/bots/api#markdown-style |
||||
243 | * |
||||
244 | * @param string $string |
||||
245 | * |
||||
246 | * @return string |
||||
247 | */ |
||||
248 | 2 | public static function escapeMarkdown(string $string): string |
|||
249 | { |
||||
250 | 2 | return str_replace( |
|||
251 | 2 | ['[', '`', '*', '_',], |
|||
252 | 2 | ['\[', '\`', '\*', '\_',], |
|||
253 | 2 | $string |
|||
254 | 2 | ); |
|||
255 | } |
||||
256 | |||||
257 | /** |
||||
258 | * Escape markdown (v2) special characters |
||||
259 | * |
||||
260 | * @see https://core.telegram.org/bots/api#markdownv2-style |
||||
261 | * |
||||
262 | * @param string $string |
||||
263 | * |
||||
264 | * @return string |
||||
265 | */ |
||||
266 | 1 | public static function escapeMarkdownV2(string $string): string |
|||
267 | { |
||||
268 | 1 | return str_replace( |
|||
269 | 1 | ['_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!'], |
|||
270 | 1 | ['\_', '\*', '\[', '\]', '\(', '\)', '\~', '\`', '\>', '\#', '\+', '\-', '\=', '\|', '\{', '\}', '\.', '\!'], |
|||
271 | 1 | $string |
|||
272 | 1 | ); |
|||
273 | } |
||||
274 | |||||
275 | /** |
||||
276 | * Try to mention the user |
||||
277 | * |
||||
278 | * Mention the user with the username otherwise print first and last name |
||||
279 | * if the $escape_markdown argument is true special characters are escaped from the output |
||||
280 | * |
||||
281 | * @todo What about MarkdownV2? |
||||
282 | * |
||||
283 | * @param bool $escape_markdown |
||||
284 | * |
||||
285 | * @return string |
||||
286 | */ |
||||
287 | 3 | public function tryMention($escape_markdown = false): string |
|||
288 | { |
||||
289 | // TryMention only makes sense for the User and Chat entity. |
||||
290 | 3 | if (!($this instanceof User || $this instanceof Chat)) { |
|||
291 | return ''; |
||||
292 | } |
||||
293 | |||||
294 | //Try with the username first... |
||||
295 | 3 | $name = $this->getProperty('username'); |
|||
296 | 3 | $is_username = $name !== null; |
|||
297 | |||||
298 | 3 | if ($name === null) { |
|||
299 | //...otherwise try with the names. |
||||
300 | 3 | $name = $this->getProperty('first_name'); |
|||
301 | 3 | $last_name = $this->getProperty('last_name'); |
|||
302 | 3 | if ($last_name !== null) { |
|||
303 | 3 | $name .= ' ' . $last_name; |
|||
304 | } |
||||
305 | } |
||||
306 | |||||
307 | 3 | if ($escape_markdown) { |
|||
308 | 1 | $name = self::escapeMarkdown($name); |
|||
309 | } |
||||
310 | |||||
311 | 3 | return ($is_username ? '@' : '') . $name; |
|||
312 | } |
||||
313 | } |
||||
314 |