First rewrite of the keyboard entities.

Update all keyboard commands to follow new structure.
parent bf5c0648
......@@ -11,8 +11,8 @@
namespace Longman\TelegramBot\Commands\UserCommands;
use Longman\TelegramBot\Commands\UserCommand;
use Longman\TelegramBot\Entities\Keyboard;
use Longman\TelegramBot\Request;
use Longman\TelegramBot\Entities\ForceReply;
/**
* User "/forcereply" command
......@@ -25,7 +25,7 @@ class ForceReplyCommand extends UserCommand
protected $name = 'forcereply';
protected $description = 'Force reply with reply markup';
protected $usage = '/forcereply';
protected $version = '0.0.6';
protected $version = '0.1.0';
/**#@-*/
/**
......@@ -33,13 +33,12 @@ class ForceReplyCommand extends UserCommand
*/
public function execute()
{
$message = $this->getMessage();
$chat_id = $message->getChat()->getId();
$chat_id = $this->getMessage()->getChat()->getId();
$data = [
'chat_id' => $chat_id,
'text' => 'Write something:',
'reply_markup' => new ForceReply(['selective' => false]),
'reply_markup' => Keyboard::forceReply(),
];
return Request::sendMessage($data);
......
......@@ -11,8 +11,7 @@
namespace Longman\TelegramBot\Commands\UserCommands;
use Longman\TelegramBot\Commands\UserCommand;
use Longman\TelegramBot\Entities\ReplyKeyboardHide;
use Longman\TelegramBot\Entities\ReplyKeyboardMarkup;
use Longman\TelegramBot\Entities\Keyboard;
use Longman\TelegramBot\Request;
/**
......@@ -26,7 +25,7 @@ class HidekeyboardCommand extends UserCommand
protected $name = 'hidekeyboard';
protected $description = 'Hide the custom keyboard';
protected $usage = '/hidekeyboard';
protected $version = '0.0.6';
protected $version = '0.1.0';
/**#@-*/
/**
......@@ -34,13 +33,12 @@ class HidekeyboardCommand extends UserCommand
*/
public function execute()
{
$message = $this->getMessage();
$chat_id = $message->getChat()->getId();
$chat_id = $this->getMessage()->getChat()->getId();
$data = [
'chat_id' => $chat_id,
'text' => 'Keyboard Hidden',
'reply_markup' => new ReplyKeyboardHide(['selective' => false]),
'reply_markup' => Keyboard::hide(),
];
return Request::sendMessage($data);
......
......@@ -11,9 +11,8 @@
namespace Longman\TelegramBot\Commands\UserCommands;
use Longman\TelegramBot\Commands\UserCommand;
use Longman\TelegramBot\Entities\InlineKeyboard;
use Longman\TelegramBot\Request;
use Longman\TelegramBot\Entities\InlineKeyboardMarkup;
use Longman\TelegramBot\Entities\InlineKeyboardButton;
/**
* User "/inlinekeyboard" command
......@@ -23,10 +22,10 @@ class InlinekeyboardCommand extends UserCommand
/**#@+
* {@inheritdoc}
*/
protected $name = 'Inlinekeyboard';
protected $name = 'inlinekeyboard';
protected $description = 'Show inline keyboard';
protected $usage = '/inlinekeyboard';
protected $version = '0.0.2';
protected $version = '0.1.0';
/**#@-*/
/**
......@@ -34,17 +33,18 @@ class InlinekeyboardCommand extends UserCommand
*/
public function execute()
{
$message = $this->getMessage();
$chat_id = $this->getMessage()->getChat()->getId();
$inline_keyboard = new InlineKeyboard([
['text' => 'inline', 'switch_inline_query' => 'true'],
['text' => 'callback', 'callback_data' => 'identifier'],
['text' => 'open url', 'url' => 'https://github.com/akalongman/php-telegram-bot'],
]);
$inline_keyboard = [
new InlineKeyboardButton(['text' => 'inline', 'switch_inline_query' => 'true']),
new InlineKeyboardButton(['text' => 'callback', 'callback_data' => 'identifier']),
new InlineKeyboardButton(['text' => 'open url', 'url' => 'https://github.com/akalongman/php-telegram-bot']),
];
$data = [
'chat_id' => $message->getChat()->getId(),
'chat_id' => $chat_id,
'text' => 'inline keyboard',
'reply_markup' => new InlineKeyboardMarkup(['inline_keyboard' => [$inline_keyboard]]),
'reply_markup' => $inline_keyboard,
];
return Request::sendMessage($data);
......
......@@ -11,8 +11,8 @@
namespace Longman\TelegramBot\Commands\UserCommands;
use Longman\TelegramBot\Commands\UserCommand;
use Longman\TelegramBot\Entities\Keyboard;
use Longman\TelegramBot\Request;
use Longman\TelegramBot\Entities\ReplyKeyboardMarkup;
/**
* User "/keyboard" command
......@@ -25,7 +25,7 @@ class KeyboardCommand extends UserCommand
protected $name = 'keyboard';
protected $description = 'Show a custom keyboard with reply markup';
protected $usage = '/keyboard';
protected $version = '0.1.0';
protected $version = '0.2.0';
/**#@-*/
/**
......@@ -33,71 +33,55 @@ class KeyboardCommand extends UserCommand
*/
public function execute()
{
$message = $this->getMessage();
$chat_id = $message->getChat()->getId();
$data = [
'chat_id' => $chat_id,
'text' => 'Press a Button:',
];
$chat_id = $this->getMessage()->getChat()->getId();
//Keyboard examples
/** @var Keyboard[] $keyboards */
$keyboards = [];
//Example 0
$keyboard = [];
$keyboard[] = ['7', '8', '9'];
$keyboard[] = ['4', '5', '6'];
$keyboard[] = ['1', '2', '3'];
$keyboard[] = [' ', '0', ' '];
$keyboards[] = $keyboard;
$keyboards[] = new Keyboard(
['7', '8', '9'],
['4', '5', '6'],
['1', '2', '3'],
[' ', '0', ' ']
);
//Example 1
$keyboard = [];
$keyboard[] = ['7', '8', '9', '+'];
$keyboard[] = ['4', '5', '6', '-'];
$keyboard[] = ['1', '2', '3', '*'];
$keyboard[] = [' ', '0', ' ', '/'];
$keyboards[] = $keyboard;
$keyboards[] = new Keyboard(
['7', '8', '9', '+'],
['4', '5', '6', '-'],
['1', '2', '3', '*'],
[' ', '0', ' ', '/']
);
//Example 2
$keyboard = [];
$keyboard[] = ['A'];
$keyboard[] = ['B'];
$keyboard[] = ['C'];
$keyboards[] = $keyboard;
$keyboards[] = new Keyboard('A', 'B', 'C');
//Example 3
$keyboard = [];
$keyboard[] = ['A'];
$keyboard[] = ['B'];
$keyboard[] = ['C', 'D'];
$keyboards[] = $keyboard;
$keyboards[] = new Keyboard(
['text' => 'A'],
'B',
['C', 'D']
);
//Example 4 (bots version 2.0)
$keyboard = [];
$keyboard[] = [
[
'text' => 'Send my contact',
'request_contact' => true,
],
[
'text' => 'Send my location',
'request_location' => true,
],
];
$keyboards[] = $keyboard;
$keyboards[] = new Keyboard([
['text' => 'Send my contact', 'request_contact' => true],
['text' => 'Send my location', 'request_location' => true],
]);
//Return a random keyboard.
$keyboard = $keyboards[mt_rand(0, count($keyboards) - 1)];
$data['reply_markup'] = new ReplyKeyboardMarkup(
[
'keyboard' => $keyboard,
'resize_keyboard' => true,
'one_time_keyboard' => false,
'selective' => false,
]
);
$keyboard = $keyboards[mt_rand(0, count($keyboards) - 1)]
->setResizeKeyboard(true)
->setOneTimeKeyboard(true)
->setSelective(false);
$data = [
'chat_id' => $chat_id,
'text' => 'Press a Button:',
'reply_markup' => $keyboard,
];
return Request::sendMessage($data);
}
......
......@@ -11,6 +11,7 @@
namespace Longman\TelegramBot\Entities;
use Exception;
use Longman\TelegramBot\Entities\InlineQuery\InlineEntity;
use ReflectionObject;
/**
......@@ -198,7 +199,7 @@ abstract class Entity
}
/**
* Return the variable for the called getter
* Return the variable for the called getter or magically set properties dynamically.
*
* @param $method
* @param $args
......@@ -207,10 +208,11 @@ abstract class Entity
*/
public function __call($method, $args)
{
$action = substr($method, 0, 3);
if ($action === 'get') {
//Convert method to snake_case (which is the name of the property)
$property_name = ltrim(strtolower(preg_replace('/[A-Z]/', '_$0', substr($method, 3))), '_');
$action = substr($method, 0, 3);
if ($action === 'get') {
$property = $this->getProperty($property_name);
if ($property !== null) {
......@@ -223,6 +225,13 @@ abstract class Entity
return $property;
}
} elseif ($action === 'set') {
// Limit setters to specific classes.
if ($this instanceof InlineEntity || $this instanceof Keyboard || $this instanceof KeyboardButton) {
$this->$property_name = $args[0];
return $this;
}
}
return null;
......
<?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;
/**
* Class ForceReply
*
* @link https://core.telegram.org/bots/api#forcereply
*
* @method bool getForceReply() Shows reply interface to the user, as if they manually selected the bot‘s message and tapped 'Reply'
* @method bool getSelective() Optional. Use this parameter if you want to force reply from 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 ForceReply extends Entity
{
/**
* ForceReply constructor.
*
* @param array $data
*
* @throws \Longman\TelegramBot\Exception\TelegramException
*/
public function __construct(array $data = [])
{
$data['force_reply'] = true;
parent::__construct($data);
}
}
......@@ -13,22 +13,19 @@ namespace Longman\TelegramBot\Entities;
use Longman\TelegramBot\Exception\TelegramException;
/**
* Class InlineKeyboardMarkup
* Class InlineKeyboard
*
* @link https://core.telegram.org/bots/api#inlinekeyboardmarkup
*
* @method InlineKeyboardButton[][] getInlineKeyboard() Array of button rows, each represented by an Array of InlineKeyboardButton objects
*/
class InlineKeyboardMarkup extends Entity
class InlineKeyboard extends Keyboard
{
/**
* {@inheritdoc}
*/
protected function subEntities()
public function __construct($data = [])
{
return [
'inline_keyboard' => InlineKeyboardButton::class,
];
$data = call_user_func_array([$this, 'createFromParams'], func_get_args());
parent::__construct($data);
}
/**
......@@ -38,10 +35,7 @@ class InlineKeyboardMarkup extends Entity
{
$inline_keyboard = $this->getProperty('inline_keyboard');
if ($inline_keyboard === null) {
throw new TelegramException('Inline Keyboard field is empty!');
}
if ($inline_keyboard !== null) {
if (!is_array($inline_keyboard)) {
throw new TelegramException('Inline Keyboard field is not an array!');
}
......@@ -52,4 +46,5 @@ class InlineKeyboardMarkup extends Entity
}
}
}
}
}
......@@ -21,9 +21,31 @@ use Longman\TelegramBot\Exception\TelegramException;
* @method string getUrl() Optional. HTTP url to be opened when button is pressed
* @method string getCallbackData() Optional. Data to be sent in a callback query to the bot when button is pressed, 1-64 bytes
* @method string getSwitchInlineQuery() Optional. If set, pressing the button will prompt the user to select one of their chats, open that chat and insert the bot's username and the specified inline query in the input field. Can be empty, in which case just the bot’s username will be inserted.
*
* @method $this setText(string $text) Label text on the button
* @method $this setUrl(string $url) Optional. HTTP url to be opened when button is pressed
* @method $this setCallbackData(string $callback_data) Optional. Data to be sent in a callback query to the bot when button is pressed, 1-64 bytes
* @method $this setSwitchInlineQuery(string $switch_inline_query) Optional. If set, pressing the button will prompt the user to select one of their chats, open that chat and insert the bot's username and the specified inline query in the input field. Can be empty, in which case just the bot’s username will be inserted.
*/
class InlineKeyboardButton extends Entity
class InlineKeyboardButton extends KeyboardButton
{
/**
* Check if the passed data array could be an InlineKeyboardButton.
*
* @param array $data
*
* @return bool
*/
public static function couldBe($data)
{
return is_array($data) &&
array_key_exists('text', $data) && (
array_key_exists('url', $data) ||
array_key_exists('callback_data', $data) ||
array_key_exists('switch_inline_query', $data)
);
}
/**
* {@inheritdoc}
*/
......@@ -41,4 +63,17 @@ class InlineKeyboardButton extends Entity
throw new TelegramException('You must use only one of these fields: url, callback_data, switch_inline_query!');
}
}
/**
* {@inheritdoc}
*/
public function __call($method, $args)
{
// Only 1 of these can be set, so clear the others when setting a new one.
if (in_array($method, ['setUrl', 'setCallbackData', 'setSwitchInlineQuery'], true)) {
unset($this->url, $this->callback_data, $this->switch_inline_query);
}
return parent::__call($method, $args);
}
}
......@@ -12,27 +12,12 @@ namespace Longman\TelegramBot\Entities\InlineQuery;
use Longman\TelegramBot\Entities\Entity;
abstract class InlineEntity extends Entity
{
/**
* Magic method to set properties dynamically
*
* @param $method
* @param $args
/**
* Class InlineEntity
*
* @return \Longman\TelegramBot\Entities\InlineQuery\InlineEntity
* This is the base class for all inline entities.
*/
public function __call($method, $args)
{
$action = substr($method, 0, 3);
if ($action === 'set') {
//Convert method to snake_case (which is the name of the property)
$property_name = ltrim(strtolower(preg_replace('/[A-Z]/', '_$0', substr($method, 3))), '_');
$this->$property_name = $args[0];
return $this;
}
abstract class InlineEntity extends Entity
{
return parent::__call($method, $args);
}
}
<?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 ReplyKeyboardMarkup
*
* @link https://core.telegram.org/bots/api#replykeyboardmarkup
*
* @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 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.
* @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 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 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.
* @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
{
/**
* {@inheritdoc}
*/
public function __construct($data = [])
{
$data = call_user_func_array([$this, 'createFromParams'], func_get_args());
parent::__construct($data);
}
/**
* If this keyboard is an inline keyboard.
*
* @return bool
*/
public function isInlineKeyboard()
{
return $this instanceof InlineKeyboard;
}
/**
* Get the proper keyboard button class for this keyboard.
*
* @return mixed
*/
public function getKeyboardButtonClass()
{
return $this->isInlineKeyboard() ? InlineKeyboardButton::class : KeyboardButton::class;
}
/**
* Get the type of keyboard, either "inline_keyboard" or "keyboard".
*
* @return string
*/
public function getKeyboardType()
{
return $this->isInlineKeyboard() ? 'inline_keyboard' : 'keyboard';
}
/**
* If no explicit keyboard is passed, try to create one from the parameters.
*
* @return array
*/
protected function createFromParams()
{
/** @var KeyboardButton|InlineKeyboardButton $button_class */
$button_class = $this->getKeyboardButtonClass();
$keyboard_type = $this->getKeyboardType();
// If the inline_keyboard isn't set directly, try to create one from the arguments.
$data = func_get_arg(0);
if (!array_key_exists($keyboard_type, $data)) {
$new_keyboard = [];
foreach (func_get_args() as $row) {
if (is_array($row)) {
$new_row = [];
if ($button_class::couldBe($row)) {
$new_row[] = new $button_class($row);
} else {
foreach ($row as $button) {
if ($button instanceof $button_class) {
$new_row[] = $button;
} elseif (!$this->isInlineKeyboard() || $button_class::couldBe($button)) {
$new_row[] = new $button_class($button);
}
}
}
} else {
$new_row = [new $button_class($row)];
}
$new_keyboard[] = $new_row;
}
if (!empty($new_keyboard)) {
$data = [$keyboard_type => $new_keyboard];
}
}
return $data;
}
/**
* Create a new row in keyboard and add buttons.
*
* @return $this
*/
public function addRow()
{
$keyboard_type = $this->getKeyboardType();
$this->$keyboard_type[] = func_get_args();
return $this;
}
/**
* {@inheritdoc}
*/
protected function validate()
{
$keyboard = $this->getProperty('keyboard');
if ($keyboard !== null) {
if (!is_array($keyboard)) {
throw new TelegramException('Keyboard field is not an array!');
}
foreach ($keyboard as $item) {
if (!is_array($item)) {
throw new TelegramException('Keyboard subfield is not an array!');
}
}
}
}
/**
* Hide the current custom keyboard and display the default letter-keyboard.
*
* @link https://core.telegram.org/bots/api#replykeyboardhide
*
* @param array $data
*
* @return \Longman\TelegramBot\Entities\Keyboard
* @throws \Longman\TelegramBot\Exception\TelegramException
*/
public static function hide(array $data = [])
{
return new static(array_merge(['keyboard' => null, 'hide_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 \Longman\TelegramBot\Entities\Keyboard
* @throws \Longman\TelegramBot\Exception\TelegramException
*/
public static function forceReply(array $data = [])
{
return new static(array_merge(['keyboard' => null, 'force_reply' => true, 'selective' => false], $data));
}
}
......@@ -20,9 +20,40 @@ use Longman\TelegramBot\Exception\TelegramException;
* @method string getText() Text of the button. If none of the optional fields are used, it will be sent to the bot as a message when the button is pressed
* @method bool getRequestContact() Optional. If True, the user's phone number will be sent as a contact when the button is pressed. Available in private chats only
* @method bool getRequestLocation() Optional. If True, the user's current location will be sent when the button is pressed. Available in private chats only
*
* @method $this setText(string $text) Text of the button. If none of the optional fields are used, it will be sent to the bot as a message when the button is pressed
* @method $this setRequestContact(bool $request_contact) Optional. If True, the user's phone number will be sent as a contact when the button is pressed. Available in private chats only
* @method $this setRequestLocation(bool $request_location) Optional. If True, the user's current location will be sent when the button is pressed. Available in private chats only
*/
class KeyboardButton extends Entity
{
/**
* {@inheritdoc}
*/
public function __construct($data)
{
if (is_string($data)) {
$data = ['text' => $data];
}
parent::__construct($data);
}
/**
* Check if the passed data array could be a KeyboardButton.
*
* @param array $data
*
* @return bool
*/
public static function couldBe($data)
{
return is_array($data) &&
array_key_exists('text', $data) && (
array_key_exists('request_contact', $data) ||
array_key_exists('request_location', $data)
);
}
/**
* {@inheritdoc}
*/
......@@ -32,4 +63,17 @@ class KeyboardButton extends Entity
throw new TelegramException('You must use only one of these fields: request_contact, request_location!');
}
}
/**
* {@inheritdoc}
*/
public function __call($method, $args)
{
// Only 1 of these can be set, so clear the others when setting a new one.
if (in_array($method, ['setRequestContact', 'setRequestLocation'], true)) {
unset($this->request_contact, $this->request_location);
}
return parent::__call($method, $args);
}
}
<?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;
/**
* Class ReplyKeyboardHide
*
* @link https://core.telegram.org/bots/api#replykeyboardhide
*
* @method bool getHideKeyboard() Requests clients to hide the custom keyboard
* @method bool getSelective() Optional. Use this parameter if you want to hide keyboard for 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 ReplyKeyboardHide extends Entity
{
/**
* ReplyKeyboardHide constructor.
*
* @param array $data
*
* @throws \Longman\TelegramBot\Exception\TelegramException
*/
public function __construct(array $data = [])
{
$data['hide_keyboard'] = true;
parent::__construct($data);
}
}
<?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 ReplyKeyboardMarkup
*
* @link https://core.telegram.org/bots/api#replykeyboardmarkup
*
* @method KeyboardButton[][] getKeyboard() Array of button rows, each represented by an Array of KeyboardButton objects
* @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 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.
* @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.
*/
class ReplyKeyboardMarkup extends Entity
{
/**
* {@inheritdoc}
*/
protected function subEntities()
{
return [
'keyboard' => KeyboardButton::class,
];
}
/**
* {@inheritdoc}
*/
protected function validate()
{
$keyboard = $this->getProperty('keyboard');
if ($keyboard === null) {
throw new TelegramException('Keyboard field is empty!');
}
if (!is_array($keyboard)) {
throw new TelegramException('Keyboard field is not an array!');
}
foreach ($keyboard as $item) {
if (!is_array($item)) {
throw new TelegramException('Keyboard subfield is not an array!');
}
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment