new pager
[phinde.git] / src / phinde / Html / Pager.php
1 <?php
2 namespace phinde;
3
4 /**
5  * A better result pager.
6  *
7  * Rules:
8  * - "Prev" and "next" buttons are outside
9  * - No "first" and "last", but "1" and "$totalNumOfPages"
10  * - two previous and two next pages are shown as buttons
11  * - When current page is <= 5, first 5 pages are shown
12  * - ".." is only shown for at least two skipped pages
13  *
14  * Examples:
15  * [<< prev] [1] [2] [3] [next >>]
16  * [<< prev] [1] [2] [3] [4] [5] [next >>]
17  * [<< prev] [1] [2] [3] [4] [5] ... [8] [next >>]
18  * [<< prev] [1] ... [4] [5] [6] [7] [8] ... [10] [next >>]
19  *
20  * replace ".." with actual link when between previous and next is only one
21  */
22 class Html_Pager
23 {
24     protected $pager;
25
26     /**
27      * Create a new pager
28      *
29      * @param integer $itemCount   Number of items in total
30      * @param integer $perPage     Number of items on one page
31      * @param integer $currentPage Current page, beginning with 1
32      * @param string  $filename    URL the page number shall be appended
33      */
34     public function __construct($itemCount, $perPage, $currentPage, $filename)
35     {
36         $append = true;
37         if (strpos($filename, '%d') !== false) {
38             $append = false;
39         }
40
41         $numPages = ceil($itemCount / $perPage);
42         $this->numPages = $numPages;
43
44         //1-based
45         $pages = [
46             1 => true,
47             2 => true,
48             $numPages - 1 => true,
49             $numPages     => true,
50         ];
51         if ($currentPage <= 6) {
52             $pages[3] = 3;
53             $pages[4] = 4;
54             $pages[5] = 5;
55         }
56         if ($currentPage >= $numPages - 5) {
57             $pages[$numPages - 2] = true;
58             $pages[$numPages - 3] = true;
59             $pages[$numPages - 4] = true;
60         }
61         for ($n = $currentPage - 2; $n <= $currentPage + 2; $n++) {
62             $pages[$n] = true;
63         }
64         foreach (array_keys($pages) as $key) {
65             if ($key < 1 || $key > $numPages) {
66                 unset($pages[$key]);
67             }
68         }
69         if ($currentPage >= 7 && !isset($pages[4])) {
70             $pages[3] = null;
71         }
72         if ($currentPage <= $numPages - 6 && !isset($pages[$numPages - 3])) {
73             $pages[$numPages - 2] = null;
74         }
75
76         ksort($pages);
77         foreach ($pages as $pageNum => &$value) {
78             if ($pageNum == $currentPage) {
79                 $value = ['active'=> false, 'title' => $pageNum];
80             } else if ($value !== null) {
81                 $value = $this->makeLink($pageNum, $filename);
82             } else {
83                 $value = ['active'=> false, 'title' => '…'];
84             }
85         }
86
87         $prev = ['active'=> false, 'title' => '« prev'];
88         if ($currentPage > 1) {
89             $prev = $this->makeLink($currentPage - 1, $filename, '« prev');
90         }
91         $next = ['active'=> false, 'title' => 'next »'];
92         if ($currentPage < $numPages) {
93             $next = $this->makeLink($currentPage + 1, $filename, 'next »');
94         }
95         //first and last are for opensearch
96         $first = ['active'=> false, 'title' => 'first'];
97         if ($currentPage > 1) {
98             $first = $this->makeLink(1, $filename, 'first');
99         }
100         $last = ['active'=> false, 'title' => 'last'];
101         if ($numPages > 1 && $currentPage < $numPages) {
102             $last = $this->makeLink($numPages, $filename, 'last');
103         }
104
105         $this->links = [
106             'prev'  => $prev,
107             'next'  => $next,
108             'first' => $first,
109             'last'  => $last,
110             'pages' => $pages,
111         ];
112     }
113
114     protected function makeLink($pageNum, $filename, $title = null)
115     {
116         $title = $title === null ? $pageNum : $title;
117         $url   = $filename . '&page=' . $pageNum;
118         return [
119             'active' => true,
120             'url'    => $url,
121             'title'  => $title,
122             'html'   => '<a href="' . htmlspecialchars($url)
123                 . '" title="Page ' . $pageNum . '">'
124                 . htmlspecialchars($title)
125                 . '</a>',
126         ];
127     }
128
129     public function getLinks()
130     {
131         return $this->links;
132     }
133
134     public function getFullUrls()
135     {
136         $arUrls  = array();
137         foreach ($this->links as $key => $link) {
138             if ($key == 'pages') {
139                 continue;
140             }
141             if ($link['active']) {
142                 $arUrls[$key] = str_replace(
143                     '&amp;', '&',
144                     Helper::fullUrl('/'  . $link['url'])
145                 );
146             }
147         }
148         return $arUrls;
149     }
150
151     public function numPages()
152     {
153         return $this->numPages;
154         return $this->pager->numPages();
155     }
156 }
157
158 ?>