Completed
Pull Request — develop (#291)
by Armando
15:42
created

Keyboard   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 196
Duplicated Lines 8.16 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 31
lcom 1
cbo 3
dl 16
loc 196
rs 9.8
c 0
b 0
f 0

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() 16 16 5
A hide() 0 4 1
A forceReply() 0 4 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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 hide 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 hide 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
    public function __construct($data = [])
36
    {
37
        $data = call_user_func_array([$this, 'createFromParams'], func_get_args());
38
        parent::__construct($data);
39
40
        // Remove any empty buttons.
41
        $this->{$this->getKeyboardType()} = array_filter($this->{$this->getKeyboardType()});
42
    }
43
44
    /**
45
     * If this keyboard is an inline keyboard.
46
     *
47
     * @return bool
48
     */
49
    public function isInlineKeyboard()
50
    {
51
        return $this instanceof InlineKeyboard;
52
    }
53
54
    /**
55
     * Get the proper keyboard button class for this keyboard.
56
     *
57
     * @return KeyboardButton|InlineKeyboardButton
58
     */
59
    public function getKeyboardButtonClass()
60
    {
61
        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
    public function getKeyboardType()
70
    {
71
        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
    protected function createFromParams()
80
    {
81
        $keyboard_type = $this->getKeyboardType();
82
83
        $args = func_get_args();
84
85
        // Force button parameters into individual rows.
86
        foreach ($args as &$arg) {
87
            !is_array($arg) && $arg = [$arg];
88
        }
89
        unset($arg);
90
91
        $data = reset($args);
92
93
        if ($from_data = array_key_exists($keyboard_type, (array)$data)) {
94
            $args = $data[$keyboard_type];
95
96
            // Make sure we're working with a proper row.
97
            if (!is_array($args)) {
98
                $args = [];
99
            }
100
        }
101
102
        $new_keyboard = [];
103
        foreach ($args as $row) {
104
            $new_keyboard[] = $this->parseRow($row);
105
        }
106
107
        if (!empty($new_keyboard)) {
108
            if (!$from_data) {
109
                $data = [];
110
            }
111
            $data[$keyboard_type] = $new_keyboard;
112
        }
113
114
        return $data;
115
    }
116
117
    /**
118
     * Create a new row in keyboard and add buttons.
119
     *
120
     * @return $this
121
     */
122
    public function addRow()
123
    {
124
        if (($new_row = $this->parseRow(func_get_args())) !== null) {
125
            $this->{$this->getKeyboardType()}[] = $new_row;
126
        }
127
128
        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
    protected function parseRow($row)
139
    {
140
        if (!is_array($row)) {
141
            return null;
142
        }
143
144
        $new_row = [];
145
        foreach ($row as $button) {
146
            if (($new_button = $this->parseButton($button)) !== null) {
147
                $new_row[] = $new_button;
148
            }
149
        }
150
151
        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
    protected function parseButton($button)
162
    {
163
        $button_class = $this->getKeyboardButtonClass();
164
165
        if ($button instanceof $button_class) {
166
            return $button;
167
        }
168
169
        if (!$this->isInlineKeyboard() || $button_class::couldBe($button)) {
170
            return new $button_class($button);
171
        }
172
173
        return null;
174
    }
175
176
    /**
177
     * {@inheritdoc}
178
     */
179 View Code Duplication
    protected function validate()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
180
    {
181
        $keyboard = $this->getProperty('keyboard');
182
183
        if ($keyboard !== null) {
184
            if (!is_array($keyboard)) {
185
                throw new TelegramException('Keyboard field is not an array!');
186
            }
187
188
            foreach ($keyboard as $item) {
189
                if (!is_array($item)) {
190
                    throw new TelegramException('Keyboard subfield is not an array!');
191
                }
192
            }
193
        }
194
    }
195
196
    /**
197
     * Hide the current custom keyboard and display the default letter-keyboard.
198
     *
199
     * @link https://core.telegram.org/bots/api#replykeyboardhide
200
     *
201
     * @param array $data
202
     *
203
     * @return \Longman\TelegramBot\Entities\Keyboard
204
     * @throws \Longman\TelegramBot\Exception\TelegramException
205
     */
206
    public static function hide(array $data = [])
207
    {
208
        return new static(array_merge(['keyboard' => [], 'hide_keyboard' => true, 'selective' => false], $data));
209
    }
210
211
    /**
212
     * Display a reply interface to the user (act as if the user has selected the bot's message and tapped 'Reply').
213
     *
214
     * @link https://core.telegram.org/bots/api#forcereply
215
     *
216
     * @param array $data
217
     *
218
     * @return \Longman\TelegramBot\Entities\Keyboard
219
     * @throws \Longman\TelegramBot\Exception\TelegramException
220
     */
221
    public static function forceReply(array $data = [])
222
    {
223
        return new static(array_merge(['keyboard' => [], 'force_reply' => true, 'selective' => false], $data));
224
    }
225
}
226