-
-
Notifications
You must be signed in to change notification settings - Fork 959
Expand file tree
/
Copy pathKeyboard.php
More file actions
231 lines (200 loc) · 8.47 KB
/
Copy pathKeyboard.php
File metadata and controls
231 lines (200 loc) · 8.47 KB
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
<?php
/**
* This file is part of the TelegramBot package.
*
* (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* Written by Marco Boretto <marco.bore@gmail.com>
*/
namespace Longman\TelegramBot\Entities;
use Longman\TelegramBot\Exception\TelegramException;
/**
* Class Keyboard
*
* @link https://core.telegram.org/bots/api#replykeyboardmarkup
*
* @method bool getIsPersistent() Optional. Requests clients to always show the keyboard when the regular keyboard is hidden. Defaults to false, in which case the custom keyboard can be hidden and opened with a keyboard icon.
* @method bool getResizeKeyboard() Optional. Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller if there are just two rows of buttons). Defaults to false, in which case the custom keyboard is always of the same height as the app's standard keyboard.
* @method bool getOneTimeKeyboard() Optional. Requests clients to remove the keyboard as soon as it's been used. The keyboard will still be available, but clients will automatically display the usual letter-keyboard in the chat – the user can press a special button in the input field to see the custom keyboard again. Defaults to false.
* @method string getInputFieldPlaceholder() Optional. The placeholder to be shown in the input field when the keyboard is active; 1-64 characters
* @method bool getSelective() Optional. Use this parameter if you want to show the keyboard to specific users only. Targets: 1) users that are @mentioned in the text of the Message object; 2) if the bot's message is a reply (has reply_to_message_id), sender of the original message.
*
* @method $this setIsPersistent(bool $is_persistent) Optional. Requests clients to always show the keyboard when the regular keyboard is hidden. Defaults to false, in which case the custom keyboard can be hidden and opened with a keyboard icon.
* @method $this setResizeKeyboard(bool $resize_keyboard) Optional. Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller if there are just two rows of buttons). Defaults to false, in which case the custom keyboard is always of the same height as the app's standard keyboard.
* @method $this setOneTimeKeyboard(bool $one_time_keyboard) Optional. Requests clients to remove the keyboard as soon as it's been used. The keyboard will still be available, but clients will automatically display the usual letter-keyboard in the chat – the user can press a special button in the input field to see the custom keyboard again. Defaults to false.
* @method $this setInputFieldPlaceholder(string $input_field_placeholder) Optional. The placeholder to be shown in the input field when the keyboard is active; 1-64 characters
* @method $this setSelective(bool $selective) Optional. Use this parameter if you want to show the keyboard to specific users only. Targets: 1) users that are @mentioned in the text of the Message object; 2) if the bot's message is a reply (has reply_to_message_id), sender of the original message.
*/
class Keyboard extends Entity
{
public function __construct()
{
$data = $this->createFromParams(...func_get_args());
parent::__construct($data);
// Remove any empty buttons.
$this->{$this->getKeyboardType()} = array_filter($this->{$this->getKeyboardType()});
}
/**
* If this keyboard is an inline keyboard.
*
* @return bool
*/
public function isInlineKeyboard(): bool
{
return $this instanceof InlineKeyboard;
}
/**
* Get the proper keyboard button class for this keyboard.
*
* @return string
*/
public function getKeyboardButtonClass(): string
{
return $this->isInlineKeyboard() ? InlineKeyboardButton::class : KeyboardButton::class;
}
/**
* Get the type of keyboard, either "inline_keyboard" or "keyboard".
*
* @return string
*/
public function getKeyboardType(): string
{
return $this->isInlineKeyboard() ? 'inline_keyboard' : 'keyboard';
}
/**
* If no explicit keyboard is passed, try to create one from the parameters.
*
* @return array
*/
protected function createFromParams(): array
{
$keyboard_type = $this->getKeyboardType();
$args = func_get_args();
// Force button parameters into individual rows.
foreach ($args as &$arg) {
!is_array($arg) && $arg = [$arg];
}
unset($arg);
$data = reset($args);
if ($from_data = array_key_exists($keyboard_type, (array) $data)) {
$args = $data[$keyboard_type];
// Make sure we're working with a proper row.
if (!is_array($args)) {
$args = [];
}
}
$new_keyboard = [];
foreach ($args as $row) {
$new_keyboard[] = $this->parseRow($row);
}
if (!empty($new_keyboard)) {
if (!$from_data) {
$data = [];
}
$data[$keyboard_type] = $new_keyboard;
}
// If $args was empty, $data still contains `false`
return $data ?: [];
}
/**
* Create a new row in keyboard and add buttons.
*
* @return Keyboard
*/
public function addRow(): Keyboard
{
if (($new_row = $this->parseRow(func_get_args())) !== null) {
// Workaround for "Indirect modification of overloaded property has no effect" notice in PHP 8.2.
// https://stackoverflow.com/a/19749730/3757422
$keyboard = $this->{$this->getKeyboardType()};
$keyboard[] = $new_row;
$this->{$this->getKeyboardType()} = $keyboard;
}
return $this;
}
/**
* Parse a given row to the correct array format.
*
* @param array|string $row
*
* @return array|null
*/
protected function parseRow($row): ?array
{
if (!is_array($row)) {
return null;
}
$new_row = [];
foreach ($row as $button) {
if (($new_button = $this->parseButton($button)) !== null) {
$new_row[] = $new_button;
}
}
return $new_row;
}
/**
* Parse a given button to the correct KeyboardButton object type.
*
* @param array|string|KeyboardButton $button
*
* @return KeyboardButton|null
*/
protected function parseButton($button): ?KeyboardButton
{
$button_class = $this->getKeyboardButtonClass();
if ($button instanceof $button_class) {
return $button;
}
if (!$this->isInlineKeyboard() || call_user_func([$button_class, 'couldBe'], $button)) {
return new $button_class($button);
}
return null;
}
/**
* {@inheritdoc}
*/
protected function validate(): void
{
$keyboard_type = $this->getKeyboardType();
$keyboard = $this->getProperty($keyboard_type);
if ($keyboard !== null) {
if (!is_array($keyboard)) {
throw new TelegramException($keyboard_type . ' field is not an array!');
}
foreach ($keyboard as $item) {
if (!is_array($item)) {
throw new TelegramException($keyboard_type . ' subfield is not an array!');
}
}
}
}
/**
* Remove the current custom keyboard and display the default letter-keyboard.
*
* @link https://core.telegram.org/bots/api/#replykeyboardremove
*
* @param array $data
*
* @return Keyboard
*/
public static function remove(array $data = []): Keyboard
{
return new static(array_merge(['keyboard' => [], 'remove_keyboard' => true, 'selective' => false], $data));
}
/**
* Display a reply interface to the user (act as if the user has selected the bot's message and tapped 'Reply').
*
* @link https://core.telegram.org/bots/api#forcereply
*
* @param array $data
*
* @return Keyboard
*/
public static function forceReply(array $data = []): Keyboard
{
return new static(array_merge(['keyboard' => [], 'force_reply' => true, 'selective' => false], $data));
}
}