Completed
Push — master ( 08ca03...9de7f6 )
by Andreas
13:53
created

org_openpsa_qbpager   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 308
Duplicated Lines 0 %

Test Coverage

Coverage 58.68%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 147
c 1
b 0
f 0
dl 0
loc 308
ccs 98
cts 167
cp 0.5868
rs 8.8
wmc 45

22 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 2
A _prepare_qbs() 0 5 1
A begin_group() 0 4 1
A include_deleted() 0 4 1
A get_current_page() 0 3 1
B get_pages() 0 69 8
A execute_unchecked() 0 5 1
A count_unchecked() 0 9 3
A _check_page_vars() 0 15 4
A add_order() 0 3 1
A execute() 0 5 1
A show() 0 9 1
A add_constraint() 0 4 1
A show_pages_as_list() 0 3 1
A _get_query_string() 0 11 4
A _sanity_check() 0 4 2
A end_group() 0 4 1
A count_pages() 0 5 1
A count() 0 9 3
A show_pages() 0 3 1
A show_previousnext() 0 23 4
A _qb_limits() 0 12 2

How to fix   Complexity   

Complex Class

Complex classes like org_openpsa_qbpager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use org_openpsa_qbpager, and based on these observations, apply Extract Interface, too.

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 extends midcom_baseclasses_components_purecode
12
{
13
    public $results_per_page = 25;
14
    public $display_pages = 10;
15
    public $string_next = 'next';
16
    public $string_previous = 'previous';
17
    protected $_midcom_qb;
18
    protected $_midcom_qb_count;
19
    protected $_pager_id;
20
    protected $_prefix = '';
21
    private $_offset = 0;
22
    private $count;
23
    private $_count_mode;
24
    private $_current_page = 1;
25
26 14
    public function __construct($classname, $pager_id)
27
    {
28 14
        if (empty($pager_id)) {
29
            throw new midcom_error('pager_id is not set (needed for distinguishing different instances on same request)');
30
        }
31 14
        parent::__construct();
32
33 14
        $this->_pager_id = $pager_id;
34 14
        $this->_prefix = 'org_openpsa_qbpager_' . $this->_pager_id . '_';
35 14
        $this->_prepare_qbs($classname);
36 14
    }
37
38 13
    protected function _prepare_qbs($classname)
39
    {
40 13
        $this->_midcom_qb = midcom::get()->dbfactory->new_query_builder($classname);
41
        // Make another QB for counting, we need to do this to avoid trouble with core internal references system
42 13
        $this->_midcom_qb_count = midcom::get()->dbfactory->new_query_builder($classname);
43 13
    }
44
45
    /**
46
     * Makes sure we have some absolutely required things properly set
47
     */
48 14
    protected function _sanity_check()
49
    {
50 14
        if ($this->results_per_page < 1) {
51
            throw new LogicException('results_per_page is set to ' . $this->results_per_page);
52
        }
53 14
    }
54
55
    /**
56
     * Check $_REQUEST for variables and sets internal status accordingly
57
     */
58 14
    private function _check_page_vars()
59
    {
60 14
        $page_var = $this->_prefix . 'page';
61 14
        $results_var = $this->_prefix . 'results';
62 14
        if (!empty($_REQUEST[$page_var])) {
63
            debug_add("{$page_var} has value: {$_REQUEST[$page_var]}");
64
            $this->_current_page = (int)$_REQUEST[$page_var];
65
        }
66 14
        if (!empty($_REQUEST[$results_var])) {
67
            debug_add("{$results_var} has value: {$_REQUEST[$results_var]}");
68
            $this->results_per_page = (int)$_REQUEST[$results_var];
69
        }
70 14
        $this->_offset = ($this->_current_page-1)*$this->results_per_page;
71 14
        if ($this->_offset < 0) {
72
            $this->_offset = 0;
73
        }
74 14
    }
75
76
    /**
77
     * Get the current page number
78
     */
79 5
    public function get_current_page() : int
80
    {
81 5
        return $this->_current_page;
82
    }
83
84
    /**
85
     * Fetch all $_GET variables
86
     */
87
    private function _get_query_string(string $page_var, int $page_number) : string
88
    {
89
        $query = [$page_var => $page_number];
90
91
        foreach ($_GET as $key => $value) {
92
            if ($key != $page_var && $key != '') {
93
                $query[$key] = $value;
94
            }
95
        }
96
97
        return '?' . http_build_query($query);
98
    }
99
100
    /**
101
     * Displays previous/next selector
102
     */
103 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...
104
    {
105 5
        $page_count = $this->count_pages();
106
        //Skip the header in case we only have one page
107 5
        if ($page_count <= 1) {
108 5
            return;
109
        }
110
        //@todo Move to style element
111
        //TODO: "showing results (offset)-(offset+limit)
112
        $page_var = $this->_prefix . 'page';
113
        echo '<div class="org_openpsa_qbpager_previousnext">';
114
115
        if ($this->_current_page > 1) {
116
            $previous = $this->_current_page - 1;
117
            echo "\n<a class=\"previous_page\" href=\"" . $this->_get_query_string($page_var, $previous) . "\" rel=\"prev\">" . $this->_l10n->get($this->string_previous) . "</a>";
118
        }
119
120
        if ($this->_current_page < $page_count) {
121
            $next = $this->_current_page + 1;
122
            echo "\n<a class=\"next_page\" href=\"" . $this->_get_query_string($page_var, $next) . "\" rel=\"next\">" . $this->_l10n->get($this->string_next) . "</a>";
123
        }
124
125
        echo "\n</div>\n";
126
    }
127
128 1
    public function get_pages() : array
129
    {
130 1
        $pages = [];
131 1
        $page_count = $this->count_pages();
132
133 1
        if ($page_count < 1) {
134
            return $pages;
135
        }
136
137 1
        $page_var = $this->_prefix . 'page';
138 1
        $display_start = max(($this->_current_page - ceil($this->display_pages / 2)), 1);
139 1
        $display_end = min(($this->_current_page + ceil($this->display_pages / 2)), $page_count);
140
141 1
        if ($this->_current_page > 1) {
142
            $previous = $this->_current_page - 1;
143
            if ($previous > 1) {
144
                $pages[] = [
145
                    'class' => 'first',
146
                    'href' => $this->_get_query_string($page_var, 1),
147
                    'rel' => 'prev',
148
                    'label' => $this->_l10n->get('first'),
149
                    'number' => 1
150
                ];
151
            }
152
            $pages[] = [
153
                'class' => 'previous',
154
                'href' => $this->_get_query_string($page_var, $previous),
155
                'rel' => 'prev',
156
                'label' => $this->_l10n->get($this->string_previous),
157
                'number' => $previous
158
            ];
159
        }
160 1
        $page = $display_start - 1;
161 1
        while ($page++ < $display_end) {
162 1
            $href = false;
163 1
            if ($page != $this->_current_page) {
164
                $href = $this->_get_query_string($page_var, $page);
165
            }
166 1
            $pages[] = [
167 1
                'class' => 'current',
168 1
                'href' => $href,
169
                'rel' => false,
170 1
                'label' => $page,
171 1
                'number' => $page
172
            ];
173
        }
174
175 1
        if ($this->_current_page < $page_count) {
176
            $next = $this->_current_page + 1;
177
            $pages[] = [
178
                'class' => 'next',
179
                'href' => $this->_get_query_string($page_var, $next),
180
                'rel' => 'next',
181
                'label' => $this->_l10n->get($this->string_next),
182
                'number' => $next
183
            ];
184
185
            if ($next < $page_count) {
186
                $pages[] = [
187
                    'class' => 'last',
188
                    '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

188
                    'href' => $this->_get_query_string($page_var, /** @scrutinizer ignore-type */ $page_count),
Loading history...
189
                    'rel' => 'next',
190
                    'label' => $this->_l10n->get('last'),
191
                    'number' => $page_count
192
                ];
193
            }
194
        }
195
196 1
        return $pages;
197
    }
198
199 1
    private function show(string $name, array $data)
200
    {
201 1
        $context = midcom_core_context::enter();
202 1
        $context->set_custom_key('request_data', $data);
203 1
        midcom::get()->style->prepend_component_styledir($this->_component);
204 1
        midcom::get()->style->enter_context($context);
205 1
        midcom_show_style('show_' . $name);
206 1
        midcom::get()->style->leave_context();
207 1
        midcom_core_context::leave();
208 1
    }
209
210
    /**
211
     * Displays page selector
212
     */
213 1
    public function show_pages()
214
    {
215 1
        $this->show('pages', ['pages' => $this->get_pages()]);
216 1
    }
217
218
    /**
219
     * Displays page selector as list
220
     */
221
    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...
222
    {
223
        $this->show('pages_as_list', ['pages' => $this->get_pages()]);
224
    }
225
226
    /**
227
     * sets LIMIT and OFFSET for requested page
228
     */
229 14
    protected function _qb_limits($qb)
230
    {
231 14
        $this->_check_page_vars();
232
233 14
        if ($this->_current_page == 'all') {
234
            debug_add("displaying all results");
235
            return;
236
        }
237
238 14
        $qb->set_limit($this->results_per_page);
239 14
        $qb->set_offset($this->_offset);
240 14
        debug_add("set offset to {$this->_offset} and limit to {$this->results_per_page}");
241 14
    }
242
243 14
    public function execute() : array
244
    {
245 14
        $this->_sanity_check();
246 14
        $this->_qb_limits($this->_midcom_qb);
247 14
        return $this->_midcom_qb->execute();
248
    }
249
250
    public function execute_unchecked() : array
251
    {
252
        $this->_sanity_check();
253
        $this->_qb_limits($this->_midcom_qb);
254
        return $this->_midcom_qb->execute_unchecked();
255
    }
256
257
    /**
258
     * Returns number of total pages for query
259
     *
260
     * By default returns a number of pages without any ACL checks
261
     */
262 6
    public function count_pages()
263
    {
264 6
        $this->_sanity_check();
265 6
        $this->count_unchecked();
266 6
        return ceil($this->count / $this->results_per_page);
267
    }
268
269
    //Rest of supported methods wrapped with extra sanity check
270 14
    public function add_constraint(string $param, string $op, $val) : bool
271
    {
272 14
        $this->_midcom_qb_count->add_constraint($param, $op, $val);
273 14
        return $this->_midcom_qb->add_constraint($param, $op, $val);
274
    }
275
276 13
    public function add_order(string $param, string $sort = 'ASC') : bool
277
    {
278 13
        return $this->_midcom_qb->add_order($param, $sort);
279
    }
280
281 2
    public function begin_group($type)
282
    {
283 2
        $this->_midcom_qb_count->begin_group($type);
284 2
        $this->_midcom_qb->begin_group($type);
285 2
    }
286
287 2
    public function end_group()
288
    {
289 2
        $this->_midcom_qb_count->end_group();
290 2
        $this->_midcom_qb->end_group();
291 2
    }
292
293 1
    public function include_deleted()
294
    {
295 1
        $this->_midcom_qb_count->include_deleted();
296 1
        $this->_midcom_qb->include_deleted();
297 1
    }
298
299
    public function count() : int
300
    {
301
        $this->_sanity_check();
302
        if (   !$this->count
303
            || $this->_count_mode != 'count') {
304
            $this->count = $this->_midcom_qb_count->count();
305
        }
306
        $this->_count_mode = 'count';
307
        return $this->count;
308
    }
309
310 6
    public function count_unchecked() : int
311
    {
312 6
        $this->_sanity_check();
313 6
        if (   !$this->count
314 6
            || $this->_count_mode != 'count_unchecked') {
315 6
            $this->count = $this->_midcom_qb_count->count_unchecked();
316
        }
317 6
        $this->_count_mode = 'count_unchecked';
318 6
        return $this->count;
319
    }
320
}
321