mohammad-zarifiyan/laravel-telegram-bot

这是一个Laravel包,可以帮助您轻松创建可扩展的Telegram机器人,并通过Telegram发送通知。

6.8.4 2024-07-20 11:18 UTC

This package is auto-updated.

Last update: 2024-09-05 15:25:43 UTC


README

此包可以帮助您轻松在Laravel项目中使用Telegram Bot API,并利用其功能构建出色的Telegram机器人。

请阅读Telegram API文档以深入了解如何使用此包。

安装

要在项目中安装此包,请在项目根目录中运行以下命令

composer require mohammad-zarifiyan/laravel-telegram-bot:^6.8

基本配置

如果您想发布配置文件,请运行以下命令(可选)

php artisan vendor:publish --provider="MohammadZarifiyan\Telegram\Providers\TelegramServiceProvider" --tag="telegram-config"

配置API密钥

要使用Telegram机器人,您必须有一个API密钥。您可以通过@BotFather 获取API密钥。然后,设置您的机器人的API密钥。默认情况下,您应该在config/services.php文件中添加以下代码

<?php

return [
    // The rest of your code

    'telegram' => [
        'api-key' => env('TELEGRAM_API_KEY'),
    ],
];

然后在.env文件中添加TELEGRAM_API_KEY

自定义仓库

如果您想通过其他方式获取API密钥,例如数据库,您可以使用自己的仓库而不是上述方法。只需创建一个类,并在其中实现MohammadZarifiyan\Telegram\Interfaces\ApiKeyRepository。然后,在telegram.php配置文件中,将api-key-repository的值设置为您的类的地址。

示例

app/Repositories/TelegramApiKeyRepository.php 文件

<?php

namespace App\Repositories;

use \MohammadZarifiyan\Telegram\Interfaces\ApiKeyRepository;

class TelegramApiKeyRepository implements ApiKeyRepository
{
    public function get(): ?string
    {
        return '123456:abcdefg';// Return API Key
    }
}

telegram.php 配置文件

<?php

return [
    // The rest of the file

    'api-key-repository' => \App\Repositories\TelegramApiKeyRepository::class,// Set your own custom repository

    // The rest of the file
];

配置端点

您可以使用任意端点向其发送HTTP请求,而不是使用Telegram机器人的默认端点(api.telegram.org)。默认情况下,您应该在config/services.php文件中添加以下代码

<?php

return [
    // The rest of your code

    'telegram' => [
        'endpoint' => env('TELEGRAM_ENDPOINT'),
    ],
];

然后在.env文件中添加TELEGRAM_ENDPOINT

自定义仓库

如果您想通过其他方式获取端点,例如数据库,您可以创建自己的仓库而不是上述方法。只需创建一个类,并在其中实现MohammadZarifiyan\Telegram\Interfaces\EndpointRepository。然后,在telegram.php配置文件中,将endpoint-repository的值设置为您的类的地址。

示例

app/Repositories/TelegramEndpointRepository.php 文件

<?php

namespace App\Repositories;

use \MohammadZarifiyan\Telegram\Interfaces\EndpointRepository;

class TelegramEndpointRepository implements EndpointRepository
{
    public function get(): ?string
    {
        return 'https://example.com';// Return your own custom endpoint
    }
}

telegram.php 配置文件

<?php

return [
    // The rest of the file

    'endpoint-repository' => \App\Repositories\TelegramEndpointRepository::class,// Set your own custom repository

    // The rest of the file
];

验证端点的TLS证书

您还可以在向端点发送请求时设置端点的TLS证书进行验证。为此,您可以在.env中设置TELEGRAM_VERIFY_ENDPOINT。建议将TELEGRAM_VERIFY_ENDPOINT的值始终设置为true

telegram.php 配置文件

<?php

return [
    // The rest of the file
    
    'verify-endpoint' => (bool) env('TELEGRAM_VERIFY_ENDPOINT', true),
    
    // The rest of the file
];

