Repository: defstudio/telegraph (php)

Issue:
Implement `setChatMenuButton`
https://core.telegram.org/bots/api#setchatmenubutton



Pull request description:
implement `setChatMenuButton` method
Resolves #194

```php
Telegraph::setChatMenuButton([
    "type" => "commands",
])->send();
```

> **Note**
> web_app type requires text and url.

```php
Telegraph::setChatMenuButton([
    "type" => "web_app",
    "text" => "VISIT",
    "url" => "https://www.telegram.org",
])->send();
```

Patch:
diff --git a/docs/content/en/features/telegram-api-calls.md b/docs/content/en/features/telegram-api-calls.md
index dee14a33..3ff8d95d 100644
--- a/docs/content/en/features/telegram-api-calls.md
+++ b/docs/content/en/features/telegram-api-calls.md
@@ -346,6 +346,17 @@ title: my telegram group
 ...
 */
 ```
+
+## setChatMenuButton
+
+Set menu button. For detailed info, see [docs](https://core.telegram.org/bots/api#menubutton)
+
+```php
+Telegraph::setChatMenuButton()->default()->send(); //restore default 
+Telegraph::setChatMenuButton()->commands()->send(); //show bot commands in menu button 
+Telegraph::setChatMenuButton()->webApp("Web App", "https://my-web.app")->send(); //show start web app button 
+```
+
 ## chatMenuButton
 
 retrieves a bot current menu button info
diff --git a/docs/content/en/models/telegraph-chat.md b/docs/content/en/models/telegraph-chat.md
index cf97ba56..0b9d0c02 100644
--- a/docs/content/en/models/telegraph-chat.md
+++ b/docs/content/en/models/telegraph-chat.md
@@ -538,3 +538,23 @@ A video attachment can be sent through Telegraph `->video()` method:
 /** @var DefStudio\Telegraph\Models\TelegraphChat $telegraphChat */
 $telegraphChat->video()->send();
 ```
+
+### `menuButton`
+
+Retrieves chat menu button
+
+```php
+/** @var DefStudio\Telegraph\Models\TelegraphChat $telegraphChat */
+$button = $telegraphChat->menuButton()->send();
+```
+
+### `setMenuButton`
+
+set chat menu button
+
+```php
+/** @var DefStudio\Telegraph\Models\TelegraphChat $telegraphChat */
+$telegraphChat->setMenuButton()->default()->send(); //restore default 
+$telegraphChat->setMenuButton()->commands()->send(); //show bot commands in menu button 
+$telegraphChat->setMenuButton()->webApp("Web App", "https://my-web.app")->send(); //show start web app button 
+```
diff --git a/src/Concerns/HasBotsAndChats.php b/src/Concerns/HasBotsAndChats.php
index 7a5b57aa..38afd6ce 100644
--- a/src/Concerns/HasBotsAndChats.php
+++ b/src/Concerns/HasBotsAndChats.php
@@ -16,6 +16,7 @@ use DefStudio\Telegraph\Exceptions\FileException;
 use DefStudio\Telegraph\Exceptions\TelegraphException;
 use DefStudio\Telegraph\Models\TelegraphBot;
 use DefStudio\Telegraph\Models\TelegraphChat;
+use DefStudio\Telegraph\ScopedPayloads\SetChatMenuButtonPayload;
 use DefStudio\Telegraph\Telegraph;
 use File;
 use Illuminate\Support\Carbon;
@@ -243,6 +244,15 @@ trait HasBotsAndChats
         return $telegraph;
     }
 
