Passed
Push — main ( 364dc0...5d7b01 )
by Thierry
01:43
created

TableSelectAdmin::getSelectEntity()   B

Complexity

Conditions 10
Paths 18

Size

Total Lines 30
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 10
eloc 18
c 2
b 0
f 0
nc 18
nop 10
dl 0
loc 30
rs 7.6666

How to fix   Complexity    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace Lagdo\DbAdmin\DbAdmin;
4
5
use Lagdo\DbAdmin\Driver\Entity\TableFieldEntity;
6
7
use Exception;
8
9
use function count;
10
use function str_replace;
11
use function compact;
12
use function preg_match;
13
use function microtime;
14
use function trim;
15
use function md5;
16
use function strlen;
17
use function strpos;
18
19
/**
20
 * Admin table select functions
21
 */
22
class TableSelectAdmin extends AbstractAdmin
23
{
24
    use Traits\TableSelectTrait;
1 ignored issue
show
introduced by
The trait Lagdo\DbAdmin\DbAdmin\Traits\TableSelectTrait requires some properties which are not provided by Lagdo\DbAdmin\DbAdmin\TableSelectAdmin: $privileges, $oid, $columns, $type
Loading history...
25
26
    /**
27
     * @param array $select
28
     * @param array $columns
29
     * @param array $indexes
30
     * @param int $limit
31
     * @param int $textLength
32
     * @param array $queryOptions
33
     *
34
     * @return array
35
     */
36
    private function getAllOptions(array $select, array $columns, array $indexes,
37
        int $limit, int $textLength, array $queryOptions): array
38
    {
39
        return [
40
            'columns' => $this->getColumnsOptions($select, $columns, $queryOptions),
41
            'filters' => $this->getFiltersOptions($columns, $indexes, $queryOptions),
42
            'sorting' => $this->getSortingOptions($columns, $queryOptions),
43
            'limit' => $this->getLimitOptions($limit),
44
            'length' => $this->getLengthOptions($textLength),
45
            // 'action' => $this->getActionOptions($indexes),
46
        ];
47
    }
48
49
    /**
50
     * Get required data for create/update on tables
51
     *
52
     * @param string $table The table name
53
     * @param array $queryOptions The query options
54
     *
55
     * @return array
56
     * @throws Exception
57
     */
58
    private function prepareSelect(string $table, array &$queryOptions = []): array
59
    {
60
        $page = $this->setDefaultOptions($queryOptions);
61
        $this->util->input()->setValues($queryOptions);
0 ignored issues
show
Bug introduced by
The method setValues() does not exist on Lagdo\DbAdmin\Driver\InputInterface. ( Ignorable by Annotation )

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

61
        $this->util->input()->/** @scrutinizer ignore-call */ setValues($queryOptions);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
62
63
        // From select.inc.php
64
        $fields = $this->driver->fields($table);
65
        list(, $columns, $textLength) = $this->getFieldsOptions($fields);
66
        if (!$columns && $this->driver->support("table")) {
67
            throw new Exception($this->trans->lang('Unable to select the table') .
68
                ($fields ? "." : ": " . $this->driver->error()));
69
        }
70
71
        $indexes = $this->driver->indexes($table);
72
        $foreignKeys = $this->admin->columnForeignKeys($table);
73
        list($select, $group) = $this->util->processSelectColumns();
74
        $where = $this->util->processSelectSearch($fields, $indexes);
75
        $order = $this->util->processSelectOrder();
76
        $limit = $this->util->processSelectLimit();
77
        $tableStatus = $this->driver->tableStatusOrName($table);
78
        $unselected = $this->setPrimaryKey($indexes, $select, $tableStatus);
79
        $tableName = $this->util->tableName($tableStatus);
80
81
        // $set = null;
82
        // if(isset($rights["insert"]) || !support("table")) {
83
        //     $set = "";
84
        //     foreach((array) $queryOptions["where"] as $val) {
85
        //         if($foreignKeys[$val["col"]] && count($foreignKeys[$val["col"]]) == 1 && ($val["op"] == "="
86
        //             || (!$val["op"] && !preg_match('~[_%]~', $val["val"])) // LIKE in Editor
87
        //         )) {
88
        //             $set .= "&set" . urlencode("[" . $this->util->bracketEscape($val["col"]) . "]") . "=" . urlencode($val["val"]);
89
        //         }
90
        //     }
91
        // }
92
        // $this->util->selectLinks($tableStatus, $set);
93
94
        // if($page == "last")
95
        // {
96
        //     $isGroup = count($group) < count($select);
97
        //     $found_rows = $this->driver->result($this->driver->sqlForRowCount($table, $where, $isGroup, $group));
98
        //     $page = \floor(\max(0, $found_rows - 1) / $limit);
99
        // }
100
101
        $options = $this->getAllOptions($select, $columns, $indexes, $limit, $textLength, $queryOptions);
102
        $entity = $this->getSelectEntity($table, $columns, $fields, $select, $group, $where, $order, $unselected, $limit, $page);
103
        $query = $this->driver->buildSelectQuery($entity);
104
        // From adminer.inc.php
105
        $query = str_replace("\n", " ", $query);
106
107
        return [$options, $query, $select, $fields, $foreignKeys, $columns, $indexes,
108
            $where, $group, $order, $limit, $page, $textLength, $tableName, $unselected];
109
    }
110
111
    /**
112
     * Get required data for create/update on tables
113
     *
114
     * @param string $table The table name
115
     * @param array $queryOptions The query options
116
     *
117
     * @return array
118
     * @throws Exception
119
     */
120
    public function getSelectData(string $table, array $queryOptions = []): array
121
    {
122
        list($options, $query) = $this->prepareSelect($table, $queryOptions);
123
124
        $query = $this->util->html($query);
125
        $mainActions = [
126
            'select-exec' => $this->trans->lang('Execute'),
127
            'insert-table' => $this->trans->lang('New item'),
128
            'select-back' => $this->trans->lang('Back'),
129
        ];
130
131
        return compact('mainActions', 'options', 'query');
132
    }
133
134
    /**
135
     * @param string $query
136
     * @param int $page
137
     *
138
     * @return array
139
     */
140
    private function executeQuery(string $query, int $page): array
141
    {
142
        // From driver.inc.php
143
        $start = microtime(true);
144
        $statement = $this->driver->execute($query);
145
        // From adminer.inc.php
146
        $duration = $this->trans->formatTime($start); // Compute and format the duration
147
148
        if (!$statement) {
149
            return ['error' => $this->driver->error()];
150
        }
151
        // From select.inc.php
152
        $rows = [];
153
        while (($row = $statement->fetchAssoc())) {
154
            if ($page && $this->driver->jush() == "oracle") {
155
                unset($row["RNUM"]);
156
            }
157
            $rows[] = $row;
158
        }
159
160
        return [$rows, $duration];
161
    }
162
163
    /**
164
     * @param array $rows
165
     * @param array $select
166
     * @param array $fields
167
     * @param array $unselected
168
     * @param array $queryOptions
169
     *
170
     * @return array
171
     */
172
    private function getResultHeaders(array $rows, array $select, array $fields, array $unselected, array $queryOptions): array
173
    {
174
        // Results headers
175
        $headers = [
176
            '', // !$group && $select ? '' : lang('Modify');
177
        ];
178
        $names = [];
179
        // $functions = [];
180
        reset($select);
181
        $rank = 1;
182
        foreach ($rows[0] as $key => $value) {
183
            $header = [];
184
            if (!isset($unselected[$key])) {
185
                $value = $queryOptions["columns"][key($select)] ?? [];
186
                $fun = $value["fun"] ?? '';
187
                $field = $fields[$select ? ($value ? $value["col"] : current($select)) : $key];
188
                $name = ($field ? $this->util->fieldName($field, $rank) : ($fun ? "*" : $key));
189
                $header = compact('value', 'field', 'name');
190
                if ($name != "") {
191
                    $rank++;
192
                    $names[$key] = $name;
193
                    $column = $this->driver->escapeId($key);
194
                    // $href = remove_from_uri('(order|desc)[^=]*|page') . '&order%5B0%5D=' . urlencode($key);
195
                    // $desc = "&desc%5B0%5D=1";
196
                    $header['column'] = $column;
197
                    $header['key'] = $this->util->html($this->util->bracketEscape($key));
198
                    $header['sql'] = $this->util->applySqlFunction($fun, $name); //! columns looking like functions
199
                }
200
                // $functions[$key] = $fun;
201
                next($select);
202
            }
203
            $headers[] = $header;
204
        }
205
        return [$headers, $names];
206
    }
207
208
    /**
209
     * @param array $rows
210
     * @param array $queryOptions
211
     *
212
     * @return array
213
     */
214
    /*private function getValuesLengths(array $rows, array $queryOptions): array
215
    {
216
         $lengths = [];
217
         if($queryOptions["modify"])
218
         {
219
             foreach($rows as $row)
220
             {
221
                 foreach($row as $key => $value)
222
                 {
223
                     $lengths[$key] = \max($lengths[$key], \min(40, strlen(\utf8_decode($value))));
224
                 }
225
             }
226
         }
227
         return $lengths;
228
    }*/
229
230
    /**
231
     * @param array $row
232
     * @param array $indexes
233
     *
234
     * @return array
235
     */
236
    private function getUniqueIds(array $row, array $indexes): array
237
    {
238
        $uniqueIds = $this->util->uniqueIds($row, $indexes);
239
        if (empty($uniqueIds)) {
240
            $pattern = '~^(COUNT\((\*|(DISTINCT )?`(?:[^`]|``)+`)\)|(AVG|GROUP_CONCAT|MAX|MIN|SUM)\(`(?:[^`]|``)+`\))$~';
241
            foreach ($row as $key => $value) {
242
                if (!preg_match($pattern, $key)) {
243
                    //! columns looking like functions
244
                    $uniqueIds[$key] = $value;
245
                }
246
            }
247
        }
248
        return $uniqueIds;
249
    }
250
251
    /**
252
     * @param array $row
253
     * @param array $fields
254
     * @param array $indexes
255
     *
256
     * @return array
257
     */
258
    private function getRowIds(array $row, array $fields, array $indexes): array
259
    {
260
        $uniqueIds = $this->getUniqueIds($row, $indexes);
261
        // Unique identifier to edit returned data.
262
        // $unique_idf = "";
263
        $rowIds = ['where' => [], 'null' => []];
264
        foreach ($uniqueIds as $key => $value) {
265
            $key = trim($key);
266
            $type = '';
267
            $collation = '';
268
            if (isset($fields[$key])) {
269
                $type = $fields[$key]->type;
270
                $collation = $fields[$key]->collation;
271
            }
272
            if (($this->driver->jush() == "sql" || $this->driver->jush() == "pgsql") &&
273
                preg_match('~char|text|enum|set~', $type) && strlen($value) > 64) {
274
                $key = (strpos($key, '(') ? $key : $this->driver->escapeId($key)); //! columns looking like functions
275
                $key = "MD5(" . ($this->driver->jush() != 'sql' || preg_match("~^utf8~", $collation) ?
276
                        $key : "CONVERT($key USING " . $this->driver->charset() . ")") . ")";
277
                $value = md5($value);
278
            }
279
            if ($value !== null) {
280
                $rowIds['where'][$this->util->bracketEscape($key)] = $value;
281
            } else {
282
                $rowIds['null'][] = $this->util->bracketEscape($key);
283
            }
284
            // $unique_idf .= "&" . ($value !== null ? \urlencode("where[" . $this->util->bracketEscape($key) . "]") .
285
            //     "=" . \urlencode($value) : \urlencode("null[]") . "=" . \urlencode($key));
286
        }
287
        return $rowIds;
288
    }
289
290
    /**
291
     * @param array $row
292
     * @param array $fields
293
     * @param array $names
294
     * @param int $textLength
295
     *
296
     * @return array
297
     */
298
    private function getRowColumns(array $row, array $fields, array $names, int $textLength): array
299
    {
300
        $cols = [];
301
        foreach ($row as $key => $value) {
302
            if (isset($names[$key])) {
303
                $field = $fields[$key] ?? new TableFieldEntity();
304
                $value = $this->driver->value($value, $field);
305
                /*if ($value != "" && (!isset($email_fields[$key]) || $email_fields[$key] != "")) {
306
                    //! filled e-mails can be contained on other pages
307
                    $email_fields[$key] = ($this->util->isMail($value) ? $names[$key] : "");
308
                }*/
309
                $link = "";
310
                $cols[] = [
311
                    // 'id',
312
                    'text' => preg_match('~text|lob~', $field->type),
313
                    'value' => $this->util->selectValue($value, $link, $field, $textLength),
314
                    // 'editable' => false,
315
                ];
316
            }
317
        }
318
        return $cols;
319
    }
320
321
    /**
322
     * Get required data for create/update on tables
323
     *
324
     * @param string $table The table name
325
     * @param array $queryOptions The query options
326
     *
327
     * @return array
328
     * @throws Exception
329
     */
330
    public function execSelect(string $table, array $queryOptions): array
331
    {
332
        list(, $query, $select, $fields, , , $indexes, $where, $group, , $limit, $page,
333
            $textLength, , $unselected) = $this->prepareSelect($table, $queryOptions);
334
335
        list($rows, $duration) = $this->executeQuery($query, $page);
336
        if (!$rows) {
337
            return ['error' => $this->trans->lang('No rows.')];
338
        }
339
        // $backward_keys = $this->driver->backwardKeys($table, $tableName);
340
        // lengths = $this->getValuesLengths($rows, $queryOptions);
341
342
        list($headers, $names) = $this->getResultHeaders($rows, $select, $fields, $unselected, $queryOptions);
343
344
        $results = [];
345
        foreach ($rows as $row) {
346
            // Unique identifier to edit returned data.
347
            $rowIds = $this->getRowIds($row, $fields, $indexes);
348
            $cols = $this->getRowColumns($row, $fields, $names, $textLength);
349
            $results[] = ['ids' => $rowIds, 'cols' => $cols];
350
        }
351
352
        $isGroup = count($group) < count($select);
353
        $total = $this->driver->result($this->driver->sqlForRowCount($table, $where, $isGroup, $group));
354
355
        $rows = $results;
356
        $error = null;
357
        return compact('duration', 'headers', 'query', 'rows', 'limit', 'total', 'error');
358
    }
359
}
360