Passed
Pull Request — develop (#1077)
by Marco
02:09
created

Keyboard::isInlineKeyboard()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
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
 * Written by Marco Boretto <[email protected]>
12
 */
13
14
namespace PhpTelegramBot\Core\Entities;
15
16
use PhpTelegramBot\Core\Exception\TelegramException;
17
18
/**
19
 * Class Keyboard
20
 *
21
 * @link https://core.telegram.org/bots/api#replykeyboardmarkup
22
 *
23
 * @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.
24
 * @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.
25
 * @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.
26
 *
27
 * @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.
28
 * @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.
29
 * @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.
30
 */
31
class Keyboard extends Entity
32
{
33
    /**
34
     * {@inheritdoc}
35
     */
36 18
    public function __construct($data = [])
37
    {
38 18
        $data = call_user_func_array([$this, 'createFromParams'], func_get_args());
39 18
        parent::__construct($data);
40
41
        // Remove any empty buttons.
42 14
        $this->{$this->getKeyboardType()} = array_filter($this->{$this->getKeyboardType()});
43 14
    }
44
45
    /**
46
     * If this keyboard is an inline keyboard.
47
     *
48
     * @return bool
49
     */
50 18
    public function isInlineKeyboard()
51
    {
52 18
        return $this instanceof InlineKeyboard;
53
    }
54
55
    /**
56
     * Get the proper keyboard button class for this keyboard.
57
     *
58
     * @return string
59
     */
60 12
    public function getKeyboardButtonClass()
61
    {
62 12
        return $this->isInlineKeyboard() ? InlineKeyboardButton::class : KeyboardButton::class;
63
    }
64
65
    /**
66
     * Get the type of keyboard, either "inline_keyboard" or "keyboard".
67
     *
68
     * @return string
69
     */
70 18
    public function getKeyboardType()
71
    {
72 18
        return $this->isInlineKeyboard() ? 'inline_keyboard' : 'keyboard';
73
    }
74
75
    /**
76
     * If no explicit keyboard is passed, try to create one from the parameters.
77
     *
78
     * @return array
79
     */
80 18
    protected function createFromParams()
81
    {
82 18
        $keyboard_type = $this->getKeyboardType();
83
84 18
        $args = func_get_args();
85
86
        // Force button parameters into individual rows.
87 18
        foreach ($args as &$arg) {
88 18
            !is_array($arg) && $arg = [$arg];
89
        }
90 18
        unset($arg);
91
92 18
        $data = reset($args);
93
94 18
        if ($from_data = array_key_exists($keyboard_type, (array) $data)) {
95 6
            $args = $data[$keyboard_type];
96
97
            // Make sure we're working with a proper row.
98 6
            if (!is_array($args)) {
99 2
                $args = [];
100
            }
101
        }
102
103 18
        $new_keyboard = [];
104 18
        foreach ($args as $row) {
105 15
            $new_keyboard[] = $this->parseRow($row);
106
        }
107
108 18
        if (!empty($new_keyboard)) {
109 15
            if (!$from_data) {
110 12
                $data = [];
111
            }
112 15
            $data[$keyboard_type] = $new_keyboard;
113
        }
114
115 18
        return $data;
116
    }
117
118
    /**
119
     * Create a new row in keyboard and add buttons.
120
     *
121
     * @return $this
122
     */
123 2
    public function addRow()
124
    {
125 2
        if (($new_row = $this->parseRow(func_get_args())) !== null) {
0 ignored issues
show
introduced by
The condition $new_row = $this->parseR...nc_get_args()) !== null is always true.
Loading history...
126 2
            $this->{$this->getKeyboardType()}[] = $new_row;
127
        }
128
129 2
        return $this;
130
    }
131
132
    /**
133
     * Parse a given row to the correct array format.
134
     *
135
     * @param array $row
136
     *
137
     * @return array
138
     */
139 15
    protected function parseRow($row)
140
    {
141 15
        if (!is_array($row)) {
0 ignored issues
show
introduced by
The condition is_array($row) is always true.
Loading history...
142 2
            return null;
143
        }
144
145 13
        $new_row = [];
146 13
        foreach ($row as $button) {
147 12
            if (($new_button = $this->parseButton($button)) !== null) {
148 12
                $new_row[] = $new_button;
149
            }
150
        }
151
152 13
        return $new_row;
153
    }
154
155
    /**
156
     * Parse a given button to the correct KeyboardButton object type.
157
     *
158
     * @param array|string|KeyboardButton $button
159
     *
160
     * @return KeyboardButton|null
161
     */
162 12
    protected function parseButton($button)
163
    {
164 12
        $button_class = $this->getKeyboardButtonClass();
165
166 12
        if ($button instanceof $button_class) {
167 6
            return $button;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $button also could return the type array|string which is incompatible with the documented return type PhpTelegramBot\Core\Entities\KeyboardButton|null.
Loading history...
168
        }
169
170 6
        if (!$this->isInlineKeyboard() || call_user_func([$button_class, 'couldBe'], $button)) {
171 6
            return new $button_class($button);
172
        }
173
174
        return null;
175
    }
176
177
    /**
178
     * {@inheritdoc}
179
     */
180 18
    protected function validate()
181
    {
182 18
        $keyboard_type = $this->getKeyboardType();
183 18
        $keyboard      = $this->getProperty($keyboard_type);
184
185 18
        if ($keyboard !== null) {
186 18
            if (!is_array($keyboard)) {
187 2
                throw new TelegramException($keyboard_type . ' field is not an array!');
188
            }
189
190 16
            foreach ($keyboard as $item) {
191 15
                if (!is_array($item)) {
192 2
                    throw new TelegramException($keyboard_type . ' subfield is not an array!');
193
                }
194
            }
195
        }
196 14
    }
197
198
    /**
199
     * Remove the current custom keyboard and display the default letter-keyboard.
200
     *
201
     * @link https://core.telegram.org/bots/api/#replykeyboardremove
202
     *
203
     * @param array $data
204
     *
205
     * @return Keyboard
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 Keyboard
220
     */
221 1
    public static function forceReply(array $data = [])
222
    {
223 1
        return new static(array_merge(['keyboard' => [], 'force_reply' => true, 'selective' => false], $data));
224
    }
225
}
226