向Telegram提交请求

使用perform方法向Telegram API发送请求。第一个参数是方法,第二个参数是要发送到Telegram API的数据。

注意:请参阅此链接中可用的Telegram方法

示例

在以下示例中,发送了“Hello world”。

use \MohammadZarifiyan\Telegram\Facades\Telegram;

Telegram::perform('sendMessage', [
    'text' => 'Hello world!',
    'chat_id' => 1234
]);

并发请求

有时,您可能希望并发地发出多个HTTP请求。换句话说,您希望同时发出多个请求而不是按顺序发出请求。

幸运的是,您可以使用concurrent方法来完成此操作。该方法接受一个闭包,该闭包接收一个MohammadZarifiyan\Telegram\Interfaces\PendingRequestStack实例,允许您轻松地将请求添加到请求池以进行调度。

示例

以下示例中,同时向用户发送了三条消息。

use \MohammadZarifiyan\Telegram\Interfaces\PendingRequestStack;
use \MohammadZarifiyan\Telegram\Facades\Telegram;
 
$responses = Telegram::concurrent(fn (PendingRequestStack $pendingRequestStack) => [
    $pendingRequestStack->add('sendMessage', [
        'text' => 'Message 1',
        'chat_id' => 1234
    ]),
    $pendingRequestStack->add('sendMessage', [
        'text' => 'Message 2',
        'chat_id' => 1234
    ]),
    $pendingRequestStack->add('sendMessage', [
        'text' => 'Message 3',
        'chat_id' => 1234
    ]),
]);

$result = $responses[0]->json('ok')
    && $responses[1]->json('ok')
    && $responses[2]->json('ok');

if ($result) {
    // All messages have been sent successfully.
}
else {
    // There was a problem sending some messages.
}

通过Telegram机器人发送通知

要通过Telegram发送通知,请将routeNotificationForTelegram方法添加到您的通知模型中。然后,返回通知的Telegramchat_id

public function routeNotificationForTelegram($notification)
{
    // return telegram id
}

从通知的via方法返回telegram通道。

public function via($notifiable): array
{
    return ['telegram'];
}

最后,将toTelegram添加到您的通知类中,并使用MohammadZarifiyan\Telegram\TelegramRequestContent来指定您的Telegram通知数据。

use \MohammadZarifiyan\Telegram\Interfaces\TelegramRequestContent as TelegramRequestContentInterface;

public function toTelegram($notifiable): TelegramRequestContentInterface
{
    // Return an instance of \MohammadZarifiyan\Telegram\TelegramRequestContent
}

示例

以下示例中,你好发送给了所有用户。

use App\Notifications\HelloNotification;
use App\Models\User;
use Illuminate\Support\Facades\Notification;

$users = User::all();

Notification::send($users, HelloNotification::class);

User.php文件

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Notifications\Notifiable;

class User extends Model
{
    use Notifiable;

    protected $fillable = ['telegram_id'];

    protected $casts = [
        'telegram_id' => 'integer'
    ];

    public function routeNotificationForTelegram($notification)
    {
        return $this->telegram_id;
    }
}

HelloNotification.php文件

<?php

namespace App\Notifications;

use \Illuminate\Notifications\Notification;
use \MohammadZarifiyan\Telegram\Interfaces\TelegramRequestContent as TelegramRequestContentInterface;
use \MohammadZarifiyan\Telegram\TelegramRequestContent;

class PaymentPaidNotification extends Notification
{
    public function via($notifiable): array
    {
        return ['telegram'];
    }

    public function toTelegram($notifiable): TelegramRequestContentInterface
    {
        return TelegramRequestContent::fresh()
            ->setMethod('sendMessage')
            ->setData([
                'text' => 'Hello'
            ]);
    }
}

回复标记

如果您想在请求有效载荷中添加可重用的回复标记,只需创建一个ReplyMarkup类。要创建一个ReplyMarkup类,请运行以下命令

