Passed
Push — master ( 92bbd7...8b441d )
by Andreas
17:44
created

org_openpsa_qbpager::end_group()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package org.openpsa.qbpager
4
 */
5
6
/**
7
 * Pages QB resultsets
8
 *
9
 * @package org.openpsa.qbpager
10
 */
11
class org_openpsa_qbpager
12
{
13
    use midcom_baseclasses_components_base;
0 ignored issues
show
introduced by
The trait midcom_baseclasses_components_base requires some properties which are not provided by org_openpsa_qbpager: $i18n, $head
Loading history...
14
15
    public $results_per_page = 25;
16
    public $display_pages = 10;
17
    public $string_next = 'next';
18
    public $string_previous = 'previous';
19
    protected $_midcom_qb;
20
    protected $_midcom_qb_count;
21
    protected $_pager_id;
22
    protected $_prefix = '';
23
    private $_offset = 0;
24
    private $count;
25
    private $_count_mode;
26
    private $_current_page = 1;
27
28 14
    public function __construct(string $classname, string $pager_id)
29
    {
30 14
        $this->_component = 'org.openpsa.qbpager';
31 14
        if (empty($pager_id)) {
32
            throw new midcom_error('pager_id is not set (needed for distinguishing different instances on same request)');
33
        }
34
35 14
        $this->_pager_id = $pager_id;
36 14
        $this->_prefix = 'org_openpsa_qbpager_' . $pager_id . '_';
37 14
        $this->_prepare_qbs($classname);
38 14
    }
39
40 13
    protected function _prepare_qbs(string $classname)
41
    {
42 13
        $this->_midcom_qb = midcom::get()->dbfactory->new_query_builder($classname);
43
        // Make another QB for counting, we need to do this to avoid trouble with core internal references system
44 13
        $this->_midcom_qb_count = midcom::get()->dbfactory->new_query_builder($classname);
45 13
    }
46
47
    /**
48
     * Get the current page number
49
     */
50 5
    public function get_current_page() : int
51
    {
52 5
        return $this->_current_page;
53
    }
54
55
    /**
56
     * Fetch all $_GET variables
57
     */
58
    private function _get_query_string(string $page_var, int $page_number) : string
59
    {
60
        $query = [$page_var => $page_number];
61
62
        foreach ($_GET as $key => $value) {
63
            if (!in_array($key, [$page_var, ''])) {
64
                $query[$key] = $value;
65
            }
66
        }
67
68
        return '?' . http_build_query($query);
69
    }
70
71
    /**
72
     * Displays previous/next selector
73
     */
74 5
    function show_previousnext()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
75
    {
76 5
        $page_count = $this->count_pages();
77
        //Skip the header in case we only have one page
78 5
        if ($page_count <= 1) {
79 5
            return;
80
        }
81
        //@todo Move to style element
82
        //TODO: "showing results (offset)-(offset+limit)
83
        $page_var = $this->_prefix . 'page';
84
        echo '<div class="org_openpsa_qbpager_previousnext">';
85
86
        if ($this->_current_page > 1) {
87
            $previous = $this->_current_page - 1;
88
            echo "\n<a class=\"previous_page\" href=\"" . $this->_get_query_string($page_var, $previous) . "\" rel=\"prev\">" . $this->_l10n->get($this->string_previous) . "</a>";
89
        }
90
91
        if ($this->_current_page < $page_count) {
92
            $next = $this->_current_page + 1;
93
            echo "\n<a class=\"next_page\" href=\"" . $this->_get_query_string($page_var, $next) . "\" rel=\"next\">" . $this->_l10n->get($this->string_next) . "</a>";
94
        }
95
96
        echo "\n</div>\n";
97
    }
98
99 1
    public function get_pages() : array
100
    {
101 1
        $pages = [];
102 1
        $page_count = $this->count_pages();
103
104 1
        if ($page_count < 1) {
105
            return $pages;
106
        }
107
108 1
        $page_var = $this->_prefix . 'page';
109 1
        $display_start = max(($this->_current_page - ceil($this->display_pages / 2)), 1);
110 1
        $display_end = min(($this->_current_page + ceil($this->display_pages / 2)), $page_count);
111
112 1
        if ($this->_current_page > 1) {
113
            $previous = $this->_current_page - 1;
114
            if ($previous > 1) {
115
                $pages[] = [
116
                    'class' => 'first',
117
                    'href' => $this->_get_query_string($page_var, 1),
118
                    'rel' => 'prev',
119
                    'label' => $this->_l10n->get('first'),
120
                    'number' => 1
121
                ];
122
            }
123
            $pages[] = [
124
                'class' => 'previous',
125
                'href' => $this->_get_query_string($page_var, $previous),
126
                'rel' => 'prev',
127
                'label' => $this->_l10n->get($this->string_previous),
128
                'number' => $previous
129
            ];
130
        }
131 1
        $page = $display_start - 1;
132 1
        while ($page++ < $display_end) {
133 1
            $href = false;
134 1
            if ($page != $this->_current_page) {
135
                $href = $this->_get_query_string($page_var, $page);
136
            }
137 1
            $pages[] = [
138 1
                'class' => 'current',
139 1
                'href' => $href,
140
                'rel' => false,
141 1
                'label' => $page,
142 1
                'number' => $page
143
            ];
144
        }
145
146 1
        if ($this->_current_page < $page_count) {
147
            $next = $this->_current_page + 1;
148
            $pages[] = [
149
                'class' => 'next',
150
                'href' => $this->_get_query_string($page_var, $next),
151
                'rel' => 'next',
152
                'label' => $this->_l10n->get($this->string_next),
153
                'number' => $next
154
            ];
155
156
            if ($next < $page_count) {
157
                $pages[] = [
158
                    'class' => 'last',
159
                    'href' => $this->_get_query_string($page_var, $page_count),
0 ignored issues
show
Bug introduced by
$page_count of type double is incompatible with the type integer expected by parameter $page_number of org_openpsa_qbpager::_get_query_string(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

159
                    'href' => $this->_get_query_string($page_var, /** @scrutinizer ignore-type */ $page_count),
Loading history...
160
                    'rel' => 'next',
161
                    'label' => $this->_l10n->get('last'),
162
                    'number' => $page_count
163
                ];
164
            }
165
        }
166
167 1
        return $pages;
168
    }
169
170 1
    private function show(string $name, array $data)
171
    {
172 1
        $context = midcom_core_context::enter();
173 1
        $context->set_custom_key('request_data', $data);
174 1
        midcom::get()->style->prepend_component_styledir($this->_component);
175 1
        midcom::get()->style->enter_context($context);
176 1
        midcom_show_style('show_' . $name);
177 1
        midcom::get()->style->leave_context();
178 1
        midcom_core_context::leave();
179 1
    }
180
181
    /**
182
     * Displays page selector
183
     */
184 1
    public function show_pages()
185
    {
186 1
        $this->show('pages', ['pages' => $this->get_pages()]);
187 1
    }
188
189
    /**
190
     * Displays page selector as list
191
     */
192
    function show_pages_as_list()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
193
    {
194
        $this->show('pages_as_list', ['pages' => $this->get_pages()]);
195
    }
196
197
    /**
198
     * Check $_REQUEST for variables and sets LIMIT and OFFSET for requested page
199
     */
200 14
    protected function _qb_limits($qb)
201
    {
202 14
        $page_var = $this->_prefix . 'page';
203 14
        if (!empty($_REQUEST[$page_var])) {
204
            debug_add("{$page_var} has value: {$_REQUEST[$page_var]}");
205
            $this->_current_page = max(1, (int) $_REQUEST[$page_var]);
206
        }
207 14
        if ($this->_current_page == 'all') {
208
            debug_add("displaying all results");
209
            return;
210
        }
211 14
        $results_var = $this->_prefix . 'results';
212 14
        if (!empty($_REQUEST[$results_var])) {
213
            debug_add("{$results_var} has value: {$_REQUEST[$results_var]}");
214
            $this->results_per_page = max(1, (int) $_REQUEST[$results_var]);
215
        }
216 14
        if ($this->results_per_page < 1) {
217
            throw new LogicException('results_per_page is set to ' . $this->results_per_page);
218
        }
219 14
        $this->_offset = ($this->_current_page - 1) * $this->results_per_page;
220 14
        $qb->set_limit($this->results_per_page);
221 14
        $qb->set_offset($this->_offset);
222 14
        debug_add("set offset to {$this->_offset} and limit to {$this->results_per_page}");
223 14
    }
224
225 14
    public function execute() : array
226
    {
227 14
        $this->_qb_limits($this->_midcom_qb);
228 14
        return $this->_midcom_qb->execute();
229
    }
230
231
    public function execute_unchecked() : array
232
    {
233
        $this->_qb_limits($this->_midcom_qb);
234
        return $this->_midcom_qb->execute_unchecked();
235
    }
236
237
    /**
238
     * Returns number of total pages for query
239
     *
240
     * By default returns a number of pages without any ACL checks
241
     */
242 6
    public function count_pages()
243
    {
244 6
        $this->count_unchecked();
245 6
        return ceil($this->count / $this->results_per_page);
246
    }
247
248
    //Rest of supported methods wrapped with extra sanity check
249 14
    public function add_constraint(string $param, string $op, $val) : bool
250
    {
251 14
        $this->_midcom_qb_count->add_constraint($param, $op, $val);
252 14
        return $this->_midcom_qb->add_constraint($param, $op, $val);
253
    }
254
255 13
    public function add_order(string $param, string $sort = 'ASC') : bool
256
    {
257 13
        return $this->_midcom_qb->add_order($param, $sort);
258
    }
259
260 2
    public function begin_group(string $type)
261
    {
262 2
        $this->_midcom_qb_count->begin_group($type);
263 2
        $this->_midcom_qb->begin_group($type);
264 2
    }
265
266 2
    public function end_group()
267
    {
268 2
        $this->_midcom_qb_count->end_group();
269 2
        $this->_midcom_qb->end_group();
270 2
    }
271
272 1
    public function include_deleted()
273
    {
274 1
        $this->_midcom_qb_count->include_deleted();
275 1
        $this->_midcom_qb->include_deleted();
276 1
    }
277
278
    public function count() : int
279
    {
280
        if (   !$this->count
281
            || $this->_count_mode != 'count') {
282
            $this->count = $this->_midcom_qb_count->count();
283
        }
284
        $this->_count_mode = 'count';
285
        return $this->count;
286
    }
287
288 6
    public function count_unchecked() : int
289
    {
290 6
        if (   !$this->count
291 6
            || $this->_count_mode != 'count_unchecked') {
292 6
            $this->count = $this->_midcom_qb_count->count_unchecked();
293
        }
294 6
        $this->_count_mode = 'count_unchecked';
295 6
        return $this->count;
296
    }
297
}
298