PHP code example of afaztech / reactor

1. Go to this page and download the library: Download afaztech/reactor library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

afaztech / reactor example snippets



namespace App\Handlers;

use Reactor\Attributes\Text;
use Reactor\Attributes\OnUpdate;
use Reactor\Attributes\Group;

#[Group('private')]
#[Text(name: '/start', isCommand: true, priority: 100)]
#[Text(name: '/restart', isCommand: true, priority: 90)]
#[OnUpdate('message')]
class StartHandler extends BaseHandler
{
    protected function handle(array $params = []): void
    {
        $user = $this->extractUser($this->update);
        if (!$user) {
            return;
        }

        $lang = $this->getUserLanguage();
        $text = $this->language->get('start_message', $lang);
        $keyboard = (new \App\Keyboard($this->language))->mainMenu($lang);

        $this->reply($text, $keyboard);
    }
}


namespace App\Handlers;

use Reactor\Attributes\Text;
use Reactor\Attributes\OnUpdate;
use Reactor\Attributes\Group;

#[Group('private')]
#[Text(name: 'about', priority: 5)]
#[OnUpdate('message')]
class AboutHandler extends BaseHandler
{
    protected function handle(array $params = []): void
    {
        $lang = $this->getUserLanguage();
        $text = $this->language->get('about_text', $lang);
        $keyboard = (new \App\Keyboard($this->language))->mainMenu($lang);

        $this->reply($text, $keyboard);
    }
}


namespace App\Handlers;

use Reactor\Attributes\Callback;
use Reactor\Attributes\OnUpdate;
use Reactor\Attributes\Group;

#[Group('private')]
#[Callback(data: 'cancel', priority: 10)]
#[OnUpdate('callback_query')]
class CancelHandler extends BaseHandler
{
    protected function handle(array $params = []): void
    {
        $this->reply('Cancelled.');
    }
}

#[Callback(data: 'item', pattern: '/^item:(\d+)$/', priority: 20)]

protected function handle(array $params = []): void
{
    $itemId = $params[0] ?? null;
    $this->reply("You selected item #{$itemId}");
}


namespace App\Handlers\Steps;

use Reactor\Attributes\Step;
use Reactor\Attributes\OnUpdate;

#[Step(name: 'awaiting_name', nextStep: 'awaiting_email', autoClear: false)]
#[OnUpdate('message')]
class AwaitingNameStep extends BaseHandler
{
    protected function handle(array $params = []): void
    {
        $userId = $this->getUserId();
        $name = trim($this->update['message']['text'] ?? '');

        $this->userRepository->setTemp($userId, ['name' => $name]);
        $this->userRepository->setStep($userId, 'awaiting_email');

        $this->reply("Thanks, {$name}! What's your email?");
    }
}


namespace App\Handlers;

use Reactor\Attributes\Fallback;

#[Fallback(priority: 0)]
class FallbackHandler extends BaseHandler
{
    protected function handle(array $params = []): void
    {
        $lang = $this->getUserLanguage();
        $this->reply($this->language->get('unknown_command', $lang));
    }
}


namespace App\Handlers\Admin;

use Reactor\Attributes\Text;
use Reactor\Attributes\OnUpdate;
use App\Handlers\BaseHandler;

#[Text(name: '/ping_admin', isCommand: true, priority: 50)]
#[OnUpdate('message')]
class PingHandler extends BaseHandler
{
    protected function handle(array $params = []): void
    {
        $this->reply('pong from admin subfolder');
    }
}

interface MiddlewareInterface
{
    public function handle(array $update): bool;
}


namespace App\Middleware;

use Reactor\Attributes\Middleware;
use Reactor\Attributes\OnUpdate;
use Reactor\Enums\MiddlewareMode;
use Reactor\Core\Config;
use Reactor\Contracts\LoggerInterface;
use Reactor\Contracts\MiddlewareInterface;

#[Middleware(priority: 10, mode: MiddlewareMode::GLOBAL)]
#[OnUpdate('any')]
class LogMiddleware implements MiddlewareInterface
{
    protected LoggerInterface $logger;
    protected Config $config;

    public function __construct(LoggerInterface $logger, Config $config)
    {
        $this->logger = $logger;
        $this->config = $config;
    }

    public function handle(array $update): bool
    {
        if ($this->config->isDebugMode()) {
            $this->logger->debug('Message received', $update);
        } else {
            $fromId = $update['message']['from']['id']
                ?? $update['callback_query']['from']['id']
                ?? null;
            $this->logger->info('Update received', [
                'type'    => array_key_first($update) ?: 'unknown',
                'user_id' => $fromId,
            ]);
        }
        return false;
    }
}

use Reactor\Enums\MiddlewareMode;

#[Middleware(priority: 50, mode: MiddlewareMode::GLOBAL)]
#[Middleware(priority: 50, mode: MiddlewareMode::GROUP, groups: ['admin'])]
#[Middleware(priority: 50, mode: MiddlewareMode::LOCAL)]

#[OnUpdate('message')]
#[OnUpdate('message,callback_query')]
#[OnUpdate(['message', 'edited_message'])]
#[OnUpdate('any')]

public function __construct(
    LoggerInterface $logger,
    Config $config,
    UserRepositoryInterface $users
) { ... }

