Keyboard   A
last analyzed

Complexity

Total Complexity 31

Size/Duplication

Total Lines 197
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 31
c 0
b 0
f 0
lcom 1
cbo 3
dl 0
loc 197
ccs 62
cts 62
cp 1
rs 9.8

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A isInlineKeyboard() 0 4 1
A getKeyboardButtonClass() 0 4 2
A getKeyboardType() 0 4 2
C createFromParams() 0 37 8
A addRow() 0 8 2
A parseRow() 0 15 4
A parseButton() 0 14 4
B validate() 0 17 5
A forceReply() 0 4 1
A remove() 0 4 1
1
<?php
2
/**
3
 * This file is part of the TelegramBot package.
4
 *
5
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * Written by Marco Boretto <[email protected]>
11
 */
12
13
namespace Longman\TelegramBot\Entities;
14
15
use Longman\TelegramBot\Exception\TelegramException;
16
17
/**
18
 * Class Keyboard
19
 *
20
 * @link https://core.telegram.org/bots/api#replykeyboardmarkup
21
 *
22
 * @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.
23
 * @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.
24
 * @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.
25
 *
26
 * @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.
27
 * @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.
28
 * @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.
29
 */
30
class Keyboard extends Entity
31
{
32
    /**
33
     * {@inheritdoc}
34
     */
35 18
    public function __construct($data = [])
36
    {
37 18
        $data = call_user_func_array([$this, 'createFromParams'], func_get_args());
38 18
        parent::__construct($data);
39
40
        // Remove any empty buttons.
41 14
        $this->{$this->getKeyboardType()} = array_filter($this->{$this->getKeyboardType()});
42 14
    }
43
44
    /**
45
     * If this keyboard is an inline keyboard.
46
     *
47
     * @return bool
48
     */
49 18
    public function isInlineKeyboard()
50
    {
51 18
        return $this instanceof InlineKeyboard;
52
    }
53
54
    /**
55
     * Get the proper keyboard button class for this keyboard.
56
     *
57
     * @return KeyboardButton|InlineKeyboardButton
58
     */
59 12
    public function getKeyboardButtonClass()
60
    {
61 12
        return $this->isInlineKeyboard() ? InlineKeyboardButton::class : KeyboardButton::class;
62
    }
63
64
    /**
65
     * Get the type of keyboard, either "inline_keyboard" or "keyboard".
66
     *
67
     * @return string
68
     */
69 18
    public function getKeyboardType()
70
    {
71 18
        return $this->isInlineKeyboard() ? 'inline_keyboard' : 'keyboard';
72
    }
73
74
    /**
75
     * If no explicit keyboard is passed, try to create one from the parameters.
76
     *
77
     * @return array
78
     */
79 18
    protected function createFromParams()
80
    {
81 18
        $keyboard_type = $this->getKeyboardType();
82
83 18
        $args = func_get_args();
84
85
        // Force button parameters into individual rows.
86 18
        foreach ($args as &$arg) {
87 18
            !is_array($arg) && $arg = [$arg];
88
        }
89 18
        unset($arg);
90
91 18
        $data = reset($args);
92
93 18
        if ($from_data = array_key_exists($keyboard_type, (array) $data)) {
94 6
            $args = $data[$keyboard_type];
95
96
            // Make sure we're working with a proper row.
97 6
            if (!is_array($args)) {
98 2
                $args = [];
99
            }
100
        }
101
102 18
        $new_keyboard = [];
103 18
        foreach ($args as $row) {
104 15
            $new_keyboard[] = $this->parseRow($row);
105
        }
106
107 18
        if (!empty($new_keyboard)) {
108 15
            if (!$from_data) {
109 12
                $data = [];
110
            }
111 15
            $data[$keyboard_type] = $new_keyboard;
112
        }
113
114 18
        return $data;
115
    }
116
117
    /**
118
     * Create a new row in keyboard and add buttons.
119
     *
120
     * @return $this
121
     */
122 2
    public function addRow()
123
    {
124 2
        if (($new_row = $this->parseRow(func_get_args())) !== null) {
125 2
            $this->{$this->getKeyboardType()}[] = $new_row;
126
        }
127
128 2
        return $this;
129
    }
130
131
    /**
132
     * Parse a given row to the correct array format.
133
     *
134
     * @param array $row
135
     *
136
     * @return array
137
     */
138 15
    protected function parseRow($row)
139
    {
140 15
        if (!is_array($row)) {
141 2
            return null;
142
        }
143
144 13
        $new_row = [];
145 13
        foreach ($row as $button) {
146 12
            if (($new_button = $this->parseButton($button)) !== null) {
147 12
                $new_row[] = $new_button;
148
            }
149
        }
150
151 13
        return $new_row;
152
    }
153
154
    /**
155
     * Parse a given button to the correct KeyboardButton object type.
156
     *
157
     * @param array|string|\Longman\TelegramBot\Entities\KeyboardButton $button
158
     *
159
     * @return \Longman\TelegramBot\Entities\KeyboardButton|null
160
     */
161 12
    protected function parseButton($button)
162
    {
163 12
        $button_class = $this->getKeyboardButtonClass();
164
165 12
        if ($button instanceof $button_class) {
166 6
            return $button;
167
        }
168
169 6
        if (!$this->isInlineKeyboard() || $button_class::couldBe($button)) {
170 6
            return new $button_class($button);
171
        }
172
173
        return null;
174
    }
175
176
    /**
177
     * {@inheritdoc}
178
     */
179 18
    protected function validate()
180
    {
181 18
        $keyboard_type = $this->getKeyboardType();
182 18
        $keyboard = $this->getProperty($keyboard_type);
183
184 18
        if ($keyboard !== null) {
185 18
            if (!is_array($keyboard)) {
186 2
                throw new TelegramException($keyboard_type . ' field is not an array!');
187
            }
188
189 16
            foreach ($keyboard as $item) {
190 15
                if (!is_array($item)) {
191 15
                    throw new TelegramException($keyboard_type . ' subfield is not an array!');
192
                }
193
            }
194
        }
195 14
    }
196
197
    /**
198
     * Remove the current custom keyboard and display the default letter-keyboard.
199
     *
200
     * @link https://core.telegram.org/bots/api/#replykeyboardremove
201
     *
202
     * @param array $data
203
     *
204
     * @return \Longman\TelegramBot\Entities\Keyboard
205
     * @throws \Longman\TelegramBot\Exception\TelegramException
206
     */
207 1
    public static function remove(array $data = [])
208
    {
209 1
        return new static(array_merge(['keyboard' => [], 'remove_keyboard' => true, 'selective' => false], $data));
210
    }
211
212
    /**
213
     * Display a reply interface to the user (act as if the user has selected the bot's message and tapped 'Reply').
214
     *
215
     * @link https://core.telegram.org/bots/api#forcereply
216
     *
217
     * @param array $data
218
     *
219
     * @return \Longman\TelegramBot\Entities\Keyboard
220
     * @throws \Longman\TelegramBot\Exception\TelegramException
221
     */
222 1
    public static function forceReply(array $data = [])
223
    {
224 1
        return new static(array_merge(['keyboard' => [], 'force_reply' => true, 'selective' => false], $data));
225
    }
226
}
227