php artisan make:telegram-reply-markup <ReplyMarkupName>

示例

php artisan make:telegram-reply-markup MyKeyboard

app\Telegram\ReplyMarkups\MyKeyboard.php文件

<?php

namespace App\Telegram\ReplyMarkups;

use \MohammadZarifiyan\Telegram\Interfaces\ReplyMarkup;

class MyKeyboard implements ReplyMarkup
{
    public function __invoke(): array
    {
        return [
            'resize_keyboard' => true,
            'keyboard' => [
                [
                    // This array contains a row
                    
                    [
                        // This array contains a column
                        'text' => 'top left button'
                    ],
                    
                    [
                        // This array contains a column
                        'text' => 'top right button'
                    ]
                ],
                [
                    // This array contains a row
                    
                    [
                        // This array contains a column
                        'text' => 'bottom left button'
                    ],
                    
                    [
                        // This array contains a column
                        'text' => 'bottom right button'
                    ]
                ]
            ]
        ];
    }
}

以下是最终代码

use \App\Telegram\ReplyMarkups\MyKeyboard;
use \MohammadZarifiyan\Telegram\Facades\Telegram;

Telegram::perform(
    'sendMessage',
    [
        'text' => 'Hello world!',
        'chat_id' => 1234
    ],
    MyKeyboard::class
);

您甚至可以使用setReplyMarkup方法在通知中使用您的ReplyMarkup类。

<?php

namespace App\Notifications;

use \App\Telegram\ReplyMarkups\MyKeyboard;
use \Illuminate\Notifications\Notification;
use MohammadZarifiyan\Telegram\Interfaces\TelegramRequestContent as TelegramRequestContentInterface;
use \MohammadZarifiyan\Telegram\TelegramRequestContent;

class PaymentPaidNotification extends Notification
{
    public function via($notifiable): array
    {
        return ['telegram'];
    }

    public function toTelegram($notifiable): TelegramRequestContentInterface
    {
        return TelegramRequestContent::fresh()
            ->setMethod('sendMessage')
            ->setData([
                'text' => 'Hello'
            ])
            ->setReplyMarkup(MyKeyboard::class); 
    }
}

附件

使用MohammadZarifiyan\Telegram\Attachment类将服务器上存储的文件附加到请求中。

示例

以下示例中,服务器上存储的图片将被发送到聊天中。

use MohammadZarifiyan\Telegram\Facades\Telegram;
use MohammadZarifiyan\Telegram\Attachment;

$file_contents = file_get_contents('path/to/file.png');
$file_name = 'my-file.png';

Telegram::perform('sendPhoto', [
    'photo' => new Attachment($file_contents, $file_name),
    'chat_id' => 1234
]);

请求操作

有时,您可能希望在发送执行之前操作请求。

首先,创建一个类并实现\MohammadZarifiyan\Telegram\Interfaces\PendingRequest。然后,在其构造函数中检索\MohammadZarifiyan\Telegram\Interfaces\PendingRequest

接下来,在telegram.php配置文件中,将pending-request-manipulator的值设置为您的类地址。

然后,您可以按照需要操作在构造函数中接收到的请求。

telegram.php 配置文件

<?php

return [
    // The rest of the file
    
    'pending-request-manipulator' => App\Telegram\PendingRequestManipulator::class,
    
    // The rest of the file
];

PendingRequestManipulator.php文件

<?php

namespace App\Telegram;

use MohammadZarifiyan\Telegram\Interfaces\PendingRequest as PendingRequestInterface;

class PendingRequestManipulator implements PendingRequestInterface
{
    public function __construct(public PendingRequestInterface $pendingRequest)
    {
        //
    }
    
    public function getUrl(): string
    {
        return $this->pendingRequest->getUrl();// You can change the URL of the request here.
    }
    
    public function getBody(): array
    {
        return $this->pendingRequest->getBody();// You can change the body of the request here.
    }
    
