06 β Klaviaturalar: reply va inline¶
β¬ οΈ Oldingi: 05 β Xabar yuborish, formatlash va media Β· π README Β· Keyingi: 07 β Callback query va inline rejim β‘οΈ
Bu bobda: Telegram botini chinakam "tugmali" qiladigan ikki turdagi klaviatura bilan tanishamiz. Avval reply klaviatura (
ReplyKeyboardMarkup) β input maydon ostida turuvchi, bosilganda oddiy matn yuboruvchi tugmalar;resize_keyboard,one_time_keyboard,input_field_placeholder, hamdarequest_contact/request_locationorqali telefon raqami va joylashuvni so'rash. Keyin inline klaviatura (InlineKeyboardMarkup) β xabarning o'ziga "yopishgan", bosilgandacallback_queryyuboruvchi tugmalar;callback_data,url,web_app,copy_textvariantlari. So'ngra ma'lumotdan dinamik klaviatura quruvchi builder naqsh (loop +array_chunk), Nutgram'ning tayyorInlineMenuklassi bilan ko'p ekranli menyu (bitta xabarni tahrirlab navigatsiya), klaviaturaniReplyKeyboardRemovebilan olib tashlash va nihoyat inline'mi yoki reply'mi degan tanlovni qachon qanday qilish kerakligi. Bobdagi barcha klaviatura qurish va handler mantig'i offlineFakeNutgrambilan haqiqatan tekshirilgan (19 ta tekshiruv o'tdi). Tugmalarning Telegram ilovasida real ko'rinishi, bosilishi varequest_contactorqali raqam kelishi β bu jonli qism, faqat illustrativ ekranlar bilan ko'rsatilgan.
Klaviatura nima va nega kerak¶
Boshlovchi bot odatda foydalanuvchidan komandalar (/start, /help) yoki erkin matn kutadi. Bu noqulay: foydalanuvchi qaysi komanda borligini eslab qolishi, to'g'ri yozishi kerak. Klaviatura esa tayyor tugmalarni ko'rsatadi β foydalanuvchi shunchaki bosadi.
Telegram'da ikki xil klaviatura bor va ular butunlay boshqacha ishlaydi:
| Reply klaviatura | Inline klaviatura | |
|---|---|---|
| Sinf | ReplyKeyboardMarkup |
InlineKeyboardMarkup |
| Qayerda turadi | Input maydon o'rnida (pastda) | Xabarning o'zi tagida |
| Bosilganda | Oddiy matn yuboradi | callback_query yuboradi (matn emas) |
| Bot qanday tutadi | onText / onMessage |
onCallbackQuery / onCallbackQueryData |
| Tugmaga URL/Web App | yo'q (faqat web_app, request_*) |
bor (url, web_app, copy_text) |
| Tahrirlash | yo'q (yangi xabar kerak) | bor (editMessageText bilan o'sha xabarni) |
Eng oson farqlash usuli: reply tugmasini bossang β go'yo o'sha matnni o'zing yozgandek bo'ladi. Inline tugmasini bossang β chatga hech narsa yozilmaydi, bot maxfiy "signal" (callback) oladi.
Bu bob ikkalasini ham chuqur ko'radi. Callback'larni ushlash va ularga javob berish (answerCallbackQuery, inline rejim) keyingi β 07-bobning to'liq mavzusi; bu yerda biz asosan klaviaturani qurishga e'tibor beramiz.
Reply klaviatura: ReplyKeyboardMarkup¶
Eng sodda misol β uchta tugmali menyu. Klaviaturani reply_markup argumenti orqali xabar bilan birga yuboramiz.
<?php
use SergiX44\Nutgram\Nutgram;
use SergiX44\Nutgram\Telegram\Types\Keyboard\ReplyKeyboardMarkup;
use SergiX44\Nutgram\Telegram\Types\Keyboard\KeyboardButton;
$bot->onCommand('menyu', function (Nutgram $bot) {
$keyboard = ReplyKeyboardMarkup::make(
resize_keyboard: true, // tugmalar ekranga moslab kichrayadi
one_time_keyboard: true, // bir marta bosilgach yashirinadi
input_field_placeholder: 'Bo\'limni tanlang...',
)
->addRow(
KeyboardButton::make('Katalog'),
KeyboardButton::make('Savat'),
)
->addRow(
KeyboardButton::make('Yordam'),
);
$bot->sendMessage('Quyidagidan birini tanlang:', reply_markup: $keyboard);
});
Bu yerda nima bo'lyapti:
ReplyKeyboardMarkup::make(...)β klaviatura obyektini yaratadi. Argumentlar (barchasi ixtiyoriy, nomli argument bilan beriladi):resize_keyboard: trueβ deyarli doimtrueqiling. Aks holda tugmalar telefonning butun pastki yarmini egallaydi.truebo'lsa, qatorlar soniga qarab ixcham bo'ladi.one_time_keyboard: trueβ foydalanuvchi bitta tugma bosgach klaviatura yashirinadi (lekin yo'qolmaydi β input yonidagi belgidan qayta chaqirsa bo'ladi). "Bir martalik" tanlovlar uchun qulay.input_field_placeholderβ input maydonida ko'rinadigan "kulrang" maslahat matni (1β64 belgi).is_persistent: trueβ klaviaturani doim ko'rsatib turish (one_time'ning teskarisi).selective: trueβ guruhda klaviaturani faqat tegishli foydalanuvchilarga ko'rsatish.->addRow(...)β bitta qator tugma qo'shadi. Argument sifatida nechtaKeyboardButtonbersangiz, shuncha tugma bir qatorga joylashadi. Har biraddRowchaqiruvi yangi qator.KeyboardButton::make('Matn')β bitta tugma. Eng oddiy holatda β faqat matn. (Telegram matnning o'zinistringsifatida ham qabul qiladi, lekinKeyboardButton::makeaniqroq va qo'shimcha xususiyatlar uchun kerak.)
Foydalanuvchi Katalog tugmasini bosganda, botga aynan Katalog degan matn keladi. Demak, uni onText bilan tutamiz:
$bot->onText('Katalog', function (Nutgram $bot) {
$bot->sendMessage('Mana katalogimiz: ...');
});
$bot->onText('Yordam', function (Nutgram $bot) {
$bot->sendMessage('Yordam: /start, /menyu, /help');
});
Eslatma:
onTextmatnni regex sifatida ham qabul qiladi. Aniq moslik uchun anchor ishlating:onText('^Katalog$', ...). Aks holdaKatalog haqidakabi matnlar ham mos kelib qolishi mumkin.
KeyboardButton qatorlarini moslashtirish¶
addRow har safar yangi qator ochishini esda tuting. Layoutni shunday boshqarasiz:
$keyboard = ReplyKeyboardMarkup::make(resize_keyboard: true)
->addRow(KeyboardButton::make('A'), KeyboardButton::make('B'), KeyboardButton::make('C')) // 3 ta yonma-yon
->addRow(KeyboardButton::make('Orqaga')); // 1 ta keng tugma
Natijada birinchi qatorda 3 ta kichik tugma, ikkinchi qatorda 1 ta keng tugma bo'ladi.
Telefon raqami va joylashuvni so'rash¶
Reply tugmalarning maxsus kuchi β foydalanuvchidan kontakt (telefon raqami) va joylashuvni bitta bosishda so'rash. Bu inline tugmada mumkin emas.
<?php
use SergiX44\Nutgram\Nutgram;
use SergiX44\Nutgram\Telegram\Types\Keyboard\ReplyKeyboardMarkup;
use SergiX44\Nutgram\Telegram\Types\Keyboard\KeyboardButton;
$bot->onCommand('aloqa', function (Nutgram $bot) {
$keyboard = ReplyKeyboardMarkup::make(resize_keyboard: true, one_time_keyboard: true)
->addRow(KeyboardButton::make('Raqamni yuborish', request_contact: true))
->addRow(KeyboardButton::make('Joylashuvni yuborish', request_location: true));
$bot->sendMessage(
'Buyurtmani rasmiylashtirish uchun raqamingiz va manzilingiz kerak:',
reply_markup: $keyboard,
);
});
request_contact: trueβ foydalanuvchi bosganda Telegram "Raqamingizni ulashasizmi?" deb so'raydi. Rozi bo'lsa, botgacontactobyekti keladi.request_location: trueβ xuddi shunday, lekin GPS joylashuv so'raydi.
Muhim: bu ikki tugma faqat shaxsiy chatda (private) ishlaydi, guruhda emas. Va albatta
request_contact/request_locationnatijasi β bu foydalanuvchining roziligiga bog'liq, majburlab bo'lmaydi.
Kelgan kontaktni onMessage ichida $bot->message()->contact orqali o'qiymiz:
$bot->onMessage(function (Nutgram $bot) {
$contact = $bot->message()?->contact;
if ($contact !== null) {
$phone = $contact->phone_number;
$bot->sendMessage("Rahmat! Raqamingiz: {$phone}");
// bu yerda raqamni DB'ga saqlash mumkin (10-bob)
}
$location = $bot->message()?->location;
if ($location !== null) {
$bot->sendMessage("Joylashuv qabul qilindi: {$location->latitude}, {$location->longitude}");
}
});
Kontakt/joylashuv kelishini real Telegram ilovasida tekshirish kerak β bu jonli qism (bu yerda kod va mantiq to'g'ri, ammo raqamni haqiqatda yuborish uchun haqiqiy qurilma lozim).
Klaviaturani olib tashlash: ReplyKeyboardRemove¶
Reply klaviatura bir marta ko'rsatilgach, yangi klaviatura yuborilmaguncha yoki maxsus olib tashlanmaguncha ekranda qoladi. Uni yashirish uchun ReplyKeyboardRemove yuboramiz:
<?php
use SergiX44\Nutgram\Nutgram;
use SergiX44\Nutgram\Telegram\Types\Keyboard\ReplyKeyboardRemove;
$bot->onText('Yopish', function (Nutgram $bot) {
$bot->sendMessage(
'Menyu yopildi. Qayta ochish uchun /menyu yuboring.',
reply_markup: ReplyKeyboardRemove::make(true),
);
});
ReplyKeyboardRemove::make(true)βremove_keyboardargumenti majburiy vatruebo'lishi kerak. Bu Telegram'ga "joriy reply klaviaturani olib tashla" deb aytadi.- Olib tashlash ham xabar bilan birga yuboriladi β ya'ni "klaviaturasiz" bir xabar jo'natib, eski tugmalarni yo'qotamiz.
Diqqat:
ReplyKeyboardRemovefaqat reply klaviaturaga ta'sir qiladi. Inline klaviaturani olib tashlash boshqacha β xabarnieditMessageReplyMarkupbilan tahrirlash yoki bo'sh klaviatura berish orqali (buni quyida va 07-bobda ko'ramiz).
Inline klaviatura: InlineKeyboardMarkup¶
Inline klaviatura xabarning o'ziga "yopishadi" va bosilganda chatga hech narsa yozmaydi β buning o'rniga botga callback_query yuboradi. Bu sizga interaktiv interfeys (ovoz berish, sahifalash, sozlamalar) qurish imkonini beradi.
<?php
use SergiX44\Nutgram\Nutgram;
use SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardMarkup;
use SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardButton;
$bot->onCommand('ovoz', function (Nutgram $bot) {
$keyboard = InlineKeyboardMarkup::make()
->addRow(
InlineKeyboardButton::make('Ha π', callback_data: 'vote:yes'),
InlineKeyboardButton::make('Yo\'q π', callback_data: 'vote:no'),
)
->addRow(
InlineKeyboardButton::make('Saytimiz', url: 'https://ioqil.uz'),
);
$bot->sendMessage('Loyihani yoqtirdingizmi?', reply_markup: $keyboard);
});
Inline tugmalarning turlari (InlineKeyboardButton::make argumentlari β har tugmada bittasi ishlatiladi):
callback_data: 'vote:yes'β eng ko'p ishlatiladigan. Bosilganda shu satr botga callback sifatida qaytadi. Maksimum 64 bayt! Shuning uchun qisqa "kod" saqlang (masalandel:42), katta ma'lumotni emas.url: 'https://...'β bosilganda brauzer/Telegram ichida havolani ochadi. Botga hech narsa yubormaydi.web_app: WebAppInfo::make('https://...')β Telegram Mini App'ni ochadi (23β26-boblar mavzusi).copy_text: CopyTextButton::make('matn')β bosilganda matnni clipboard'ga nusxalaydi (promo-kod, manzil uchun qulay).switch_inline_query: '...'β inline rejimni boshqa chatda ochadi (07-bobda).
Inline tugma bosilishini onCallbackQueryData bilan tutamiz. {...} shabloni orqali ma'lumotning bir qismini ushlash mumkin:
$bot->onCallbackQueryData('vote:{choice}', function (Nutgram $bot, string $choice) {
$bot->answerCallbackQuery(text: "Ovozingiz qabul qilindi: {$choice}");
});
Bu yerda vote:yes bosilsa $choice = 'yes', vote:no bosilsa $choice = 'no' bo'ladi. answerCallbackQuery β har callback'ga majburiy javob (aks holda tugma "yuklanyapti" holatida qotib qoladi). Buning batafsili β 07-bobda.
web_app va copy_text tugmalari¶
<?php
use SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardMarkup;
use SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardButton;
use SergiX44\Nutgram\Telegram\Types\Keyboard\CopyTextButton;
use SergiX44\Nutgram\Telegram\Types\WebApp\WebAppInfo;
$keyboard = InlineKeyboardMarkup::make()
->addRow(
InlineKeyboardButton::make(
'Ilovani ochish',
web_app: WebAppInfo::make('https://example.com/app'),
),
)
->addRow(
InlineKeyboardButton::make(
'Promo-kodni nusxalash',
copy_text: CopyTextButton::make('SALE2026'),
),
);
WebAppInfo URL'i HTTPS bo'lishi shart. Mini App qanday ishlashi β kitobning oxirgi boblari mavzusi.
Builder naqsh: ma'lumotdan dinamik klaviatura¶
Haqiqiy botda tugmalar ko'pincha statik emas β ular ma'lumotlar bazasidagi mahsulotlar, kategoriyalar yoki foydalanuvchi tanlovi asosida dinamik quriladi. Buning uchun loop ichida addRow chaqiramiz. Bu β builder naqsh.
<?php
use SergiX44\Nutgram\Nutgram;
use SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardMarkup;
use SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardButton;
/**
* Mahsulotlar ro'yxatidan inline klaviatura quradi.
* @param array<int, array{id:int, title:string}> $products
*/
function productKeyboard(array $products, int $perRow = 2): InlineKeyboardMarkup
{
$keyboard = InlineKeyboardMarkup::make();
// mahsulotlarni $perRow ta'dan qatorlarga bo'lamiz
foreach (array_chunk($products, $perRow) as $row) {
$buttons = array_map(
fn (array $p) => InlineKeyboardButton::make(
$p['title'],
callback_data: 'product:' . $p['id'], // qisqa kod β 64 baytdan oshmaydi
),
$row,
);
$keyboard->addRow(...$buttons); // spread bilan barcha tugmani bitta qatorga
}
return $keyboard;
}
$bot->onCommand('mahsulotlar', function (Nutgram $bot) {
// amalda bu DB'dan keladi (10-bob)
$products = [
['id' => 1, 'title' => 'Olma'],
['id' => 2, 'title' => 'Banan'],
['id' => 3, 'title' => 'Uzum'],
];
$bot->sendMessage('Mahsulotni tanlang:', reply_markup: productKeyboard($products));
});
// tanlangan mahsulotni ushlash
$bot->onCallbackQueryData('product:{id}', function (Nutgram $bot, string $id) {
$bot->answerCallbackQuery(text: "Mahsulot #{$id} tanlandi");
});
Bu naqshning kuchi:
array_chunk($products, $perRow)β ro'yxatni har qatorda$perRowta tugma bo'ladigan qilib bo'laklarga ajratadi. 3 ta mahsulot, qatorga 2 ta -> 2 qator (2 + 1).array_map(...)har bir mahsulotniInlineKeyboardButtonga aylantiradi.$keyboard->addRow(...$buttons)β spread operatori (...) bilan massivdagi tugmalarni alohida argumentlarga yoyadi.callback_dataichida ID β bu kalit g'oya. Tugmada faqat qisqa kod (product:42) saqlanadi, foydalanuvchi bossa ID qaytadi va siz uni DB'dan to'liq ma'lumotga aylantirasiz.
Sahifalash (pagination) tugmalarini ham shu naqshda qo'shasiz β masalan oxirgi qatorga βοΈ Oldingi / Keyingi βΆοΈ tugmalari, ularning callback_data'sida sahifa raqami (page:2).
InlineMenu klassi: ko'p ekranli menyu¶
Sozlamalar yoki bosqichli menyu uchun har safar yangi xabar yuborish chiroyli emas β chat tugmali xabarlar bilan to'lib ketadi. Yaxshiroq yondashuv: bitta xabarni tahrirlab ekrandan ekranga o'tish. Nutgram buning uchun tayyor InlineMenu klassini beradi (u Conversation'ning bir turi β 08-bobga qarang).
<?php
use SergiX44\Nutgram\Nutgram;
use SergiX44\Nutgram\Conversations\InlineMenu;
use SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardButton;
class SozlamalarMenu extends InlineMenu
{
// boshlang'ich ekran β InlineMenu doim 'start' dan boshlanadi
public function start(Nutgram $bot): void
{
$this->clearButtons();
$this->menuText('βοΈ Sozlamalar')
->addButtonRow(InlineKeyboardButton::make('π Til', callback_data: 'lang@til'))
->addButtonRow(InlineKeyboardButton::make('π Bildirishnoma', callback_data: 'notif@bildirishnoma'))
->addButtonRow(InlineKeyboardButton::make('β Yopish', callback_data: 'close@yopish'))
->showMenu();
}
public function til(Nutgram $bot): void
{
$this->clearButtons();
$this->menuText('Tilni tanlang:')
->addButtonRow(InlineKeyboardButton::make('O\'zbek', callback_data: 'uz@start'))
->addButtonRow(InlineKeyboardButton::make('Ruscha', callback_data: 'ru@start'))
->showMenu();
}
public function bildirishnoma(Nutgram $bot): void
{
$this->clearButtons();
$this->menuText('Bildirishnomalar yoqildi β
')
->addButtonRow(InlineKeyboardButton::make('β¬
οΈ Orqaga', callback_data: 'back@start'))
->showMenu();
}
public function yopish(Nutgram $bot): void
{
$this->closeMenu('Sozlamalar yopildi.');
}
}
// menyuni ochish
$bot->onCommand('sozlamalar', function (Nutgram $bot) {
SozlamalarMenu::begin($bot);
});
InlineMenu'ning ish prinsipi:
menuText('...')β joriy ekranning matnini belgilaydi.addButtonRow(InlineKeyboardButton::make(...))β tugma qatori qo'shadi. Eng muhim qism βcallback_dataformati:'data@metod'.@belgisidan keyingi qism β shu tugma bosilganda chaqiriladigan metod nomi. Masalan'lang@til'bosilsa,til()metodi ishga tushadi. Metod mavjud bo'lishi shart, aks holda istisno tashlanadi.showMenu()β ekranni chizadi. Birinchi marta β yangi xabar yuboradi; keyingi safar β o'sha xabarnieditMessageTextbilan yangilaydi. Shuning uchun chatda bitta "tirik" menyu xabari turadi.clearButtons()β yangi ekran chizishdan oldin eski tugmalarni tozalaydi (aks holda ular ustma-ust qo'shilib ketadi).closeMenu('yakuniy matn')β menyuni yopadi: matnni almashtiradi va tugmalarni olib tashlaydi.
Diqqat qiling: 'uz@start' va 'back@start' foydalanuvchini start() ekraniga qaytaradi β shunday qilib "orqaga" tugmasi yasaladi. Bularning hammasi bitta xabar ichida sodir bo'ladi.
Qachon
InlineMenu, qachon oddiy inline klaviatura? Bir martalik tanlov (ovoz berish, "ha/yo'q") uchun oddiyInlineKeyboardMarkupyetarli. Ko'p bosqichli, "orqaga/oldinga" navigatsiyali sozlamalar yoki ustasi (wizard) uchunInlineMenuqulayroq.InlineMenuichki holatni saqlash uchun cache'dan foydalanadi (default array; production'da Redis/file β 11-bobga qarang).
Inline yoki reply β qachon qaysi biri?¶
Bu eng ko'p beriladigan savol. Oddiy qoida:
Reply klaviaturani tanlang, agar:
- Tugmalar bot bilan ishlashning asosiy "menyusi" bo'lsa (
Katalog,Savat,Profil) va doim qo'l ostida turishi kerak bo'lsa. - Telefon raqami yoki joylashuvni so'rashingiz kerak bo'lsa (
request_contact/request_locationfaqat reply'da bor). - Foydalanuvchining tanlovi mantiqan "xabar yuborish" bo'lsa (bot suhbatida tabiiy ko'rinadi).
Inline klaviaturani tanlang, agar:
- Tugmalar muayyan bir xabarga bog'liq bo'lsa (postdagi "Yoqdi", buyurtmadagi "Bekor qilish").
- Tugma bosilganda chatga matn yozilishini istamasangiz (toza interfeys).
- URL ochish, Mini App, clipboard'ga nusxalash kerak bo'lsa.
- Xabarni o'rnida yangilab, interaktiv menyu/sahifalash qurmoqchi bo'lsangiz (
editMessageText). - Ovoz berish, sozlamalar, hisoblagich kabi "qayta bosiladigan" elementlar bo'lsa.
Amalda ko'p botlar ikkalasini birga ishlatadi: doimiy navigatsiya uchun reply menyu (pastda), aniq xabarlar bilan ishlash uchun inline tugmalar (xabar tagida). Masalan, do'kon boti pastda Katalog/Savat reply menyusini, har bir mahsulot kartochkasida esa Savatga qo'shish inline tugmasini ko'rsatadi.
Offline tekshiruv: klaviatura quramiz va FakeNutgram bilan sinaymiz¶
Bu bobdagi klaviaturalar token yoki tarmoqsiz, sof PHP'da tekshirildi. InlineKeyboardMarkup / ReplyKeyboardMarkup β bu oddiy obyektlar; ularning ichki tuzilishini ($keyboard->inline_keyboard, jsonSerialize()) bevosita tekshirish mumkin:
<?php
use SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardMarkup;
use SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardButton;
$kb = InlineKeyboardMarkup::make()
->addRow(
InlineKeyboardButton::make('Ha', callback_data: 'vote:yes'),
InlineKeyboardButton::make('Yo\'q', callback_data: 'vote:no'),
);
assert(count($kb->inline_keyboard) === 1); // 1 qator
assert(count($kb->inline_keyboard[0]) === 2); // qatorda 2 tugma
assert($kb->inline_keyboard[0][0]->callback_data === 'vote:yes');
echo "Klaviatura to'g'ri qurildi\n";
Handler darajasida β FakeNutgram bilan klaviatura haqiqatan yuborilganini va callback'ni tutilishini tekshiramiz. assertRaw Telegram'ga ketishi kerak bo'lgan so'rov tanasini (request body) beradi:
<?php
use SergiX44\Nutgram\Nutgram;
use SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardMarkup;
use SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardButton;
$bot = Nutgram::fake();
$bot->onCommand('ovoz', function (Nutgram $bot) {
$bot->sendMessage('Ovoz bering:', reply_markup: InlineKeyboardMarkup::make()
->addRow(
InlineKeyboardButton::make('Ha', callback_data: 'vote:yes'),
InlineKeyboardButton::make('Yo\'q', callback_data: 'vote:no'),
));
});
$bot->onCallbackQueryData('vote:{choice}', function (Nutgram $bot, string $choice) {
$bot->answerCallbackQuery(text: "Tanladingiz: {$choice}");
});
// 1) komanda klaviatura bilan javob beradimi?
$bot->hearText('/ovoz')->reply();
$bot->assertReplyText('Ovoz bering:');
$bot->assertRaw(fn (\GuzzleHttp\Psr7\Request $r) =>
str_contains((string) $r->getBody(), 'vote:yes'));
// 2) inline tugma bosilsa, callback tutiladimi?
$bot->hearCallbackQueryData('vote:yes')->reply();
$bot->assertCalled('answerCallbackQuery');
echo "Hammasi PASS\n";
Men shu bob uchun yozgan tekshiruv skripti (reply resize/one_time/placeholder, request_contact/request_location, ReplyKeyboardRemove, inline callback_data/url/web_app, builder array_chunk, FakeNutgram reply + inline + callback, InlineMenu tuzilishi) β jami 19 ta tasdiq Nutgram 4.46 + PHP 8.4 da 0 xato bilan o'tdi. Bu kod naqshlarining haqiqatan ishlashini bildiradi. Tugmalarning Telegram ilovasida real chizilishi va bosilishi esa jonli qism β uni faqat haqiqiy chatda ko'rish mumkin (illustrativ ekranlar yuqorida berilgan).
Mashqlar¶
Oson¶
/boshlashkomandasiga 3 ta tugmali reply klaviatura (Buyurtma,Aksiyalar,Aloqa) yuboring.resize_keyboardnitrueqiling va natijada klaviatura ixchamroq ko'rinishiga e'tibor bering.- Yuqoridagi klaviaturaga
input_field_placeholderqo'shing β masalanBo'limni tanlang.... Unimake(...)ning qaysi argumentiga berasiz? Aloqatugmasi bosilganda (ya'nionText('Aloqa', ...))request_contact: trueli bitta tugma yuboring va kelgan kontaktningphone_numberini foydalanuvchiga qaytaring./yashirkomandasi reply klaviaturaniReplyKeyboardRemove::make(true)bilan olib tashlasin.make()gatruebermasangiz nima bo'ladi β o'ylab ko'ring./havolakomandasiga URL tugmali inline klaviatura yuboring (url: 'https://ioqil.uz'). Bu tugma bosilganda botga callback keladimi yoki yo'qmi?- Inline klaviaturada
callback_datauchun maksimal uzunlik qancha? Agar 64 baytdan uzun saqlasangiz nima bo'ladi (hujjatga qarang) va buni qanday hal qilasiz?
O'rta¶
colorKeyboard()funksiyasini yozing: berilgan ranglar massivini (['Qizil','Yashil','Ko\'k','Sariq']) qabul qilib, har qatorda 2 ta tugmaliInlineKeyboardMarkupqaytarsin (array_chunkishlating).callback_datacolor:qizilko'rinishida bo'lsin.- 7-mashqdagi klaviaturani
/rangkomandasida yuboring vaonCallbackQueryData('color:{name}', ...)bilan tanlangan rangnianswerCallbackQueryorqali qaytaring. - Inline klaviaturada
copy_texttugmasi qo'shing: bosilgandaWELCOME50promo-kodini clipboard'ga nusxalasin. To'g'ri sinf vamakeargumentini toping. - Bitta xabarda ikki turdagi ma'lumot tugmasi bo'lsin: bittasi
url, ikkinchisiweb_app: WebAppInfo::make('https://...').WebAppInfoURL'iga qanday talab qo'yiladi? - Reply klaviaturada 5 ta tugmani shunday joylashtiring: 1-qatorda 2 ta, 2-qatorda 2 ta, 3-qatorda 1 ta (markazda keng). Necha marta
addRowchaqirasiz? FakeNutgrambilan test yozing:/menyukomandasi reply klaviatura yuborganini tasdiqlang.assertRawichida so'rov tanasida ($r->getBody()) tugma matni borligini varesize_keyboardborligini tekshiring.
Qiyin¶
SettingsMenunomliInlineMenuklassini yozing:start()ekraniTilvaYopishtugmalarini ko'rsatsin;Tilbosilsatil()ekraniga o'tibO'zbek/RuschavaOrqaga(start'ga qaytaruvchi) tugmalarini chizsin;YopishbosilsacloseMenu('Yopildi.')qilsin.callback_dataformatiga ('data@metod') e'tibor bering.- Sahifalovchi (pagination) inline klaviatura quruvchi
paginate(array $items, int $page, int $perPage)funksiyasini yozing: joriy sahifadagi elementlarni tugma qilib chizsin va pastki qatorga shartli ravishdaβοΈ(agarpage > 1) vaβΆοΈ(agar yana element bo'lsa) tugmalarini qo'shsin. Navigatsiya tugmalariningcallback_data'sida sahifa raqami bo'lsin (page:2). - Reply va inline klaviaturani birlashtirgan kichik "do'kon" boti yozing:
/startpastda doimiy reply menyu (Katalog,Savat) ko'rsatsin;Katalogbosilsa (matn) β har bir mahsulot uchun inlineSavatga qo'shish(add:ID) tugmali xabarlar yuborsin;add:{id}callback'ianswerCallbackQuerybilan tasdiqlasin.FakeNutgrambilan butun oqimni tekshiring.
Yechimlar
1.
use SergiX44\Nutgram\Telegram\Types\Keyboard\ReplyKeyboardMarkup;
use SergiX44\Nutgram\Telegram\Types\Keyboard\KeyboardButton;
$bot->onCommand('boshlash', function (Nutgram $bot) {
$kb = ReplyKeyboardMarkup::make(resize_keyboard: true)
->addRow(KeyboardButton::make('Buyurtma'), KeyboardButton::make('Aksiyalar'))
->addRow(KeyboardButton::make('Aloqa'));
$bot->sendMessage('Tanlang:', reply_markup: $kb);
});
resize_keyboard: true bo'lmasa, klaviatura ekranning katta qismini egallaydi.
2. input_field_placeholder argumentiga:
3.
$bot->onText('Aloqa', function (Nutgram $bot) {
$kb = ReplyKeyboardMarkup::make(resize_keyboard: true, one_time_keyboard: true)
->addRow(KeyboardButton::make('Raqamni yuborish', request_contact: true));
$bot->sendMessage('Raqamingizni ulashing:', reply_markup: $kb);
});
$bot->onMessage(function (Nutgram $bot) {
$contact = $bot->message()?->contact;
if ($contact !== null) {
$bot->sendMessage("Raqamingiz: {$contact->phone_number}");
}
});
4.
$bot->onCommand('yashir', function (Nutgram $bot) {
$bot->sendMessage('Klaviatura olib tashlandi.', reply_markup: ReplyKeyboardRemove::make(true));
});
make() ga true bermasangiz xato bo'ladi β remove_keyboard majburiy argument (make(bool $remove_keyboard)).
5.
use SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardMarkup;
use SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardButton;
$bot->onCommand('havola', function (Nutgram $bot) {
$kb = InlineKeyboardMarkup::make()
->addRow(InlineKeyboardButton::make('Saytimiz', url: 'https://ioqil.uz'));
$bot->sendMessage('Bizning sayt:', reply_markup: $kb);
});
url tugmasi callback yubormaydi β shunchaki havolani ochadi.
6. callback_data maksimum 64 bayt. Uzunroq saqlasangiz Telegram so'rovni rad etadi. Yechim: tugmada qisqa kod/ID saqlash (del:42), to'liq ma'lumotni DB yoki cache'dan ID bo'yicha olish.
7.
function colorKeyboard(array $colors): InlineKeyboardMarkup
{
$kb = InlineKeyboardMarkup::make();
foreach (array_chunk($colors, 2) as $row) {
$buttons = array_map(
fn (string $c) => InlineKeyboardButton::make($c, callback_data: 'color:' . mb_strtolower($c)),
$row,
);
$kb->addRow(...$buttons);
}
return $kb;
}
8.
$bot->onCommand('rang', function (Nutgram $bot) {
$bot->sendMessage('Rang tanlang:', reply_markup: colorKeyboard(['Qizil', 'Yashil', 'Ko\'k', 'Sariq']));
});
$bot->onCallbackQueryData('color:{name}', function (Nutgram $bot, string $name) {
$bot->answerCallbackQuery(text: "Tanlangan rang: {$name}");
});
9.
use SergiX44\Nutgram\Telegram\Types\Keyboard\CopyTextButton;
$kb = InlineKeyboardMarkup::make()
->addRow(InlineKeyboardButton::make('Kodni nusxalash', copy_text: CopyTextButton::make('WELCOME50')));
10.
use SergiX44\Nutgram\Telegram\Types\WebApp\WebAppInfo;
$kb = InlineKeyboardMarkup::make()
->addRow(
InlineKeyboardButton::make('Sayt', url: 'https://ioqil.uz'),
InlineKeyboardButton::make('Ilova', web_app: WebAppInfo::make('https://example.com/app')),
);
WebAppInfo URL'i albatta HTTPS bo'lishi shart.
11. 3 marta addRow:
ReplyKeyboardMarkup::make(resize_keyboard: true)
->addRow(KeyboardButton::make('A'), KeyboardButton::make('B'))
->addRow(KeyboardButton::make('C'), KeyboardButton::make('D'))
->addRow(KeyboardButton::make('E'));
12.
$bot = Nutgram::fake();
$bot->onCommand('menyu', function (Nutgram $bot) {
$bot->sendMessage('Menyu:', reply_markup: ReplyKeyboardMarkup::make(resize_keyboard: true)
->addRow(KeyboardButton::make('Katalog')));
});
$bot->hearText('/menyu')->reply();
$bot->assertReplyText('Menyu:');
$bot->assertRaw(function (\GuzzleHttp\Psr7\Request $r) {
$body = (string) $r->getBody();
return str_contains($body, 'Katalog') && str_contains($body, 'resize_keyboard');
});
13.
use SergiX44\Nutgram\Conversations\InlineMenu;
class SettingsMenu extends InlineMenu
{
public function start(Nutgram $bot): void
{
$this->clearButtons();
$this->menuText('Sozlamalar:')
->addButtonRow(InlineKeyboardButton::make('Til', callback_data: 'lang@til'))
->addButtonRow(InlineKeyboardButton::make('Yopish', callback_data: 'close@yopish'))
->showMenu();
}
public function til(Nutgram $bot): void
{
$this->clearButtons();
$this->menuText('Tilni tanlang:')
->addButtonRow(InlineKeyboardButton::make('O\'zbek', callback_data: 'uz@start'))
->addButtonRow(InlineKeyboardButton::make('Ruscha', callback_data: 'ru@start'))
->addButtonRow(InlineKeyboardButton::make('Orqaga', callback_data: 'back@start'))
->showMenu();
}
public function yopish(Nutgram $bot): void
{
$this->closeMenu('Yopildi.');
}
}
$bot->onCommand('settings', fn (Nutgram $bot) => SettingsMenu::begin($bot));
@ dan keyingi qism β chaqiriladigan metod. uz@start/ru@start/back@start foydalanuvchini start() ga qaytaradi.
14.
function paginate(array $items, int $page, int $perPage): InlineKeyboardMarkup
{
$kb = InlineKeyboardMarkup::make();
$offset = ($page - 1) * $perPage;
$pageItems = array_slice($items, $offset, $perPage);
foreach ($pageItems as $it) {
$kb->addRow(InlineKeyboardButton::make($it['title'], callback_data: 'item:' . $it['id']));
}
$nav = [];
if ($page > 1) {
$nav[] = InlineKeyboardButton::make('βοΈ', callback_data: 'page:' . ($page - 1));
}
if ($offset + $perPage < count($items)) {
$nav[] = InlineKeyboardButton::make('βΆοΈ', callback_data: 'page:' . ($page + 1));
}
if ($nav !== []) {
$kb->addRow(...$nav);
}
return $kb;
}
15.
$products = [
['id' => 1, 'title' => 'Olma'],
['id' => 2, 'title' => 'Banan'],
];
$bot->onCommand('start', function (Nutgram $bot) {
$kb = ReplyKeyboardMarkup::make(resize_keyboard: true)
->addRow(KeyboardButton::make('Katalog'), KeyboardButton::make('Savat'));
$bot->sendMessage('Do\'konga xush kelibsiz!', reply_markup: $kb);
});
$bot->onText('Katalog', function (Nutgram $bot) use ($products) {
foreach ($products as $p) {
$kb = InlineKeyboardMarkup::make()
->addRow(InlineKeyboardButton::make('Savatga qo\'shish', callback_data: 'add:' . $p['id']));
$bot->sendMessage($p['title'], reply_markup: $kb);
}
});
$bot->onCallbackQueryData('add:{id}', function (Nutgram $bot, string $id) {
$bot->answerCallbackQuery(text: "#{$id} savatga qo'shildi");
});
// FakeNutgram tekshiruvi:
$fake = Nutgram::fake();
// ... yuqoridagi handlerlarni $fake ga ulang ...
$fake->hearText('/start')->reply();
$fake->assertReplyText('Do\'konga xush kelibsiz!');
$fake->hearText('Katalog')->reply(); // mahsulot xabarlari
$fake->hearCallbackQueryData('add:1')->reply();
$fake->assertCalled('answerCallbackQuery');
β¬ οΈ Oldingi: 05 β Xabar yuborish, formatlash va media Β· π README Β· Keyingi: 07 β Callback query va inline rejim β‘οΈ