Passed
Push — main ( 1a0bc1...893379 )
by Thierry
01:55
created

Util::selectValue()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 27
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 5
eloc 9
c 2
b 0
f 0
nc 4
nop 3
dl 0
loc 27
rs 9.6111
1
<?php
2
3
namespace Lagdo\DbAdmin\Db;
4
5
use Lagdo\DbAdmin\Driver\Entity\TableEntity;
6
use Lagdo\DbAdmin\Driver\Entity\TableFieldEntity;
7
use Lagdo\DbAdmin\Driver\Input;
8
use Lagdo\DbAdmin\Driver\TranslatorInterface;
9
use Lagdo\DbAdmin\Driver\UtilInterface;
10
use Lagdo\DbAdmin\Driver\UtilTrait;
0 ignored issues
show
Bug introduced by
The type Lagdo\DbAdmin\Driver\UtilTrait was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
12
use function preg_match;
13
use function strlen;
14
15
class Util implements UtilInterface
16
{
17
    use UtilTrait;
18
    use Traits\UtilTrait;
19
    use Traits\SelectUtilTrait;
20
    use Traits\QueryInputTrait;
21
    use Traits\DumpUtilTrait;
22
23
    /**
24
     * The constructor
25
     *
26
     * @param TranslatorInterface $trans
27
     * @param Input $input
28
     */
29
    public function __construct(TranslatorInterface $trans, Input $input)
30
    {
31
        $this->trans = $trans;
0 ignored issues
show
Bug Best Practice introduced by
The property trans does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
32
        $this->input = $input;
0 ignored issues
show
Bug Best Practice introduced by
The property input does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
33
    }
34
35
    /**
36
     * @inheritDoc
37
     */
38
    public function name(): string
39
    {
40
        return '<a href="https://www.adminer.org/"' . $this->blankTarget() . ' id="h1">Adminer</a>';
41
    }
42
43
    /**
44
     * Get a target="_blank" attribute
45
     *
46
     * @return string
47
     */
48
    public function blankTarget(): string
49
    {
50
        return ' target="_blank" rel="noreferrer noopener"';
51
    }
52
53
    /**
54
     * Find unique identifier of a row
55
     *
56
     * @param array $row
57
     * @param array $indexes Result of indexes()
58
     *
59
     * @return array
60
     */
61
    public function uniqueIds(array $row, array $indexes): array
62
    {
63
        foreach ($indexes as $index) {
64
            if (preg_match('~PRIMARY|UNIQUE~', $index->type)) {
65
                $ids = [];
66
                foreach ($index->columns as $key) {
67
                    if (!isset($row[$key])) { // NULL is ambiguous
68
                        continue 2;
69
                    }
70
                    $ids[$key] = $row[$key];
71
                }
72
                return $ids;
73
            }
74
        }
75
        return [];
76
    }
77
78
    /**
79
     * Table caption used in navigation and headings
80
     *
81
     * @param TableEntity $table
82
     *
83
     * @return string
84
     */
85
    public function tableName(TableEntity $table): string
86
    {
87
        return $this->html($table->name);
88
    }
89
90
    /**
91
     * Field caption used in select and edit
92
     *
93
     * @param TableFieldEntity $field Single field returned from fields()
94
     * @param int $order Order of column in select
95
     *
96
     * @return string
97
     */
98
    public function fieldName(TableFieldEntity $field, /** @scrutinizer ignore-unused */ int $order = 0): string
99
    {
100
        return '<span title="' . $this->html($field->fullType) . '">' . $this->html($field->name) . '</span>';
101
    }
102
103
    /**
104
     * @param TableFieldEntity $field
105
     * @param array $values First entries
106
     * @param bool $update
107
     *
108
     * @return string[]
109
     */
110
    private function getEditFunctionNames(TableFieldEntity $field, array $values, bool $update): array
111
    {
112
        $names = $values;
113
        foreach ($this->driver->editFunctions() as $key => $functions) {
114
            if (!$key || (!isset($this->input->values['call']) && $update)) { // relative functions
115
                foreach ($functions as $pattern => $value) {
116
                    if (!$pattern || preg_match("~$pattern~", $field->type)) {
117
                        $names[] = $value;
118
                    }
119
                }
120
            }
121
            if ($key && !preg_match('~set|blob|bytea|raw|file|bool~', $field->type)) {
122
                $names[] = 'SQL';
123
            }
124
        }
125
        return $names;
126
    }
127
128
    /**
129
     * Functions displayed in edit form
130
     *
131
     * @param TableFieldEntity $field Single field from fields()
132
     *
133
     * @return array
134
     */
135
    public function editFunctions(TableFieldEntity $field): array
136
    {
137
        $update = isset($this->input->values['select']); // || $this->where([]);
138
        if ($field->autoIncrement && !$update) {
139
            return [$this->trans->lang('Auto Increment')];
140
        }
141
142
        $names = ($field->null ? ['NULL', ''] : ['']);
143
        return $this->getEditFunctionNames($field, $names, $update);
144
    }
145
146
    /**
147
     * Value printed in select table
148
     *
149
     * @param mixed $value HTML-escaped value to print
150
     * @param string $type Field type
151
     * @param mixed $original Original value before escaping
152
     *
153
     * @return string
154
     */
155
    private function getSelectFieldValue($value, string $type, $original): string
156
    {
157
        if ($value === null) {
158
            return '<i>NULL</i>';
159
        }
160
        if (preg_match('~char|binary|boolean~', $type) && !preg_match('~var~', $type)) {
161
            return "<code>$value</code>";
162
        }
163
        if (preg_match('~blob|bytea|raw|file~', $type) && !$this->isUtf8($value)) {
164
            return '<i>' . $this->trans->lang('%d byte(s)', strlen($original)) . '</i>';
165
        }
166
        if (preg_match('~json~', $type)) {
167
            return "<code>$value</code>";
168
        }
169
        if ($this->isMail($value)) {
170
            return '<a href="' . $this->html("mailto:$value") . '">' . $value . '</a>';
171
        }
172
        elseif ($this->isUrl($value)) {
173
            // IE 11 and all modern browsers hide referrer
174
            return '<a href="' . $this->html($value) . '"' . $this->blankTarget() . '>' . $value . '</a>';
175
        }
176
        return $value;
177
    }
178
179
    /**
180
     * Format value to use in select
181
     *
182
     * @param TableFieldEntity $field
183
     * @param mixed $value
184
     * @param int|string|null $textLength
185
     *
186
     * @return string
187
     */
188
    public function selectValue(TableFieldEntity $field, $value, $textLength): string
189
    {
190
        // if (\is_array($value)) {
191
        //     $expression = '';
192
        //     foreach ($value as $k => $v) {
193
        //         $expression .= '<tr>' . ($value != \array_values($value) ?
194
        //             '<th>' . $this->html($k) :
195
        //             '') . '<td>' . $this->selectValue($field, $v, $textLength);
196
        //     }
197
        //     return "<table cellspacing='0'>$expression</table>";
198
        // }
199
        // if (!$link) {
200
        //     $link = $this->selectLink($value, $field);
201
        // }
202
        $expression = $value;
203
        if (!empty($expression)) {
204
            if (!$this->isUtf8($expression)) {
205
                $expression = "\0"; // htmlspecialchars of binary data returns an empty string
206
            } elseif ($textLength != '' && $this->isShortable($field)) {
207
                // usage of LEFT() would reduce traffic but complicate query -
208
                // expected average speedup: .001 s VS .01 s on local network
209
                $expression = $this->shortenUtf8($expression, \max(0, +$textLength));
210
            } else {
211
                $expression = $this->html($expression);
212
            }
213
        }
214
        return $this->getSelectFieldValue($expression, $field->type, $value);
215
    }
216
217
    /**
218
     * Create SQL string from field type
219
     *
220
     * @param TableFieldEntity $field
221
     * @param string $collate
222
     *
223
     * @return string
224
     */
225
    private function processType(TableFieldEntity $field, string $collate = 'COLLATE'): string
226
    {
227
        $collation = '';
228
        if (preg_match('~char|text|enum|set~', $field->type) && $field->collation) {
229
            $collation = " $collate " . $this->driver->quote($field->collation);
230
        }
231
        $sign = '';
232
        if (preg_match($this->driver->numberRegex(), $field->type) && in_array($field->unsigned, $this->driver->unsigned())) {
233
            $sign = ' ' . $field->unsigned;
234
        }
235
        return ' ' . $field->type . $this->processLength($field->length) . $sign . $collation;
236
    }
237
238
    /**
239
     * Create SQL string from field
240
     *
241
     * @param TableFieldEntity $field Basic field information
242
     * @param TableFieldEntity $typeField Information about field type
243
     *
244
     * @return array
245
     */
246
    public function processField(TableFieldEntity $field, TableFieldEntity $typeField): array
247
    {
248
        $onUpdate = '';
249
        if (preg_match('~timestamp|datetime~', $field->type) && $field->onUpdate) {
250
            $onUpdate = ' ON UPDATE ' . $field->onUpdate;
251
        }
252
        $comment = '';
253
        if ($this->driver->support('comment') && $field->comment !== '') {
254
            $comment = ' COMMENT ' . $this->driver->quote($field->comment);
255
        }
256
        $null = $field->null ? ' NULL' : ' NOT NULL'; // NULL for timestamp
257
        $autoIncrement = $field->autoIncrement ? $this->driver->autoIncrement() : null;
258
        return [$this->driver->escapeId(trim($field->name)), $this->processType($typeField),
259
            $null, $this->driver->defaultValue($field), $onUpdate, $comment, $autoIncrement];
260
    }
261
}
262