2

For a Telegram bot that I am building I want to return inline buttons dynamically depending the returned PHP PDO recordset Telegram API docs.

Hardcoded a good function piece of code looks like the below. This is confirmed working. It return two rows of buttons. The first row containing two buttons, the second row two buttons.

$reply  = "Some message to show before the buttons";
$keyb   = array('inline_keyboard' => array(
            array(
                array('text'=>'Link text', 'callback_data'=>'/command'),
                array('text'=>"Link text", 'callback_data'=>'/command')
            ),
            array(
                array('text'=>'Link text', 'callback_data'=>'/command'),
                array('text'=>'Link text', 'callback_data'=>'/command')
            )
          )
        );

$replyMarkup = json_encode($keyb);
sendMessage($chatID, $reply, $replyMarkup);

So far so good. But now I want to populate these buttons dynamically given a PHP recordset.

The below does return the desired buttons, but I do not know how I can specify a cut-off point after two buttons to create the second row. In the format below all buttons end up on a single row. Even if the recordset returns 5 results.

$reply  = "Some message to show before the buttons";

$i=0;
// Loop through all results to create individual buttons
foreach ($stmt as $row) 
{
    $options[] = array('text'=>urlencode($row['title']), 'callback_data'=>'/x');
    $i++;
}

$keyb           = array('inline_keyboard' => array( $options ));
$replyMarkup    = json_encode($keyb);
sendMessage($chatID, $reply, $replyMarkup);

I considered using an if statement with modulo operator ($i%2=1), but do not know how to cope with the parent array() that defines the row...

...
if($i%2=1)
{ 
    $options[]="array("; // <-- Setting an array as a value will obviously fail
}    
... remaining code

Happy to hear any thoughts that might help me on my way!

Thanks.

AXTG
  • 58
  • 6
  • use the `$i` to check if you have two already. _if_ you do, make a new sub-array. Then write all of them to `inline_keyboard` – Jeff Jun 13 '17 at 19:58

2 Answers2

0

This should do the trick:

<?php
// DUMMY DATA
$stmt = array(
            array('title'=>'Link text1', 'callback_data'=>'/command'),
            array('title'=>"Link text2", 'callback_data'=>'/command'),
            array('title'=>'Link text3', 'callback_data'=>'/command'),
            array('title'=>'Link text4', 'callback_data'=>'/command'),
            array('title'=>'Link text5', 'callback_data'=>'/command')
      );

$i=0;
$r=1;
foreach ($stmt as $row)
{
    // here's the trick: $options[$r][]
    $options[$r][] = array('text'=>urlencode($row['title']), 'callback_data'=>'/x');
    $i++;
    if($i===2) { // if counter at row 3
        $r++; // increase row index here
        $i=0; // reset counter
    };
}

// for debugging only:
echo "<pre>";
var_dump($options);
echo "</pre>";
                                        // note the change here
$keyb           = array('inline_keyboard' => $options);
?>

The version of @abfackeln (what a username if you understand german..) is acutally nicer, because he uses modulus and doesn't reset the counter.

Jeff
  • 6,895
  • 1
  • 15
  • 33
0

Forgive me here, I must jump in and shout:

NOOOOOOO!

to the other answers.

PHP already provides a function that can break an array into "chunks" called array_chunk(). Do NOT use incrementing and modulus conditions to generate keys, use this one function.

Code (Demo):

$stmt = array(
            array('title'=>'Link ? text1', 'callback_data'=>'/x'),
            array('title'=>"Link & text2", 'callback_data'=>'/x'),
            array('title'=>'Link # text3', 'callback_data'=>'/x'),
            array('title'=>'Link * text4', 'callback_data'=>'/x'),
            array('title'=>'Link @ text5', 'callback_data'=>'/x')
      );

// prepare the subarrays using resultset
foreach($stmt as $row){
    $options[]=['text'=>urlencode($row['title']),'callback_data'=>'/x'];
}

// then chunk into pairs, assign key, json encode --> DONE
var_export(json_encode(['inline_keyboard'=>array_chunk($options,2)]));
//sendMessage($chatID,$reply,json_encode(['inline_keyboard'=>array_chunk($options,2)]));

Output:

{"inline_keyboard":[[[{"text":"Link+%3F+text1","callback_data":"\\/x"},{"text":"Link+%26+text2","callback_data":"\\/x"}],[{"text":"Link+%23+text3","callback_data":"\\/x"},{"text":"Link+%2A+text4","callback_data":"\\/x"}],[{"text":"Link+%40+text5","callback_data":"\\/x"}]]]}
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • Hi mickmackusa, I can understand your frustration. Such an undervalued function that `array_chunk()` is. I tested it successfully, and thus a change in best answer applied. A **minor remark** for those looking to reuse this for Telegram: use `json_encode(['inline_keyboard'=>array_chunk($options,2)])` instead, as that is the level of depth expected. – AXTG Jun 18 '17 at 13:53
  • @AXTG Thanks for that advisement. I've updated my answers to correct the array depth. – mickmackusa Jun 18 '17 at 20:05