    public function getAttachments(): array
    {
        return $this->pendingRequest->getAttachments();// You can change the attachments of the request here.
    }
}

生成文件URL

使用generateFileUrl方法为位于Telegram服务器上的文件创建链接。

示例

use MohammadZarifiyan\Telegram\Facades\Telegram;

$response = Telegram::perform('getFile', [
    'file_id' => 'abcdefg'// Your file id
]);

if ($response->json('ok')) {
    $file_path = $response->json('result.file_path');
    $file_url = Telegram::generateFileUrl($file_path);
    // You can use $file_url to download the file.
}
else {
    $error = $response->json('description');
    // There was an error receiving file information. You can use $error to display the error.
}

获取机器人ID

使用getBotId方法获取您设置的API密钥的机器人ID。

示例

.env文件

TELEGRAM_API_KEY=123456:abcdefg
use MohammadZarifiyan\Telegram\Facades\Telegram;

echo Telegram::getBotId();// Output: 123456

配置安全令牌

强烈建议为您的机器人设置安全令牌,以确保通过Telegram webhook发送更新。

默认情况下,您应该在config/services.php文件中添加以下代码。

<?php

return [
    // The rest of your code

    'telegram' => [
        'secure-token' => env('TELEGRAM_SECURE_TOKEN'),
    ],
];

然后,将TELEGRAM_SECURE_TOKEN添加到您的.env文件中。

注意:只允许使用字符A-Z、a-z、0-9、_和-

注意:更改安全令牌后,您必须重新设置机器人的webhook。

自定义仓库

如果您想通过其他方式获取安全令牌,例如数据库,可以创建自己的存储库而不是上述方法。只需创建一个类,并在其中实现MohammadZarifiyan\Telegram\Interfaces\SecureTokenRepository。然后,在telegram.php配置文件中,将secure-token-repository的值设置为您的类地址。

示例

app/Repositories/TelegramSecureTokenRepository.php文件

<?php

namespace App\Repositories;

use MohammadZarifiyan\Telegram\Interfaces\SecureTokenRepository;

class TelegramSecureTokenRepository implements SecureTokenRepository
{
    public function get(): ?string
    {
        return 'abcdefg';// Return your secure token
    }
}

telegram.php 配置文件

<?php

return [
    // The rest of the file

    'secure-token-repository' => \App\Repositories\TelegramSecureTokenRepository::class,// Set your own custom repository

    // The rest of the file
];

处理更新

处理更新可以在不同的步骤中发生,具体取决于您的需求。此方法使您能够实现所需的所有功能,而无需考虑障碍。

开始处理

创建路由后,使用handleRequest方法处理请求。您还可以将请求存储在数据库中,稍后处理。

示例

api.php文件

<?php

use MohammadZarifiyan\Telegram\Facades\Telegram;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::post('telegram-update', function (Request $request) {
   Telegram::handleRequest($request);
});

中间件

如果您想运行一些代码来修改处理更新阻止处理,可以使用Telegram中间件

Telegram中间件在命令处理器和断路器之前运行。如果中间件返回的不是MohammadZarifiyan\Telegram\Update的实例,则会抛出一个MohammadZarifiyan\Telegram\TelegramMiddlewareFailedException的实例,并停止处理Telegram更新。

在Telegram中间件中调用的方法是基于正在处理的Telegram更新类型。

例如,如果更新类型是 callback_query,则调用的方法将是 handleCallbackQuery。如果没有根据更新类型处理 Telegram 更新的特定方法,则在 Telegram 中间件中调用名为 handle 的方法。

handlehandleCallbackQuery 都会将 MohammadZarifiyan\Telegram\Update 的实例作为第一个参数接收。

注意,handleCallbackQuery 只是一个示例,方法名将根据更新类型的不同而变化。

要生成新的 Telegram 中间件,请运行以下命令。

php artisan make:telegram-middleware <MiddlewareName>

您应在 telegram.php 配置文件中添加您的 Telegram 中间件。

