SearchController::getSearchResults()   F
last analyzed

Complexity

Conditions 32
Paths > 20000

Size

Total Lines 146
Code Lines 91

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 32
eloc 91
nc 15926976
nop 3
dl 0
loc 146
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace FFCMS\Traits;
4
5
/**
6
 * Controller Methods which utilise a mapper to search and list results
7
 */
8
trait SearchController
9
{
10
    /**
11
     * Create an internal URL
12
     * Uses method from
13
     * @see \FFCMS\Helpers\UrlHelper
14
     * @param string $url
15
     * @param array $params
16
     */
17
    abstract public function url(string $url, array $params = []): string;
18
19
20
    /**
21
     * Check the order by field is valid and return it corrected
22
     *
23
     * @param null|string $order order field in form of: "field1 ASC/DESC,field 2 ASC/DESC.."
24
     * @param array $allFields the list of fields which are valid to order by
25
     * @return string $validFields
26
     */
27
    public static function checkOrderField(string $order = null, array $allFields = []): string
28
    {
29
        if (empty($order)) {
30
            return join(',', $allFields);
31
        }
32
33
        $orderClauses = empty($order) ? [] : preg_split("/[,]/", $order);
34
        foreach ($orderClauses as $k => $field) {
35
            // split into field, asc/desc
36
            $field = preg_split("/[\s]+/", trim($field));
37
            if (!in_array($field[0], $allFields)) {
38
                // invalid field
39
                unset($orderClauses[$k]);
40
                continue;
41
            } elseif (count($field) == 1) {
42
                $field[1] = 'asc';
43
            } elseif (count($field) == 2) {
44
                if (!in_array($field[1], ['asc', 'desc'])) {
45
                    $field[1] = 'asc';
46
                }
47
            }
48
            $orderClauses[$k] = $field[0] . ' ' . $field[1];
49
        }
50
        ksort($orderClauses);
51
        $order = join(',', $orderClauses);
52
53
        return $order;
54
    }
55
56
57
    /**
58
     * Check the fields exist and return only the existing ones
59
     *
60
     * @param array $checkFieldsExist [id => 'field1,field2'...]
61
     * @param array $fieldsList the list of fields which are valid
62
     * @return array $validFields
63
     */
64
    public static function checkFieldsExist(array $checkFieldsExist = [], array $fieldsList = []): array
65
    {
66
        // fields to return and fields to search - validate
67
        $validFields = [];
68
        foreach ($checkFieldsExist as $id => $fields) {
69
            if (empty($fields)) {
70
                continue;
71
            }
72
            $fields = empty($fields) ? [] : preg_split("/[,]/", $fields);
73
            foreach ($fields as $k => $field) {
74
                if (!in_array($field, $fieldsList)) {
75
                    unset($fields[$k]);
76
                }
77
            }
78
            $validFields[$id] = join(',', $fields);
79
        }
80
        return $validFields;
81
    }
82
83
84
   /**
85
     * list objects (list is a reserved keyword) of mapper
86
     *
87
     * @param \Base $f3
88
     * @param \FFCMS\Mappers\Mapper $m
89
     * @return array
90
     */
91
    protected function &getListingResults(\Base $f3, \FFCMS\Mappers\Mapper $m, string $users_uuid = null): array
92
    {
93
        // set up paging limits
94
        $minPerPage = 5;
95
        $maxPerPage = 1024;
96
        $perPage = (int) $f3->get('REQUEST.per_page');
97
        if ($perPage < $minPerPage) {
98
            $perPage = $minPerPage;
99
        }
100
        if ($perPage > $maxPerPage) {
101
            $perPage = $maxPerPage;
102
        }
103
104
        $page = $f3->get('REQUEST.page');
105
        if ($page < 1) {
106
            $page = 1;
107
        }
108
109
        // fetch data (paging is 0 based)
110
        $allFields = $m->fields();
111
112
        // validate order field
113
        $order = self::checkOrderField($f3->get('REQUEST.order'), $allFields);
114
115
        // validated fields to return
116
        $validFields = self::checkFieldsExist([$f3->get('REQUEST.fields')], $allFields);
117
        $fields = empty($validFields['fields']) ? join(',', $allFields) : $validFields['fields'];
118
119
        // count rows
120
        $data = [];
121
122
        // count rows
123
        $isAdmin = $f3->get('isAdmin');
124
        $rows = 0;
125
        if  (in_array('users_uuid', $allFields) && !empty($users_uuid)) {
126
            $rows = $m->count(['users_uuid = ?', $users_uuid]);
127
        } elseif ($isAdmin && empty($users_uuid)) {
128
            $rows = $m->count();
129
        }
130
        if ($rows < 1) {
131
            return $data;
132
        }
133
134
        // if fewer results than per page, set per_page
135
        if ($page == 1 && $perPage > $rows) {
136
            $perPage = $rows;
137
        }
138
139
        $pagination = [];
140
        $pagination['count'] = ceil($rows / $perPage);
141
142
        // too high page number?
143
        if ($page > $pagination['count']) {
144
            $page = $pagination['count'];
145
        }
146
147
        // set up page URLs
148
        $url = $f3->get('PATH');
149
        $urlParams = [
150
            'per_page' => $perPage,
151
        ];
152
        if (!empty($order)) {
153
            $urlParams['order'] = $order;
154
        }
155
        if (!empty($fields)) {
156
            $urlParams['fields'] = $fields;
157
        }
158
        ksort($urlParams);
159
160
        // next/previous page url
161
        $prevPage = (1 > $page - 1 ) ? null : $page - 1;
162
        $nextPage = (1 + $page > $pagination['count']) ? null : $page + 1;
163
164
        $resultsFrom = round($page * ($rows / $pagination['count'])) - $perPage + 1;
165
        $resultsTo = $resultsFrom + $perPage - 1;
166
167
        // return data
168
        $data['pagination'] = [
169
            'url_base' => $this->url($url, $urlParams),
170
            'url_current' => $this->url($url, $urlParams + ['page' => $page]),
171
            'url_first' => $this->url($url, $urlParams + ['page' => 1]),
172
            'url_last' => $this->url($url, $urlParams + ['page' => $pagination['count']]),
173
            'url_next' => (null == $nextPage) ? null : $this->url($url, $urlParams + ['page' => $nextPage]),
174
            'url_previous' => (null == $prevPage) ? null : $this->url($url, $urlParams + ['page' => $prevPage]),
175
            'results' => $rows,
176
            'results_from' => $resultsFrom,
177
            'results_to' => $resultsTo,
178
            'per_page' => $perPage,
179
            'pages' => $pagination['count'],
180
            'page' => $page,
181
            'object' => $m->table(),
182
            'fields' => preg_split("/[,]/", $fields),
183
            'view' => $f3->get('REQUEST.view')
184
        ];
185
186
187
        // fetch results
188
        if ($isAdmin && empty($users_uuid)) {
189
            $m->load(null, [
190
                'order' => $order,
191
                'offset' => (1 == $page) ? 0 : ($page - 1) * $perPage,
192
                'limit' => $perPage
193
            ]);
194
        } else {
195
            $m->load(['users_uuid = ?', $users_uuid], [
196
                'order' => $order,
197
                'offset' => (1 == $page) ? 0 : ($page - 1) * $perPage,
198
                'limit' => $perPage
199
            ]);
200
        }
201
202
        $adminView = $isAdmin || ($isAdmin && 'admin' == $f3->get('REQUEST.view'));
203
        do {
204
            $data['objects'][] = $adminView ? $m->castFields($fields) : $m->exportArray($fields);
205
        }
206
        while ($m->skip());
207
208
        return $data;
209
    }
210
211
    /**
212
     * search objects of given mapper
213
     *
214
     * @param \Base $f3
215
     * @param \FFCMS\Mappers\Mapper $m
216
     * @param string|null $users_uuid uuid of user to get results for
217
     * @return array $results
218
     */
219
    protected function &getSearchResults(\Base $f3, \FFCMS\Mappers\Mapper $m, string $users_uuid = null): array
220
    {
221
        // set up paging limits
222
        $minPerPage = 10;
223
        $maxPerPage = 100;
224
        $perPage = (int) $f3->get('REQUEST.per_page');
225
        if ($perPage < $minPerPage) {
226
            $perPage = $minPerPage;
227
        }
228
        if ($perPage > $maxPerPage) {
229
            $perPage = $maxPerPage;
230
        }
231
232
        $page = $f3->get('REQUEST.page');
233
        if ($page < 1) {
234
            $page = 1;
235
        }
236
237
        // fetch data (paging is 0 based)
238
        $allFields = $m->fields();
239
240
        // validate order field
241
        $order = self::checkOrderField($f3->get('REQUEST.order'), $allFields);
242
        $validFields = self::checkFieldsExist([$f3->get('REQUEST.fields'), $f3->get('REQUEST.search_fields')], $allFields);
243
244
        // validated fields to return
245
        $fields = empty($validFields['fields']) ? join(',', $allFields) : $validFields['fields'];
246
247
        // validated fields to search in, use all if empty
248
        $searchFields = empty($validFields['search_fields']) ? join(',', $allFields) : $validFields['search_fields'];
249
250
        // get search type
251
        $search = $f3->get('REQUEST.search');
252
        if (!empty($search)) {
253
            $search = trim(strtolower($search));
254
        }
255
        $search_type = $f3->get('REQUEST.search_type');
256
        if (empty($search_type)) {
257
            $search_type = 'exact';
258
        } elseif ($search_type !== 'exact') {
259
            $search_type = 'fuzzy';
260
        }
261
262
        // construct search query
263
        $db = \Registry::get('db');
264
        $sqlClauses = [];
265
        $searchFieldsArray = preg_split("/[,]/", $searchFields);
266
        foreach ($searchFieldsArray as $field) {
267
            $sqlClauses[] = 'LOWER(' . $db->quotekey($field) . ') = ' . $db->quote($search);
268
            if ($search_type == 'fuzzy') {
269
                $sqlClauses[] = 'LOWER(' . $db->quotekey($field) . ') LIKE ' . $db->quote('%' . $search . '%');
270
            }
271
        }
272
273
274
        // get total results
275
        $isAdmin = $f3->get('isAdmin');
276
        $query = 'SELECT COUNT(*) AS results FROM ' . $db->quotekey($m->table()) . ' WHERE ';
277
        if  (in_array('users_uuid', $allFields) && !empty($users_uuid)) {
278
            $query .= ' users_uuid = ' . $db->quote($users_uuid)  . ' AND ('.  join(' OR ', $sqlClauses) . ')';
279
        } elseif ($isAdmin && empty($users_uuid)) {
280
            $query .= join(' OR ', $sqlClauses);
281
        }
282
283
        $data = [];
284
        $rows = $db->exec($query);
285
        $rows = (int) $rows[0]['results'];
286
        if ($rows < 1) {
287
            return $data;
288
        }
289
290
        // if fewer results than per page, set per_page
291
        if ($page == 1 && $perPage > $rows) {
292
            $perPage = $rows;
293
        }
294
295
        $pagination = [];
296
        $pagination['count'] = (int) ceil($rows / $perPage);
297
298
        // too high page number?
299
        if ($page > $pagination['count']) {
300
            $page = $pagination['count'];
301
        }
302
303
        // set up page URLs
304
        $url = $f3->get('PATH');
305
        $urlParams = [
306
            'per_page' => $perPage,
307
            'search' => $search,
308
            'search_type' => $search_type,
309
        ];
310
        if (!empty($order)) {
311
            $urlParams['order'] = $order;
312
        }
313
        if (!empty($fields)) {
314
            $urlParams['fields'] = $fields;
315
        }
316
        ksort($urlParams);
317
318
        // previous page url
319
        $prevPage = (1 > $page - 1 ) ? null : $page - 1;
320
        $nextPage = (1 + $page > $pagination['count']) ? null : $page + 1;
321
322
        $resultsFrom = 1 + ($page * $perPage) - $perPage;
323
        $resultsTo = $resultsFrom + $perPage - 1;
324
        if ($resultsTo > $rows) {
325
            $resultsTo = $rows;
326
        }
327
328
        // return data
329
        $data['pagination'] = [
330
            'url_base' => $this->url($url, $urlParams),
331
            'url_current' => $this->url($url, $urlParams + ['page' => $page]),
332
            'url_first' => $this->url($url, $urlParams + ['page' => 1]),
333
            'url_last' => $this->url($url, $urlParams + ['page' => $pagination['count']]),
334
            'url_next' => (null == $nextPage) ? null : $this->url($url, $urlParams + ['page' => $nextPage]),
335
            'url_previous' => (null == $prevPage) ? null : $this->url($url, $urlParams + ['page' => $prevPage]),
336
            'results' => $rows,
337
            'results_from' => $resultsFrom,
338
            'results_to' => $resultsTo,
339
            'per_page' => $perPage,
340
            'pages' => $pagination['count'],
341
            'page' => $page,
342
            'object' => $m->table(),
343
            'fields' => preg_split("/[,]/", $fields),
344
            'view' => $f3->get('REQUEST.view')
345
        ];
346
347
348
        // retrieve results
349
        $query = 'SELECT * FROM ' . $db->quotekey($m->table()) . ' WHERE ';
350
        if (empty($users_uuid)) {
351
             $query .= join(' OR ', $sqlClauses);
352
        } else {
353
             $query .= ' users_uuid = ' . $db->quote($users_uuid)  . ' AND ('.  join(' OR ', $sqlClauses) . ')';
354
        }
355
        $query .= sprintf(' LIMIT %d,%d', (1 == $page) ? 0 : ($page - 1) * $perPage, $perPage);
356
357
        $adminView = $isAdmin || ($isAdmin && 'admin' == $f3->get('REQUEST.view'));
358
        $results = $db->exec($query);
359
        foreach ($results as $row) {
360
            $data['objects'][] = $adminView ? $m->castFields($fields, $row) : $m->exportArray($fields, $row);
361
        }
362
363
        return $data;
364
    }
365
366
}
367