+    public function setChatMenuButton(): SetChatMenuButtonPayload
+    {
+        $telegraph = clone $this;
+        $telegraph->endpoint = self::ENDPOINT_SET_CHAT_MENU_BUTTON;
+        $telegraph->data['chat_id'] = $this->getChatId();
+
+        return SetChatMenuButtonPayload::makeFrom($telegraph);
+    }
+
     public function chatMenuButton(): Telegraph
     {
         $telegraph = clone $this;
diff --git a/src/Facades/Telegraph.php b/src/Facades/Telegraph.php
index a85a7d4e..96124b94 100644
--- a/src/Facades/Telegraph.php
+++ b/src/Facades/Telegraph.php
@@ -6,6 +6,7 @@ use DefStudio\Telegraph\Contracts\Downloadable;
 use DefStudio\Telegraph\Keyboard\Keyboard;
 use DefStudio\Telegraph\Models\TelegraphBot;
 use DefStudio\Telegraph\Models\TelegraphChat;
+use DefStudio\Telegraph\ScopedPayloads\SetChatMenuButtonPayload;
 use DefStudio\Telegraph\ScopedPayloads\TelegraphPollPayload;
 use DefStudio\Telegraph\ScopedPayloads\TelegraphQuizPayload;
 use DefStudio\Telegraph\Support\Testing\Fakes\TelegraphFake;
@@ -67,6 +68,7 @@ use Illuminate\Support\Facades\Facade;
  * @method static \DefStudio\Telegraph\Telegraph  demoteChatMember(string $userId)
  * @method static \DefStudio\Telegraph\Telegraph  userProfilePhotos(string $userId)
  * @method static \DefStudio\Telegraph\Telegraph  chatMenuButton()
+ * @method static SetChatMenuButtonPayload  setChatMenuButton()
  * @method static TelegraphPollPayload poll(string $question)
  * @method static TelegraphQuizPayload quiz(string $question)
  * @method static string store(Downloadable $attachment, string $path, string $filename = null)
diff --git a/src/Models/TelegraphChat.php b/src/Models/TelegraphChat.php
index 9749d81d..f8408c65 100644
--- a/src/Models/TelegraphChat.php
+++ b/src/Models/TelegraphChat.php
@@ -12,6 +12,7 @@ use DefStudio\Telegraph\Database\Factories\TelegraphChatFactory;
 use DefStudio\Telegraph\Exceptions\TelegraphException;
 use DefStudio\Telegraph\Facades\Telegraph as TelegraphFacade;
 use DefStudio\Telegraph\Keyboard\Keyboard;
+use DefStudio\Telegraph\ScopedPayloads\SetChatMenuButtonPayload;
 use DefStudio\Telegraph\ScopedPayloads\TelegraphPollPayload;
 use DefStudio\Telegraph\ScopedPayloads\TelegraphQuizPayload;
 use DefStudio\Telegraph\Telegraph;
@@ -314,4 +315,14 @@ class TelegraphChat extends Model implements Storable
     {
         return TelegraphFacade::chat($this)->forwardMessage($fromChat, $messageId);
     }
+
+    public function menuButton(): Telegraph
+    {
+        return TelegraphFacade::chat($this)->chatMenuButton();
+    }
+
+    public function setMenuButton(): SetChatMenuButtonPayload
+    {
+        return TelegraphFacade::chat($this)->setChatMenuButton();
+    }
 }