<?php

return [
    // The rest of the file

    'middlewares' => [
        App\Telegram\Middlewares\YourMiddleware::class,
    ],
    
    // The rest of the file
];

Telegram 中间件将按照在 telegram.php 配置文件中的顺序执行。

命令处理器

用户发送到您的机器人的命令必须由 命令处理器 处理。

Telegram 命令处理器将在所有 Telegram 中间件成功运行后运行。

如果找不到处理用户提交的命令的命令处理器,则会抛出一个 MohammadZarifiyan\Telegram\TelegramCommandNotFoundException 的实例。

您可以通过在 telegram.php 配置文件中将 allow-incognito-command 设置为 true 来禁用抛出异常。

此外,您可以通过调用 $update->isCommand() 来检查 Telegram 更新是否是由于机器人命令而创建的。

要生成新的命令处理器,请运行以下命令。

php artisan make:telegram-command-handler <CommandHandlerName>

您应将您的 Telegram 命令处理器添加到 telegram.php 配置文件中。

<?php

return [
    // The rest of the file

    'command_handlers' => [
        App\Telegram\CommandHandlers\YourCommandHandler::class,
    ],
    
    // The rest of the file
];

命令处理器必须实现 MohammadZarifiyan\Telegram\Interfaces\CommandHandler 接口,其外观如下所示

<?php

namespace App\Telegram\CommandHandlers;

use MohammadZarifiyan\Telegram\Interfaces\CommandHandler;
use MohammadZarifiyan\Telegram\Update;

class StartCommandHandler implements CommandHandler
{
    /**
     * The signature(s) of the Telegram bot command that can be handled by current CommandHandler.
     *
     * @param Update $update
     * @return string|array
     */
    public function getSignature(Update $update): string|array
    {
        return 'start';
    }
    
    /**
     * Handles the Telegram command.
     *
     * @param Update $update
     */
    public function handle(Update $update)
    {
        // Handle command here
    }
}

getSignature 方法必须返回 handle 方法可以处理的命令或命令的名称。

有时,Telegram 更新会带有命令参数。

您可以通过调用 toCommand 方法来访问 Telegram 机器人命令数据。然后,您将收到一个 MohammadZarifiyan\Telegram\Interfaces\Command 的实例。

例如,如果您的 Telegram 机器人用户名是 MyAwesomeBot,则您可以在您的 /start 命令中添加一个参数:https://t.me/MyAwesomeBot?start=abc

$command = $update->toCommand();

$command->getSignature(); // Returns 'start'
$command->getValue(); // Returns 'abc'

匿名命令处理器

有时您可能想创建一个没有指定签名的命令处理器。此功能主要用于不区分大小写的命令或具有动态签名的命令。为此,您可以在其中创建一个类,并在其中实现 MohammadZarifiyan\Telegram\Interfaces\AnonymousCommandHandler。然后,将您的类的地址添加到 telegram.php 配置文件中的 command_handlers

在匿名命令处理器中,有一个 matchesSignature 方法,您应该在其中检查命令匹配。

<?php

namespace App\Telegram\CommandHandlers;

use MohammadZarifiyan\Telegram\Interfaces\AnonymousCommandHandler;
use MohammadZarifiyan\Telegram\Update;

class MyAnonymousCommandHandler implements AnonymousCommandHandler
{
    /**
     * Checks whether the current CommandHandler can process the command.
     *
     * @param Update $update
     * @return bool
     */
    public function matchesSignature(Update $update): bool
    {
        $signature = $update->toCommand()->getSignature();
        
        return $signature === 'start';
    }
    
    /**
     * Handles the Telegram command.
     *
     * @param Update $update
     */
    public function handle(Update $update)
    {
        // Handle command here
    }
}

断路器

如果更新没有被 CommandHandler 处理,它将继续其路径并到达断路器。一个 断路器 是一个可以基于其类型处理请求的类,但它与 Telegram 中间件不同,不能修改更新。

