Paginator::__toString()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of Jitamin.
5
 *
6
 * Copyright (C) Jitamin Team
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Jitamin\Foundation;
13
14
use PicoDb\Table;
15
use Pimple\Container;
16
17
/**
18
 * Paginator helper.
19
 */
20
class Paginator
21
{
22
    /**
23
     * Container instance.
24
     *
25
     * @var \Pimple\Container
26
     */
27
    private $container;
28
29
    /**
30
     * Total number of items.
31
     *
32
     * @var int
33
     */
34
    private $total = 0;
35
36
    /**
37
     * Page number.
38
     *
39
     * @var int
40
     */
41
    private $page = 1;
42
43
    /**
44
     * Offset.
45
     *
46
     * @var int
47
     */
48
    private $offset = 0;
49
50
    /**
51
     * Limit.
52
     *
53
     * @var int
54
     */
55
    private $limit = 0;
56
57
    /**
58
     * Sort by this column.
59
     *
60
     * @var string
61
     */
62
    private $order = '';
63
64
    /**
65
     * Sorting direction.
66
     *
67
     * @var string
68
     */
69
    private $direction = 'ASC';
70
71
    /**
72
     * Slice of items.
73
     *
74
     * @var array
75
     */
76
    private $items = [];
77
78
    /**
79
     * PicoDb Table instance.
80
     *
81
     * @var \Picodb\Table
82
     */
83
    private $query = null;
84
85
    /**
86
     * Controller name.
87
     *
88
     * @var string
89
     */
90
    private $controller = '';
91
92
    /**
93
     * Action name.
94
     *
95
     * @var string
96
     */
97
    private $action = '';
98
99
    /**
100
     * Url params.
101
     *
102
     * @var array
103
     */
104
    private $params = [];
105
106
    /**
107
     * Constructor.
108
     *
109
     * @param \Pimple\Container $container
110
     */
111
    public function __construct(Container $container)
112
    {
113
        $this->container = $container;
114
    }
115
116
    /**
117
     * Set a PicoDb query.
118
     *
119
     * @param  \PicoDb\Table
120
     *
121
     * @return Paginator
122
     */
123
    public function setQuery(Table $query)
124
    {
125
        $this->query = $query;
126
        $this->total = $this->query->count();
127
128
        return $this;
129
    }
130
131
    /**
132
     * Execute a PicoDb query.
133
     *
134
     * @return array
135
     */
136
    public function executeQuery()
137
    {
138
        if ($this->query !== null) {
139
            return $this->query
140
                        ->offset($this->offset)
141
                        ->limit($this->limit)
142
                        ->orderBy($this->order, $this->direction)
143
                        ->findAll();
144
        }
145
146
        return [];
147
    }
148
149
    /**
150
     * Set url parameters.
151
     *
152
     * @param string $controller
153
     * @param string $action
154
     * @param array  $params
155
     *
156
     * @return Paginator
157
     */
158
    public function setUrl($controller, $action, array $params = [])
159
    {
160
        $this->controller = $controller;
161
        $this->action = $action;
162
        $this->params = $params;
163
164
        return $this;
165
    }
166
167
    /**
168
     * Add manually items.
169
     *
170
     * @param array $items
171
     *
172
     * @return Paginator
173
     */
174
    public function setCollection(array $items)
175
    {
176
        $this->items = $items;
177
178
        return $this;
179
    }
180
181
    /**
182
     * Return the items.
183
     *
184
     * @return array
185
     */
186
    public function getCollection()
187
    {
188
        return $this->items ?: $this->executeQuery();
189
    }
190
191
    /**
192
     * Set the total number of items.
193
     *
194
     * @param int $total
195
     *
196
     * @return Paginator
197
     */
198
    public function setTotal($total)
199
    {
200
        $this->total = $total;
201
202
        return $this;
203
    }
204
205
    /**
206
     * Get the total number of items.
207
     *
208
     * @return int
209
     */
210
    public function getTotal()
211
    {
212
        return $this->total;
213
    }
214
215
    /**
216
     * Set the default page number.
217
     *
218
     * @param int $page
219
     *
220
     * @return Paginator
221
     */
222
    public function setPage($page)
223
    {
224
        $this->page = $page;
225
226
        return $this;
227
    }
228
229
    /**
230
     * Get the number of current page.
231
     *
232
     * @return int
233
     */
234
    public function getPage()
235
    {
236
        return $this->page;
237
    }
238
239
    /**
240
     * Get the total number of pages.
241
     *
242
     * @return int
243
     */
244
    public function getPageTotal()
245
    {
246
        return ceil($this->getTotal() / $this->getMax());
247
    }
248
249
    /**
250
     * Set the default column order.
251
     *
252
     * @param string $order
253
     *
254
     * @return Paginator
255
     */
256
    public function setOrder($order)
257
    {
258
        $this->order = $order;
259
260
        return $this;
261
    }
262
263
    /**
264
     * Set the default sorting direction.
265
     *
266
     * @param string $direction
267
     *
268
     * @return Paginator
269
     */
270
    public function setDirection($direction)
271
    {
272
        $this->direction = $direction;
273
274
        return $this;
275
    }
276
277
    /**
278
     * Set the maximum number of items per page.
279
     *
280
     * @param int $limit
281
     *
282
     * @return Paginator
283
     */
284
    public function setMax($limit)
285
    {
286
        $this->limit = $limit;
287
288
        return $this;
289
    }
290
291
    /**
292
     * Get the maximum number of items per page.
293
     *
294
     * @return int
295
     */
296
    public function getMax()
297
    {
298
        return $this->limit;
299
    }
300
301
    /**
302
     * Return true if the collection is empty.
303
     *
304
     * @return bool
305
     */
306
    public function isEmpty()
307
    {
308
        return $this->total === 0;
309
    }
310
311
    /**
312
     * Execute the offset calculation only if the $condition is true.
313
     *
314
     * @param bool $condition
315
     *
316
     * @return Paginator
317
     */
318
    public function calculateOnlyIf($condition)
319
    {
320
        if ($condition) {
321
            $this->calculate();
322
        }
323
324
        return $this;
325
    }
326
327
    /**
328
     * Calculate the offset value accoring to url params and the page number.
329
     *
330
     * @return Paginator
331
     */
332
    public function calculate()
333
    {
334
        $this->page = $this->container['request']->getIntegerParam('page', 1);
335
        $this->direction = $this->container['request']->getStringParam('direction', $this->direction);
336
        $this->order = $this->container['request']->getStringParam('order', $this->order);
337
338
        if ($this->page < 1) {
339
            $this->page = 1;
340
        }
341
342
        $this->offset = (int) (($this->page - 1) * $this->limit);
343
344
        return $this;
345
    }
346
347
    /**
348
     * Generation pagination links.
349
     *
350
     * @return string
351
     */
352
    public function toHtml()
353
    {
354
        $html = '';
355
356
        if (!$this->hasNothingtoShow()) {
357
            $html .= '<div class="pagination">';
358
            $html .= $this->generatPageShowing();
359
            $html .= $this->generatePreviousLink();
360
            $html .= $this->generateNextLink();
361
            $html .= '</div>';
362
        }
363
364
        return $html;
365
    }
366
367
    /**
368
     * Magic method to output pagination links.
369
     *
370
     * @return string
371
     */
372
    public function __toString()
373
    {
374
        return $this->toHtml();
375
    }
376
377
    /**
378
     * Column sorting.
379
     *
380
     * @param string $label  Column title
381
     * @param string $column SQL column name
382
     *
383
     * @return string
384
     */
385
    public function order($label, $column)
386
    {
387
        $prefix = '';
388
        $direction = 'ASC';
389
390
        if ($this->order === $column) {
391
            $prefix = $this->direction === 'DESC' ? '&#9660; ' : '&#9650; ';
392
            $direction = $this->direction === 'DESC' ? 'ASC' : 'DESC';
393
        }
394
395
        return $prefix.$this->container['helper']->url->link(
396
            $label,
397
            $this->controller,
398
            $this->action,
399
            $this->getUrlParams($this->page, $column, $direction)
400
        );
401
    }
402
403
    /**
404
     * Get url params for link generation.
405
     *
406
     * @param int    $page
407
     * @param string $order
408
     * @param string $direction
409
     *
410
     * @return string
411
     */
412
    protected function getUrlParams($page, $order, $direction)
413
    {
414
        $params = [
415
            'page'      => $page,
416
            'order'     => $order,
417
            'direction' => $direction,
418
        ];
419
420
        return array_merge($this->params, $params);
421
    }
422
423
    /**
424
     * Generate the previous link.
425
     *
426
     * @return string
427
     */
428
    protected function generatePreviousLink()
429
    {
430
        $html = '<span class="pagination-previous">';
431
432
        if ($this->offset > 0) {
433
            $html .= $this->container['helper']->url->link(
434
                '&laquo; '.t('Previous'),
435
                $this->controller,
436
                $this->action,
437
                $this->getUrlParams($this->page - 1, $this->order, $this->direction),
438
                false,
439
                'btn btn-info'
440
            );
441
        } else {
442
            $html .= '<span class="btn btn-default">&laquo; '.t('Previous').'</span>';
443
        }
444
445
        $html .= '</span>';
446
447
        return $html;
448
    }
449
450
    /**
451
     * Generate the next link.
452
     *
453
     * @return string
454
     */
455
    protected function generateNextLink()
456
    {
457
        $html = '<span class="pagination-next">';
458
459
        if (($this->total - $this->offset) > $this->limit) {
460
            $html .= $this->container['helper']->url->link(
461
                t('Next').' &raquo;',
462
                $this->controller,
463
                $this->action,
464
                $this->getUrlParams($this->page + 1, $this->order, $this->direction),
465
                false,
466
                'btn btn-info'
467
            );
468
        } else {
469
            $html .= '<span class="btn btn-default">'.t('Next').' &raquo;</span>';
470
        }
471
472
        $html .= '</span>';
473
474
        return $html;
475
    }
476
477
    /**
478
     * Generate the page showing.
479
     *
480
     * @return string
481
     */
482
    protected function generatPageShowing()
483
    {
484
        return '<span class="pagination-showing">'.t('Showing %d-%d of %d', (($this->getPage() - 1) * $this->getMax() + 1), min($this->getTotal(), $this->getPage() * $this->getMax()), $this->getTotal()).'</span>';
485
    }
486
487
    /**
488
     * Return true if there is no pagination to show.
489
     *
490
     * @return bool
491
     */
492
    protected function hasNothingtoShow()
493
    {
494
        return $this->offset === 0 && ($this->total - $this->offset) <= $this->limit;
495
    }
496
}
497