diff --git a/src/ScopedPayloads/SetChatMenuButtonPayload.php b/src/ScopedPayloads/SetChatMenuButtonPayload.php
new file mode 100644
index 00000000..06beb585
--- /dev/null
+++ b/src/ScopedPayloads/SetChatMenuButtonPayload.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace DefStudio\Telegraph\ScopedPayloads;
+
+use DefStudio\Telegraph\Concerns\BuildsFromTelegraphClass;
+use DefStudio\Telegraph\Telegraph;
+
+class SetChatMenuButtonPayload extends Telegraph
+{
+    use BuildsFromTelegraphClass;
+
+    public function default(): self
+    {
+        $telegraph = clone $this;
+
+        $telegraph->data['menu_button'] = [
+            'type' => 'default',
+        ];
+
+        return $telegraph;
+    }
+
+    public function commands(): self
+    {
+        $telegraph = clone $this;
+
+        $telegraph->data['menu_button'] = [
+            'type' => 'commands',
+        ];
+
+        return $telegraph;
+    }
+
+    public function webApp(string $text, string $url): self
+    {
+        $telegraph = clone $this;
+
+        $telegraph->data['menu_button'] = [
+            'type' => 'web_app',
+            'text' => $text,
+            'web_app' => [
+                'url' => $url,
+            ],
+        ];
+
+        return $telegraph;
+    }
+}
diff --git a/src/Telegraph.php b/src/Telegraph.php
index daae1c49..e0af3937 100755
--- a/src/Telegraph.php
+++ b/src/Telegraph.php
@@ -106,6 +106,7 @@ class Telegraph
     public const ENDPOINT_SEND_POLL = 'sendPoll';
     public const ENDPOINT_FORWARD_MESSAGE = 'forwardMessage';
     public const ENDPOINT_GET_USER_PROFILE_PHOTOS = 'getUserProfilePhotos';
+    public const ENDPOINT_SET_CHAT_MENU_BUTTON = 'setChatMenuButton';
     public const ENDPOINT_GET_CHAT_MENU_BUTTON = 'getChatMenuButton';
     public const ENDPOINT_DICE = 'sendDice';
 


Test patch:
diff --git a/src/Support/Testing/Fakes/TelegraphFake.php b/src/Support/Testing/Fakes/TelegraphFake.php
index 8409dcf0..afa6ef95 100644
--- a/src/Support/Testing/Fakes/TelegraphFake.php
+++ b/src/Support/Testing/Fakes/TelegraphFake.php
@@ -10,6 +10,7 @@ namespace DefStudio\Telegraph\Support\Testing\Fakes;
 
 use DefStudio\Telegraph\Concerns\FakesRequests;
 use DefStudio\Telegraph\DTO\Attachment;
+use DefStudio\Telegraph\ScopedPayloads\SetChatMenuButtonPayload;
 use DefStudio\Telegraph\ScopedPayloads\TelegraphPollPayload;
 use DefStudio\Telegraph\ScopedPayloads\TelegraphQuizPayload;
 use DefStudio\Telegraph\Telegraph;
@@ -48,6 +49,15 @@ class TelegraphFake extends Telegraph
         return $fake;
     }
 
+    public function setChatMenuButton(): SetChatMenuButtonPayload
+    {
+        $fake = new TelegraphSetChatMenuButtonFake($this->replies);
+        $fake->endpoint = self::ENDPOINT_SET_CHAT_MENU_BUTTON;
+        $fake->data = $this->data;
+
+        return $fake;
+    }
+
     public function quiz(string $question): TelegraphQuizPayload
     {
         $fake = new TelegraphQuizFake($this->replies);
diff --git a/src/Support/Testing/Fakes/TelegraphSetChatMenuButtonFake.php b/src/Support/Testing/Fakes/TelegraphSetChatMenuButtonFake.php
new file mode 100644
index 00000000..a44b9090
--- /dev/null
+++ b/src/Support/Testing/Fakes/TelegraphSetChatMenuButtonFake.php
@@ -0,0 +1,40 @@
+<?php
+
+/** @noinspection PhpUnhandledExceptionInspection */
+
+/** @noinspection PhpUnused */
+
+/** @noinspection PhpPropertyOnlyWrittenInspection */
+
+namespace DefStudio\Telegraph\Support\Testing\Fakes;
+
+use DefStudio\Telegraph\Concerns\FakesRequests;
+
+use DefStudio\Telegraph\ScopedPayloads\SetChatMenuButtonPayload;
+use DefStudio\Telegraph\Telegraph;
+
+class TelegraphSetChatMenuButtonFake extends SetChatMenuButtonPayload
+{
+    use FakesRequests;
+
+    /**
+     * @param array<string, array<mixed>> $replies
+     */
+    public function __construct(array $replies = [])
+    {
+        parent::__construct();
+        $this->replies = $replies;
+    }
+
+    /**
+     * @param array<string, mixed> $options
+     */
+    public static function assertChangedMenuButton(string $type, array $options = []): void
+    {
+        self::assertSentData(Telegraph::ENDPOINT_SET_CHAT_MENU_BUTTON, [
+            'menu_button' => [
+                'type' => $type,
+            ] + $options,
+        ]);
+    }
+}
diff --git a/tests/Unit/Concerns/HasBotsAndChatsTest.php b/tests/Unit/Concerns/HasBotsAndChatsTest.php
index 67544952..597a502c 100644
--- a/tests/Unit/Concerns/HasBotsAndChatsTest.php
+++ b/tests/Unit/Concerns/HasBotsAndChatsTest.php
@@ -340,6 +340,27 @@ it('can demote a chat member', function () {
     })->toMatchTelegramSnapshot();
 });
 