当执行断路器时调用的方法与 Telegram 中间件完全相同。

断路器应该扩展 MohammadZarifiyan\Telegram\Breaker

如果断路器返回 true,则更新处理停止;否则,将执行下一个断路器。您还可以在您的断路器中使用 stop 方法停止更新处理。如果您不希望通过后续的断路器或阶段停止更新处理,则应返回 false 或其他非 true 值。类似地,您也可以通过在您的 Telegram 断路器中调用 continue 方法来达到相同的结果。

请注意,拥有过多的 Telegram 中间件和断路器可能会降低您的 Telegram 机器人的性能。

要生成一个新的断路器,请运行以下命令。

php artisan make:telegram-breaker <BreakerName>

您应该将您的Telegram断路器添加到telegram.php配置文件中。

<?php

return [
    // The rest of the file

    'breakers' => [
        App\Telegram\Breakers\YourBreaker::class,
    ],
    
    // The rest of the file
];

示例

以下示例中,我们处理与内联按钮取消发送通知所有用户相关的所有回调查询更新。

<?php

namespace App\Telegram\Breakers;

use MohammadZarifiyan\Telegram\Breaker;
use MohammadZarifiyan\Telegram\Update;

class CancelBulkNotificationBreaker extends Breaker
{
   public function handleCallbackQuery(Update $update): bool
   {
      if ($update->input('callback_query.data') === 'cancel-sending-all-notifications') {
         // Cancel sending notifications

         /*
          * Stop processing request by other Telegram breakers,
          * Because we already handled the Update and the is no need to continue processing this Update in our application
          */
         return $this->stop();
      }
      else {
         /*
          * Continue processing the Telegram Update using other Telegram Breakers or Telegram Stages,
          * Because this Telegram breaker could was not able to handle the Telegram update
          */
         return $this->continue();
      }
   }
}

增益器

您可能希望在您的应用程序中访问类似Illuminate\Support\Facades\Request::user()的内容,以与数据库交互有关当前更新。此功能已在本包中提供。只需在app/Telegram中创建一个名为GainerResolver的类,并在其中实现MohammadZarifiyan\Telegram\Interfaces\GainerResolver接口。然后,在telegram.php配置文件中设置您创建的类的名称。

telegram.php 配置文件

<?php

return [
    // The rest of the file

    'gainer-resolver' => \App\Telegram\GainerResolver::class,// Set your own class name

    // The rest of the file
];

通过使用$update->gainer(),您可以在整个应用程序中访问GainerResolver.php中的handle方法返回的值。

示例

app/Models/User.php文件

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected $fillable = ['telegram_id'];

    protected $casts = [
        'telegram_id' => 'integer',
    ];
}

app/Telegram/GainerResolver.php文件

<?php

use App\Models\User;
use MohammadZarifiyan\Telegram\Update;
use MohammadZarifiyan\Telegram\Interfaces\GainerResolver as GainerResolverInterface;

class GainerResolver implements GainerResolverInterface
{
    public function handle(Update $update)
    {
        if ($update->type() === 'message') {
            return User::firstOrCreate([
                'telegram_id' => $update->input('message.from.id')
            ]);
        }
        
        return null;
    }
}
use MohammadZarifiyan\Telegram\Facades\Telegram;
use App\Models\User;

$update = Telegram::getUpdate();
$gainer = $update->gainer();

if ($gainer instanceof User) {
    echo 'The user became a member of the bot on date ' . $gainer->created_at;
}
else {
    echo 'The $gainer value is null.';
}

阶段

