这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
233 changes: 149 additions & 84 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,61 +6,89 @@

<p align="center"><img src="https://user-images.githubusercontent.com/5278175/176997422-79e5c4c1-ff43-438e-b30e-651bb8e17bcf.png" alt="Dialogs" width="400"></p>

# Dialogs plugin for Telegram Bot API PHP SDK

The extension for [Telegram Bot API PHP SDK](https://github.com/irazasyed/telegram-bot-sdk) v3.1+ that allows to implement dialogs for telegram bots.


## About this fork
# Dialogs Plugin for Telegram Bot API PHP SDK

A powerful extension for [Telegram Bot API PHP SDK](https://github.com/irazasyed/telegram-bot-sdk) v3.1+ that enables dialog-based interactions in your Telegram bots.

## Table of Contents
- [About](#about)
- [Features](#features)
- [Installation](#installation)
- [Laravel Integration](#laravel-integration)
- [Framework-agnostic Usage](#framework-agnostic-usage)
- [Basic Usage](#basic-usage)
- [Creating a Dialog](#creating-a-dialog)
- [Setting up Commands](#setting-up-commands)
- [Controller Setup](#controller-setup)
- [Advanced Usage](#advanced-usage)
- [Dialog Class API](#dialog-class-api)
- [DialogManager API](#dialogmanager-api)
- [Testing](#testing)
- [Contributing](#contributing)
- [License](#license)
- [Roadmap](#roadmap)

## About

This package is a maintained fork of the original Telegram Bot Dialogs package, updated to support Telegram Bot API PHP SDK v3, PHP 8+, and modern Laravel features. Our focus is on stability, developer experience, and code readability.

### Why This Fork?

The Original package [is not maintained anymore](https://github.com/koot-labs/telegram-bot-dialogs/commit/e9c7667e56e419a7053125b40c473ce4b8d7f9c8) and does not support Telegram Bot API PHP SDK v3.
The goal of the fork is to maintain the package compatible with the latest [Telegram Bot API PHP SDK](https://github.com/irazasyed/telegram-bot-sdk),
PHP 8+ and Laravel features, focus on stability, better DX and readability.

## Features

- Framework-agnostic design with enhanced Laravel support
- Dialog-based conversation flow management
- State persistence between messages
- Flexible step navigation
- Support for multiple active dialogs

## Scope of the package

Any bot app basically listens to Updates from Telegram API
(using your webhook endpoint or by pulling these updates on any trigger, e.g. cron) and sends messages back.
(using your webhook endpoint or by pulling these updates on any trigger, like cron) and sends messages back.

This package helps to implement a dialog mode for your bot:
For a given Update, check whether the Update belongs to an already activated Dialog and if there is, run the next step of the Dialog.
for a given Update, check whether the Update belongs to an already activated Dialog and if there is, run the next step of the Dialog.

This package doesn't solve the problem to activate Dialogs for a given Update—you need to implement this logic in your app.
Different apps may have different strategies to activate Dialogs (e.g. by commands, by message content, by user_id, etc.).
This package doesn't solve the task to activate Dialogs for a given Update—you need to implement this logic in your app.
Different apps may have different strategies to activate Dialogs
(e.g. by commands, by message content, by message type, by user_id, etc.).
The package provides an API to activate Dialogs and run the next step for the active Dialog.


## Installation

You can install the package via Composer:
Install via Composer:

```shell
composer require koot-labs/telegram-bot-dialogs
```

### Laravel
While this [**package is framework-agnostic**](./docs/using-without-framework.md):
there are some additional features for Laravel.
### Laravel Integration

1. The package automatically registers `\KootLabs\TelegramBotDialogs\Laravel\DialogsServiceProvider`

1. It automatically registers the service provider `\KootLabs\TelegramBotDialogs\Laravel\DialogsServiceProvider`
2. You can publish the config file with:
```shell
php artisan vendor:publish --tag="telegram-config"
```
It will create `config/telegram.php` file that uses the following env variables:
- `TELEGRAM_DIALOGS_CACHE_DRIVER`: `database` is default value
- `TELEGRAM_DIALOGS_CACHE_PREFIX`: `tg_dialog_` is default value
2. Publish the configuration:
```shell
php artisan vendor:publish --tag="telegram-config"
```

## Usage
This creates `config/telegram.php` with these environment variables:
- `TELEGRAM_DIALOGS_CACHE_DRIVER` (default: `database`)
- `TELEGRAM_DIALOGS_CACHE_PREFIX` (default: `tg_dialog_`)

1. Create a Dialog class
2. [Create a Telegram command](https://telegram-bot-sdk.com/docs/guides/commands-system) to activate Dialog from the Command.
3. Setup your controller class to process active Dialog on income webhook request.
### Framework-agnostic Usage

For non-Laravel applications, see our [framework-agnostic guide](./docs/using-without-framework.md).

### 1. Create a Dialog class
## Basic Usage

Each dialog should be implemented as class that extends basic `Dialog` as you can see in [HelloExampleDialog](https://github.com/koot-labs/telegram-bot-dialogs/blob/master/src/Dialogs/HelloExampleDialog.php) or the code bellow:
### 1. Creating a Dialog

Create a dialog class extending `Dialog`:

```php
use KootLabs\TelegramBotDialogs\Dialog;
Expand All @@ -69,7 +97,7 @@ use Telegram\Bot\Objects\Update;
final class HelloDialog extends Dialog
{
/** @var list<string> List of method to execute. The order defines the sequence */
protected array $steps = ['sayHello', 'sayOk',];
protected array $steps = ['sayHello', 'sayOk'];

public function sayHello(Update $update): void
{
Expand All @@ -91,108 +119,145 @@ final class HelloDialog extends Dialog
}
```

### 2. Create a Telegram command
### 2. Setup Webhook Handler

> [!IMPORTANT]
> Note, Telegram command is just one of examples of triggers that can activate Dialog.
> You can use any other trigger to activate Dialog (e.g. by message content, by user_id, etc.).
> If a user already initiated a chat with your bot,
> you can activate a Dialog anytime from your server (e.g. by cron), see `\KootLabs\TelegramBotDialogs\Objects\BotInitiatedUpdate`.
In this example, the Dialog is activated by a command.
You can also activate dialogs based on other triggers (like an Update/Message type, or a work inside a Message).

To initiate a dialog please use `DialogManager` (or, if you use Laravel, `Dialogs` Facade) — it will care about storing and recovering `Dialog` instance state between steps/requests.
To execute the first and next steps please call `Dialogs::proceed()` method with update object as an argument.
Also, it is possible to use dialogs with Telegram commands and DI through type hinting.
#### 2.1. Setting up a Telegram Command
Create a command to activate your dialog (Laravel example):

```php
use App\Dialogs\HelloExampleDialog;
use App\Dialogs\HelloDialog;
use KootLabs\TelegramBotDialogs\Laravel\Facades\Dialogs;
use Telegram\Bot\Commands\Command;

final class HelloCommand extends Command
{
/** @var string Command name */
protected $name = 'hello';

/** @var string Command description */
protected $description = 'Just say "Hello" and ask few questions in a dialog mode.';
protected $description = 'Start a hello dialog';

public function handle(): void
{
Dialogs::activate(new HelloExampleDialog($this->update->getChat()->id));
Dialogs::activate(new HelloDialog($this->update->getChat()->id));
}
}
```

#### 2.2. Webhook Handler Setup

### 3. Setup your controller

Process request inside your Laravel webhook controller:
Handle webhook updates in your controller:

```php
use Telegram\Bot\BotsManager;
use KootLabs\TelegramBotDialogs\DialogManager;

final class TelegramWebhookController
final class TelegramWebhookHandler
{
public function handle(DialogManager $dialogs, BotsManager $botsManager): void
{
// Find a \Telegram\Bot\Commands\Command instance for the Update and execute it
// for /hello command, it should call HelloCommand that will activate HelloDialog
$update = $bot->commandsHandler(true);

$dialogs->exists($update)
? $dialogs->proceed($update) // proceed an active dialog (activated in HelloCommand)
: $botsManager->sendMessage([ // fallback message
$dialogs->hasActiveDialog($update)
? $dialogs->processUpdate($update) // Run the next step of the active dialog
: $botsManager->sendMessage([ // send a fallback message
'chat_id' => $update->getChat()->id,
'text' => 'There is no active dialog at this moment. Type /hello to start a new dialog.',
'text' => 'No active dialog. Type /hello to start.',
]);
}
}
```

### `Dialog` class API
## Advanced Usage

- `isEnd()` - Check the end of the dialog
- 🔐 `end()` - End dialog
- 🔐 `nextStep(string $stepName)` - Jump to the particular step, where `$step` is the `public` method name
- 🔐 `memory` - Laravel Collection to store intermediate data between steps
### Dialog Class API

```php
abstract class Dialog
{
// Navigation
public function nextStep(string $stepName): void;
public function switchToStep(string $stepName): void;
public function complete(): void;

// State Management
public function isAtStart(): bool;
public function isLastStep(): bool;
public function isComplete(): bool;

// Lifecycle Hooks
protected function beforeEveryStep(Update $update, int $stepIndex): void;
protected function afterEveryStep(Update $update, int $stepIndex): void;
protected function beforeFirstStep(Update $update): void;
protected function afterLastStep(Update $update): void;

// Properties Access
public function getChatId(): int;
public function getUserId(): ?int;
public function ttl(): int;
}
```

### `DialogManager` class API
### DialogManager API

`DialogManager` is in charge of:
- storing and recovering Dialog instances between steps/requests
- running Dialog steps (using Dialog public API)
- switching/activating Dialogs
The `DialogManager` handles:
- Dialog instance persistence
- Step execution
- Dialog activation and switching

For Laravel apps, the package provides `Dialogs` Facade, that proxies calls to `DialogManager` class.
Laravel users can use the `Dialogs` facade:

`DialogManager` public API:
- `activate(\KootLabs\TelegramBotDialogs\Dialog $dialog)` - Activate a new Dialog (without running it). The same user/chat may have few open Dialogs, DialogManager should know which one is active.
- `proceed(\Telegram\Bot\Objects\Update $update)` - Run the next step handler for the active Dialog (if exists)
- `exists(\Telegram\Bot\Objects\Update $update)` - Check for existing Dialog for a given Update (based on chat_id and optional user_id)
- `setBot(\Telegram\Bot\Api $bot)` - Use non-default Bot for Telegram Bot API calls
```php
use KootLabs\TelegramBotDialogs\Laravel\Facades\Dialogs;

// Activate a dialog
Dialogs::activate($dialog);

// Process an update
Dialogs::processUpdate($update);

// Check for active dialog
Dialogs::hasActiveDialog($update);

// Set custom bot instance
Dialogs::setBot($bot);
```

## Contributing

Contributions are welcome!
Please see our [Contributing Guide](CONTRIBUTING.md) for details.

### Testing

## ToDo
Run the test suite:

Tasks to do for v1.0:
```shell
composer test
```

## License

This package is open-sourced software licensed under the [MIT license](LICENSE).

## Roadmap

Tasks planned for v1.0:

- [x] Add documentation and examples
- [x] Support for channel bots
- [ ] Improve test coverage
- [ ] Improve developer experience (cleaner API (similar method in `Dialog` and `DialogManager`))
- [x] Improve test coverage
- [x] Improve developer experience
- [ ] Reach message type validation
- [ ] Reach API to validate message types and content
- [ ] Support `\Iterator`s and/or `\Generator`s for Dialog steps


## Backward compatibility promise

The package uses [Semver 2.0](https://semver.org/). This means that versions are tagged with MAJOR.MINOR.PATCH.
Only a new major version will be allowed to break backward compatibility (BC).
## Backward Compatibility Promise

Classes marked as `@experimental` or `@internal` are not included in our backward compatibility promise.
You are also not guaranteed that the value returned from a method is always the same.
You are guaranteed that the data type will not change.
We follow [Semver 2.0](https://semver.org/). Breaking changes are only introduced in major versions.

PHP 8 introduced [named arguments](https://wiki.php.net/rfc/named_params), which increased the cost and reduces flexibility for package maintainers.
The names of the arguments for methods in the package are not included in our BC promise.
**Note:**
- Classes marked `@experimental` or `@internal` are not covered by BC promise
- Return value consistency is not guaranteed, only data types
- Argument names (for PHP 8.0+ named arguments) are not part of BC promise
Loading