+it('can restore default chat menu button', function () {
+    expect(function (\DefStudio\Telegraph\Telegraph $telegraph) {
+        return $telegraph->chat(make_chat())
+            ->setChatMenuButton()->default();
+    })->toMatchTelegramSnapshot();
+});
+
+it('can set commands chat menu button', function () {
+    expect(function (\DefStudio\Telegraph\Telegraph $telegraph) {
+        return $telegraph->chat(make_chat())
+            ->setChatMenuButton()->commands();
+    })->toMatchTelegramSnapshot();
+});
+
+it('can set web app chat menu button', function () {
+    expect(function (\DefStudio\Telegraph\Telegraph $telegraph) {
+        return $telegraph->chat(make_chat())
+            ->setChatMenuButton()->webApp("VISIT", "https://my-web.app");
+    })->toMatchTelegramSnapshot();
+});
+
 it('can retrieve chat menu button', function () {
     expect(function (\DefStudio\Telegraph\Telegraph $telegraph) {
         return $telegraph->chat(make_chat())
diff --git a/tests/Unit/Models/TelegraphChatTest.php b/tests/Unit/Models/TelegraphChatTest.php
index a0aa8833..de9999c8 100644
--- a/tests/Unit/Models/TelegraphChatTest.php
+++ b/tests/Unit/Models/TelegraphChatTest.php
@@ -13,6 +13,7 @@ use DefStudio\Telegraph\Models\TelegraphBot;
 use DefStudio\Telegraph\Support\Testing\Fakes\TelegraphEditMediaFake;
 use DefStudio\Telegraph\Support\Testing\Fakes\TelegraphPollFake;
 use DefStudio\Telegraph\Support\Testing\Fakes\TelegraphQuizFake;
+use DefStudio\Telegraph\Support\Testing\Fakes\TelegraphSetChatMenuButtonFake;
 use Illuminate\Support\Facades\Storage;
 
 use Illuminate\Support\Str;
@@ -609,3 +610,44 @@ it('can forward a message', function () {
         'message_id' => 123,
     ]);
 });
+
+it('can retrieve current chat menu button', function () {
+    Telegraph::fake();
+    $chat = make_chat();
+
+    $chat->menuButton()->send();
+
+    Telegraph::assertSentData(\DefStudio\Telegraph\Telegraph::ENDPOINT_GET_CHAT_MENU_BUTTON);
+});
+
+it('can restore default menu button', function () {
+    Telegraph::fake();
+    $chat = make_chat();
+
+    $chat->setMenuButton()->default()->send();
+
+    TelegraphSetChatMenuButtonFake::assertChangedMenuButton('default');
+});
+
+it('can set commands menu button', function () {
+    Telegraph::fake();
+    $chat = make_chat();
+
+    $chat->setMenuButton()->commands()->send();
+
+    TelegraphSetChatMenuButtonFake::assertChangedMenuButton('commands');
+});
+
+it('can set web app menu button', function () {
+    Telegraph::fake();
+    $chat = make_chat();
+
+    $chat->setMenuButton()->webApp("VISIT", "https://my-web.app")->send();
+
+    TelegraphSetChatMenuButtonFake::assertChangedMenuButton('web_app', [
+        'text' => "VISIT",
+        'web_app' => [
+            'url' => "https://my-web.app",
+        ],
+    ]);
+});
diff --git a/tests/__snapshots__/TeletraphPollPayloadTest__it_can_create_a_poll__1.yml b/tests/__snapshots__/HasBotsAndChatsTest__it_can_restore_default_chat_menu_button__1.yml
similarity index 64%
rename from tests/__snapshots__/TeletraphPollPayloadTest__it_can_create_a_poll__1.yml
rename to tests/__snapshots__/HasBotsAndChatsTest__it_can_restore_default_chat_menu_button__1.yml
index 1022348a..cd24825a 100644
--- a/tests/__snapshots__/TeletraphPollPayloadTest__it_can_create_a_poll__1.yml
+++ b/tests/__snapshots__/HasBotsAndChatsTest__it_can_restore_default_chat_menu_button__1.yml
@@ -1,6 +1,5 @@
-url: 'https://api.telegram.org/bot3f3814e1-5836-3d77-904e-60f64b15df36/sendPoll'
+url: 'https://api.telegram.org/bot3f3814e1-5836-3d77-904e-60f64b15df36/setChatMenuButton'
 payload:
     chat_id: '-123456789'
-    options: [bar, baz]
-    question: 'foo?'
+    menu_button: { type: default }
 files: {  }
diff --git a/tests/__snapshots__/TeletraphPollPayloadTest__it_can_disable_anonymous_answers__1.yml b/tests/__snapshots__/HasBotsAndChatsTest__it_can_set_commands_chat_menu_button__1.yml
similarity index 56%
rename from tests/__snapshots__/TeletraphPollPayloadTest__it_can_disable_anonymous_answers__1.yml
rename to tests/__snapshots__/HasBotsAndChatsTest__it_can_set_commands_chat_menu_button__1.yml
index 40bc445b..91e6f244 100644
--- a/tests/__snapshots__/TeletraphPollPayloadTest__it_can_disable_anonymous_answers__1.yml
+++ b/tests/__snapshots__/HasBotsAndChatsTest__it_can_set_commands_chat_menu_button__1.yml
@@ -1,7 +1,5 @@
-url: 'https://api.telegram.org/bot3f3814e1-5836-3d77-904e-60f64b15df36/sendPoll'
+url: 'https://api.telegram.org/bot3f3814e1-5836-3d77-904e-60f64b15df36/setChatMenuButton'
 payload:
     chat_id: '-123456789'
-    options: [bar, baz]
-    question: 'foo?'
-    is_anonymous: false
+    menu_button: { type: commands }
 files: {  }
diff --git a/tests/__snapshots__/HasBotsAndChatsTest__it_can_set_web_app_chat_menu_button__1.yml b/tests/__snapshots__/HasBotsAndChatsTest__it_can_set_web_app_chat_menu_button__1.yml
new file mode 100644
index 00000000..5004c8a8
--- /dev/null
+++ b/tests/__snapshots__/HasBotsAndChatsTest__it_can_set_web_app_chat_menu_button__1.yml
@@ -0,0 +1,5 @@
+url: 'https://api.telegram.org/bot3f3814e1-5836-3d77-904e-60f64b15df36/setChatMenuButton'
+payload:
+    chat_id: '-123456789'
+    menu_button: { type: web_app, text: VISIT, web_app: { url: 'https://my-web.app' } }
+files: {  }
diff --git a/tests/__snapshots__/SendsAttachmentsTest__it_can_edit_a_media_messages__1.yml b/tests/__snapshots__/SendsAttachmentsTest__it_can_edit_a_media_messages__1.yml
deleted file mode 100644
index 8752522c..00000000
--- a/tests/__snapshots__/SendsAttachmentsTest__it_can_edit_a_media_messages__1.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-url: 'https://api.telegram.org/bot3f3814e1-5836-3d77-904e-60f64b15df36/editMessageMedia'
-payload:
-    chat_id: '-123456789'
-    message_id: 42
-    media: '{"media":"www.mediaUrl.com","type":"photo"}'
-files: {  }
diff --git a/tests/__snapshots__/TeletraphPollPayloadTest__it_can_allow_multiple_answers__1.yml b/tests/__snapshots__/TeletraphPollPayloadTest__it_can_allow_multiple_answers__1.yml
deleted file mode 100644
index 9ab7ca1c..00000000
--- a/tests/__snapshots__/TeletraphPollPayloadTest__it_can_allow_multiple_answers__1.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-url: 'https://api.telegram.org/bot3f3814e1-5836-3d77-904e-60f64b15df36/sendPoll'
-payload:
-    chat_id: '-123456789'
-    options: [bar, baz]
-    question: 'foo?'
-    allows_multiple_answers: true
-files: {  }
diff --git a/tests/__snapshots__/TeletraphPollPayloadTest__it_can_set_poll_validity__1.yml b/tests/__snapshots__/TeletraphPollPayloadTest__it_can_set_poll_validity__1.yml
deleted file mode 100644
index 66e5ed68..00000000
--- a/tests/__snapshots__/TeletraphPollPayloadTest__it_can_set_poll_validity__1.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-url: 'https://api.telegram.org/bot3f3814e1-5836-3d77-904e-60f64b15df36/sendPoll'
-payload:
-    chat_id: '-123456789'
-    options: [bar, baz]
-    question: 'foo?'
-    close_date: 1601682625
-files: {  }
diff --git a/tests/__snapshots__/TeletraphQuizPayloadTest__it_can_create_a_quiz__1.yml b/tests/__snapshots__/TeletraphQuizPayloadTest__it_can_create_a_quiz__1.yml
deleted file mode 100644
index a468c193..00000000
--- a/tests/__snapshots__/TeletraphQuizPayloadTest__it_can_create_a_quiz__1.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-url: 'https://api.telegram.org/bot3f3814e1-5836-3d77-904e-60f64b15df36/sendPoll'
-payload:
-    chat_id: '-123456789'
-    type: quiz
-    options: [bar, baz, qux]
-    question: 'foo?'
-    correct_option_id: 1
-files: {  }
diff --git a/tests/__snapshots__/TeletraphQuizPayloadTest__it_can_disable_anonymous_answers__1.yml b/tests/__snapshots__/TeletraphQuizPayloadTest__it_can_disable_anonymous_answers__1.yml
deleted file mode 100644
index 3c71b353..00000000
--- a/tests/__snapshots__/TeletraphQuizPayloadTest__it_can_disable_anonymous_answers__1.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-url: 'https://api.telegram.org/bot3f3814e1-5836-3d77-904e-60f64b15df36/sendPoll'
-payload:
-    chat_id: '-123456789'
-    type: quiz
-    options: [bar, baz]
-    question: 'foo?'
-    is_anonymous: false
-files: {  }
diff --git a/tests/__snapshots__/TeletraphQuizPayloadTest__it_can_set_quiz_validity__1.yml b/tests/__snapshots__/TeletraphQuizPayloadTest__it_can_set_quiz_validity__1.yml
deleted file mode 100644
index 2acdd026..00000000
--- a/tests/__snapshots__/TeletraphQuizPayloadTest__it_can_set_quiz_validity__1.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-url: 'https://api.telegram.org/bot3f3814e1-5836-3d77-904e-60f64b15df36/sendPoll'
-payload:
-    chat_id: '-123456789'
-    type: quiz
-    options: [bar, baz]
-    question: 'foo?'
-    close_date: 1601682625
-files: {  }