11
11
*/
12
12
class InlineKeyboardPagination implements InlineKeyboardPaginator
13
13
{
14
- /**
15
- * @var int
16
- */
17
- private $ itemsPerPage ;
18
-
19
- /**
20
- * @var int
21
- */
22
- private $ maxButtons = 5 ;
23
-
24
- /**
25
- * @var bool
26
- */
27
- private $ forceButtonCount = false ;
28
-
29
- /**
30
- * @var int
31
- */
32
- private $ selectedPage ;
33
-
34
- /**
35
- * @var array
36
- */
37
- private $ items ;
38
-
39
- /**
40
- * @var string
41
- */
42
- private $ command ;
43
-
44
- /**
45
- * @var string
46
- */
47
- private $ callbackDataFormat = 'command={COMMAND}&oldPage={OLD_PAGE}&newPage={NEW_PAGE} ' ;
48
-
49
- /**
50
- * @var array
51
- */
52
- private $ labels = [
14
+ private array $ items ;
15
+ private int $ itemsPerPage ;
16
+ private int $ selectedPage ;
17
+ private int $ maxButtons = 5 ;
18
+ private bool $ forceButtonCount = false ;
19
+ private string $ command ;
20
+ private string $ callbackDataFormat = 'command={COMMAND}&oldPage={OLD_PAGE}&newPage={NEW_PAGE} ' ;
21
+ private array $ labels = [
53
22
'default ' => '%d ' ,
54
23
'first ' => '« %d ' ,
55
24
'previous ' => '‹ %d ' ,
@@ -68,7 +37,7 @@ class InlineKeyboardPagination implements InlineKeyboardPaginator
68
37
public function setMaxButtons (int $ maxButtons = 5 , bool $ forceButtonCount = false ): InlineKeyboardPagination
69
38
{
70
39
if ($ maxButtons < 5 || $ maxButtons > 8 ) {
71
- throw new InlineKeyboardPaginationException ( ' Invalid max buttons, must be between 5 and 8. ' );
40
+ throw InlineKeyboardPaginationException:: invalidMaxButtons ( );
72
41
}
73
42
74
43
$ this ->maxButtons = $ maxButtons ;
@@ -143,10 +112,9 @@ public function setSelectedPage(int $selectedPage): InlineKeyboardPagination
143
112
{
144
113
$ numberOfPages = $ this ->getNumberOfPages ();
145
114
if ($ selectedPage < 1 || $ selectedPage > $ numberOfPages ) {
146
- throw new InlineKeyboardPaginationException (
147
- 'Invalid selected page, must be between 1 and ' . $ numberOfPages
148
- );
115
+ throw InlineKeyboardPaginationException::pageMustBeBetween (1 , $ numberOfPages );
149
116
}
117
+
150
118
$ this ->selectedPage = $ selectedPage ;
151
119
152
120
return $ this ;
@@ -173,8 +141,9 @@ public function getItemsPerPage(): int
173
141
public function setItemsPerPage (int $ itemsPerPage ): InlineKeyboardPagination
174
142
{
175
143
if ($ itemsPerPage <= 0 ) {
176
- throw new InlineKeyboardPaginationException ( ' Invalid number of items per page, must be at least 1 ' );
144
+ throw InlineKeyboardPaginationException:: invalidItemsPerPage ( );
177
145
}
146
+
178
147
$ this ->itemsPerPage = $ itemsPerPage ;
179
148
180
149
return $ this ;
@@ -191,7 +160,7 @@ public function setItemsPerPage(int $itemsPerPage): InlineKeyboardPagination
191
160
public function setItems (array $ items ): InlineKeyboardPagination
192
161
{
193
162
if (empty ($ items )) {
194
- throw new InlineKeyboardPaginationException ( ' Items list empty. ' );
163
+ throw InlineKeyboardPaginationException:: noItems ( );
195
164
}
196
165
197
166
$ this ->items = $ items ;
@@ -250,28 +219,50 @@ public function getPagination(int $selectedPage = null): array
250
219
*/
251
220
protected function generateKeyboard (): array
252
221
{
253
- $ buttons = [];
222
+ $ buttons = $ this ->generateButtons ();
223
+ $ buttons = $ this ->applyButtonLabels ($ buttons );
224
+
225
+ return array_values (array_filter ($ buttons ));
226
+ }
227
+
228
+ /**
229
+ * Generate all buttons for this inline keyboard.
230
+ *
231
+ * @return array
232
+ */
233
+ protected function generateButtons (): array
234
+ {
254
235
$ numberOfPages = $ this ->getNumberOfPages ();
255
236
256
- if ($ numberOfPages > $ this ->maxButtons ) {
257
- $ buttons [1 ] = $ this ->generateButton (1 );
237
+ $ range = ['from ' => 2 , 'to ' => $ numberOfPages - 1 ];
258
238
239
+ if ($ numberOfPages > $ this ->maxButtons ) {
259
240
$ range = $ this ->generateRange ();
260
- for ($ i = $ range ['from ' ]; $ i < $ range ['to ' ]; $ i ++) {
261
- $ buttons [$ i ] = $ this ->generateButton ($ i );
262
- }
241
+ }
263
242
264
- $ buttons [$ numberOfPages ] = $ this ->generateButton ($ numberOfPages );
265
- } else {
266
- for ($ i = 1 ; $ i <= $ numberOfPages ; $ i ++) {
267
- $ buttons [$ i ] = $ this ->generateButton ($ i );
268
- }
243
+ $ buttons [1 ] = $ this ->generateButton (1 );
244
+ for ($ i = $ range ['from ' ]; $ i <= $ range ['to ' ]; $ i ++) {
245
+ $ buttons [$ i ] = $ this ->generateButton ($ i );
269
246
}
247
+ $ buttons [$ numberOfPages ] = $ this ->generateButton ($ numberOfPages );
248
+
249
+ return $ buttons ;
250
+ }
251
+
252
+ /**
253
+ * Apply correct text labels to the keyboard buttons.
254
+ *
255
+ * @param array $buttons
256
+ *
257
+ * @return array
258
+ */
259
+ protected function applyButtonLabels (array $ buttons ): array
260
+ {
261
+ $ numberOfPages = $ this ->getNumberOfPages ();
270
262
271
- // Set the correct labels.
272
263
foreach ($ buttons as $ page => &$ button ) {
273
- $ inFirstBlock = $ this ->selectedPage <= 3 && $ page <= 3 ;
274
- $ inLastBlock = $ this ->selectedPage >= $ numberOfPages - 2 && $ page >= $ numberOfPages - 2 ;
264
+ $ inFirstBlock = max ( $ this ->selectedPage , $ page) <= 3 ;
265
+ $ inLastBlock = min ( $ this ->selectedPage , $ page) >= $ numberOfPages - 2 ;
275
266
276
267
$ labelKey = 'next ' ;
277
268
if ($ page === $ this ->selectedPage ) {
@@ -288,6 +279,7 @@ protected function generateKeyboard(): array
288
279
289
280
$ label = $ this ->labels [$ labelKey ] ?? '' ;
290
281
282
+ // Remove button for undefined labels.
291
283
if ($ label === '' ) {
292
284
$ button = null ;
293
285
continue ;
@@ -296,7 +288,7 @@ protected function generateKeyboard(): array
296
288
$ button ['text ' ] = sprintf ($ label , $ page );
297
289
}
298
290
299
- return array_values ( array_filter ( $ buttons)) ;
291
+ return $ buttons ;
300
292
}
301
293
302
294
/**
@@ -306,30 +298,32 @@ protected function generateKeyboard(): array
306
298
*/
307
299
protected function generateRange (): array
308
300
{
309
- $ numberOfIntermediateButtons = $ this ->maxButtons - 2 ;
301
+ $ numberOfIntermediateButtons = $ this ->maxButtons - 2 ; // Minus first and last buttons.
310
302
$ numberOfPages = $ this ->getNumberOfPages ();
311
303
312
- // @todo: Find a nicer solution for page 3
313
304
$ from = $ this ->selectedPage - 1 ;
314
- $ to = $ this ->selectedPage + ( $ this -> selectedPage === 3 ? $ numberOfIntermediateButtons - 1 : 2 ) ;
305
+ $ to = $ this ->selectedPage + 1 ;
315
306
316
307
if ($ this ->selectedPage === 1 ) {
317
308
$ from = 2 ;
318
- $ to = $ this ->maxButtons ;
309
+ $ to = $ this ->maxButtons - 1 ;
319
310
} elseif ($ this ->selectedPage === $ numberOfPages ) {
320
311
$ from = $ numberOfPages - $ numberOfIntermediateButtons ;
321
- $ to = $ numberOfPages ;
312
+ $ to = $ numberOfPages - 1 ;
313
+ } elseif ($ this ->selectedPage === 3 ) {
314
+ // Special case because this button is in the center of a flexible pagination.
315
+ $ to += $ numberOfIntermediateButtons - 3 ;
322
316
} elseif ($ this ->selectedPage < 3 ) {
323
317
// First half.
324
318
$ from = $ this ->selectedPage ;
325
- $ to = $ this ->selectedPage + $ numberOfIntermediateButtons ;
319
+ $ to = $ this ->selectedPage + $ numberOfIntermediateButtons - 1 ;
326
320
} elseif (($ numberOfPages - $ this ->selectedPage ) < 3 ) {
327
321
// Last half.
328
322
$ from = $ numberOfPages - $ numberOfIntermediateButtons ;
329
- $ to = $ numberOfPages ;
323
+ $ to = $ numberOfPages - 1 ;
330
324
} elseif ($ this ->forceButtonCount ) {
331
- $ from = max (2 , $ this ->selectedPage - floor ($ numberOfIntermediateButtons / 2 ));
332
- $ to = $ from + $ numberOfIntermediateButtons ;
325
+ $ from = ( int ) max (2 , $ this ->selectedPage - floor ($ numberOfIntermediateButtons / 2 ));
326
+ $ to = $ from + $ numberOfIntermediateButtons - 1 ;
333
327
}
334
328
335
329
return compact ('from ' , 'to ' );
@@ -345,7 +339,7 @@ protected function generateRange(): array
345
339
protected function generateButton (int $ page ): array
346
340
{
347
341
return [
348
- 'text ' => ( string ) $ page ,
342
+ 'text ' => $ page ,
349
343
'callback_data ' => $ this ->generateCallbackData ($ page ),
350
344
];
351
345
}
0 commit comments