public function mainMenu(?string $lang = null): array
{
    $lang = $lang ?? $this->language->getDefaultLanguage();
    $kb = new KeyboardBuilder();
    $kb->row(
        $this->language->get('start', $lang),
        $this->language->get('about', $lang)
    );
    return $kb->resize(true)->oneTime(false)->build();
}

public function backButton(?string $lang = null): array

public function customMenu(array $buttons, ?string $lang = null): array

$keyboard = (new Keyboard($this->language))->mainMenu($lang);
$this->reply('Hello!', $keyboard);

$keyboard = [
    'inline_keyboard' => [
        [
            ['text' => 'Confirm', 'callback_data' => 'confirm'],
            ['text' => 'Cancel',  'callback_data' => 'cancel'],
        ],
    ],
];
$this->reply('Are you sure?', $keyboard);

class User extends Model
{
    protected $table = 'users';

    protected $fillable = [
        'user_id', 'username', 'first_name', 'last_name',
        'language', 'step', 'temp',
    ];

    protected $casts = [
        'user_id' => 'integer',
        'status'  => 'boolean',
        'temp'    => 'array',   // JSON → array automatically
    ];
}


namespace App\Migrations;

use Reactor\Database\Migrations\Migration;
use Reactor\Contracts\DatabaseManagerInterface;

class CreateUsersTable extends Migration
{
    public function __construct(DatabaseManagerInterface $db)
    {
        parent::__construct($db);
    }

    public function up(): void
    {
        if (!$this->db->schema()->hasTable('users')) {
            $this->db->schema()->create('users', function ($table) {
                $table->increments('id');
                $table->bigInteger('user_id')->unique();
                $table->string('username', 64)->nullable();
                $table->string('first_name', 64)->nullable();
                $table->string('last_name', 64)->nullable();
                $table->boolean('status')->default(true);
                $table->string('step', 255)->nullable();
                $table->json('temp')->nullable();
                $table->string('language', 10)->default('en');
                $table->timestamps();
            });
        }
    }

    public function down(): void
    {
        $this->db->schema()->dropIfExists('users');
    }
}


namespace Reactor\Seeders;

use Reactor\Database\Seeders\Seeder;

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        // Insert initial data.
    }
}

$db = $container->get(DatabaseManagerInterface::class);

$db->table('users')->where('user_id', $id)->update(['step' => null]);
$db->transaction(function () use ($db) {
    // ...
});

User::where('user_id', $id)->first();
User::updateOrCreate(['user_id' => $id], ['username' => $username]);


namespace App\Jobs;

use Reactor\Queue\BaseJob;
use Reactor\Contracts\JobInterface;

class SendMessageJob extends BaseJob implements JobInterface
{
    public function handle(array $data): void
    {
        $chatId   = $data['chatId']   ?? null;
        $text     = $data['text']     ?? '';
        $keyboard = $data['keyboard'] ?? null;

        if ($chatId === null) {
            $this->logger->warning('SendMessageJob skipped: missing chatId', ['data' => $data]);
            return;
        }

        $this->client->sendMessage($chatId, $text, $keyboard);
        $this->logger->info("Delayed message sent to {$chatId}");
    }
}

$queue = $container->get(QueueManager::class);

$queue->push(SendMessageJob::class, [
    'chatId' => 123456789,
    'text'   => 'Hello from the queue!',
], queue: 'default', delay: 60);

$lang = $this->getUserLanguage();
$text = $this->language->get('start_message', $lang);

// With placeholders
$text = $this->language->get('blocked', $lang, ['duration' => 30]);

User::where('user_id', $userId)->update(['language' => 'fa']);


Reactor\Core\App;

$basePath = __DIR__ . '/..';
$appProviders = [ \App\Providers\AppServiceProvider::class ];
$app = new App($basePath, [], [], $appProviders);

$client = $app->getClient();
$logger = $app->getLogger();
$config = $app->getConfig();

$secret = $config->getWebhookSecret();

try {
    $update = $client->handleUpdate($secret);
    if (!empty($update)) {
        $app->processUpdate($update);
    }
} catch (\Throwable $e) {
    $logger->error("Webhook error: " . $e->getMessage());
}
bash
php reactor.php migrate
bash
php reactor.php start
bash
php reactor.php make:step AwaitingNameStep
bash
php reactor.php make:handler EchoHandler
bash
php reactor.php make:middleware AuthMiddleware
bash
php reactor.php seed
bash
php reactor.php seed --class="Reactor\Seeders\DatabaseSeeder"
bash
php reactor.php queue:work --queue=default --max=10
nginx
server {
    listen 443 ssl http2;
    server_name your-domain.com;

    root /var/www/my-bot/public_html;
    index webhook.php;

    location / {
        try_files $uri /webhook.php?$query_string;
    }

    location ~ \.php$ {
        
bash
php reactor.php <command> [options] [arguments]
cron
* * * * * cd /var/www/my-bot && php reactor.php schedule:run >> /dev/null 2>&1
env
MULTI_PROCESS=true
PHP_BINARY=/usr/bin/php
ini
[Unit]
Description=My Telegram Bot Queue Worker
After=network.target mysql.service

[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/my-bot
ExecStart=/usr/bin/php /var/www/my-bot/reactor.php queue:work --max=1000
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target