一些机器人具有交互模式,允许用户在接收到新的Telegram更新时访问新功能。例如,当用户在键盘上点击按钮时,会显示一组新的按钮,用户只能在点击初始按钮后与之交互。此功能在引导用户通过信息收集阶段的机器人中很常见。为了实现此功能,您需要保存一个检查用户下一个更新的阶段,以便在下一个更新到达时执行相应的阶段代码。幸运的是,此包大大简化了此过程。阶段类具有类似于中间件断路器类的类似方法。这些方法处理机器人更新;例如,handleMessage方法管理由在机器人聊天中发送消息触发的更新。为了利用此功能,为您的增益器定义一个模型,将一个阶段列添加到数据库表中,并将应该处理下一个更新的完全限定类名存储在阶段列中。最后,在您的增益器模型中实现MohammadZarifiyan\Telegram\Interfaces\Gainer接口。

要创建一个阶段,请运行以下命令

php artisan make:telegram-stage <StageName>

上述命令将在路径app/Telegram/Stages中创建一个文件。

更新验证和授权

您可以在阶段内的更新处理方法中验证更新。更新验证类似于Laravel中的FormRequest。为了验证更新,您必须创建一个扩展MohammadZarifiyan\Telegram\FormUpdate的类,并将其用作阶段类中更新处理方法的第一个参数。如果验证失败,将抛出类型为MohammadZarifiyan\Telegram\Exceptions\TelegramValidationException的异常。您可以在app/Exceptions/Handler.php文件中捕获TelegramValidationException并将验证错误发送给用户。

您还可以使用authorize方法。如果此方法的输出为false,将抛出类型为MohammadZarifiyan\Telegram\Exceptions\TelegramAuthorizationException的异常。您可以在app/Exceptions/Handler.php文件中捕获TelegramAuthorizationException并将授权错误发送给用户。

运行以下命令以创建新的更新

php artisan make:telegram-update <UpdateName>

此命令将在路径app/Telegram/Updates中创建一个文件。

示例

以下示例中,机器人要求用户提供他们的年龄,期望一个介于1到100之间的数字。如果用户发送的不是这个数字,机器人将响应验证错误消息。

用户迁移

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('telegram_id');
            $table->string('stage')->nullable();
            $table->unsignedTinyInteger('age')->nullable();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
};

app\Models/User.php文件

<?php

namespace App\Models;

use MohammadZarifiyan\Telegram\Interfaces\Gainer as GainerInterface;
use MohammadZarifiyan\Telegram\Traits\Gainer;
use Illuminate\Database\Eloquent\Model;

class User extends Model implements GainerInterface
{
    use Gainer;
    
    protected $fillable = [
        'telegram_id',
        'age',
    ];

    protected $casts = [
        'telegram_id' => 'integer',
        'age' => 'integer',
    ];
}

App\Telegram\Stages\Age.php文件

<?php

namespace App\Telegram\Stages;

use App\Telegram\Updates\AgeUpdate;
use MohammadZarifiyan\Telegram\Facades\Telegram;

class Age
{
    public function handleMessage(AgeUpdate $update): void
    {
        $update->gainer()->update([
            'stage' => null,
            'age' => $update->integer('message.text')
        ]);
        
        Telegram::perform('sendMessage', [
            'text' => 'Your age has been saved in the database.',
            'chat_id' => $update->integer('message.chat.id'),
        ]);
    }
}

app\Telegram\Updates\AgeUpdate.php文件

<?php

namespace App\Telegram\Updates;

use MohammadZarifiyan\Telegram\FormUpdate;

class AgeUpdate extends FormUpdate
{
    public function rules(): array
    {
        return [
            'message.text' => ['bail', 'required', 'integer', 'between:1,200']
        ];
    }

    public function attributes(): array
    {
        return [
            'message.text' => 'age'
        ];
    }
}
use MohammadZarifiyan\Telegram\Facades\Telegram;
use App\Telegram\Stages\Age;

$gainer = Telegram::getUpdate()->gainer();
$gainer->update(['stage' => Age::class]);

Telegram::perform('sendMessage', [
    'chat_id' => $gainer->telegram_id,
    'text' => 'How old are you?'
]);

更新流程图

通过查看以下图表,您可以更好地了解更新处理过程。

Handling process