Test Failed
Branch main (71ef7e)
by Rafael
10:37 queued 05:04
created

SqlMySql::getFieldQuote()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Alxarafe. Development of PHP applications in a flash!
4
 * Copyright (C) 2018 Alxarafe <[email protected]>
5
 */
6
7
namespace Alxarafe\Database\SqlHelpers;
8
9
use Alxarafe\Core\Helpers\Utils;
0 ignored issues
show
Bug introduced by
The type Alxarafe\Core\Helpers\Utils 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...
10
use Alxarafe\Core\Singletons\Config;
11
use Alxarafe\Core\Singletons\DebugTool;
0 ignored issues
show
Bug introduced by
The type Alxarafe\Core\Singletons\DebugTool 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...
12
use Alxarafe\Database\DB;
13
use Alxarafe\Database\Schema;
14
use Alxarafe\Database\SqlHelper;
15
16
/**
17
 * Clase abstracta para la presonalización de las consultas según el motor utilizado.
18
 */
19
class SqlMySql extends SqlHelper
20
{
21
    public static function getTableQuote(): string
22
    {
23
        return '`';
24
    }
25
26
    public static function getFieldQuote(): string
27
    {
28
        return '"';
29
    }
30
31
    public function getDataTypes(): array
32
    {
33
        return [
34
            Schema::TYPE_INTEGER => ['tinyint', 'smallint', 'mediumint', 'int', 'bigint'],
35
            Schema::TYPE_FLOAT => ['real', 'double'],
36
            Schema::TYPE_DECIMAL => ['decimal', 'numeric'],
37
            Schema::TYPE_STRING => ['char', 'varchar'],
38
            Schema::TYPE_TEXT => ['tinytext', 'text', 'mediumtext', 'longtext', 'blob'],
39
            Schema::TYPE_DATE => ['date'],
40
            Schema::TYPE_TIME => ['time'],
41
            Schema::TYPE_DATETIME => ['datetime', 'timestamp'],
42
            Schema::TYPE_BOOLEAN => ['boolean'],
43
        ];
44
    }
45
46
    /**
47
     * Returns an array with the name of all the tables in the database.
48
     *
49
     * @return array
50
     */
51
    public static function getTables(): array
52
    {
53
        $query = 'SHOW TABLES';
54
        return Utils::flatArray(DB::select($query));
55
    }
56
57
    /**
58
     * SQL statement that returns the fields in the table
59
     *
60
     * @param string $tableName
61
     *
62
     * @return string
63
     */
64
    public function getColumnsSql(string $tableName): string
65
    {
66
        /**
67
         * array (size=6)
68
         * 'Field' => string 'id' (length=2)
69
         * 'Type' => string 'int(10) unsigned' (length=16)
70
         * 'Null' => string 'NO' (length=2)
71
         * 'Key' => string 'PRI' (length=3)
72
         * 'Default' => null
73
         * 'Extra' => string 'auto_increment' (length=14)
74
         */
75
        return 'SHOW COLUMNS FROM ' . $this->quoteTableName($tableName) . ';';
76
    }
77
78
    /**
79
     * Modifies the structure returned by the query generated with
80
     * getColumnsSql to the normalized format that returns getColumns
81
     *
82
     * @param array $row
83
     *
84
     * @return array
85
     */
86
    public function normalizeFields(array $row): array
87
    {
88
        $result = [];
89
        $result['field'] = $row['Field'];
90
        $type = $this->splitType($row['Type']);
91
92
        /**
93
         * I thought that this would work
94
         *
95
         * $virtualType = array_search($type['type'], $this->fieldTypes);
96
         */
97
        $virtualType = $type['type'];
98
        foreach ($this->fieldTypes as $key => $values) {
0 ignored issues
show
Bug Best Practice introduced by
The property fieldTypes does not exist on Alxarafe\Database\SqlHelpers\SqlMySql. Did you maybe forget to declare it?
Loading history...
99
            if (in_array($type['type'], $values)) {
100
                $virtualType = $key;
101
                break;
102
            }
103
        }
104
105
        $result['type'] = $virtualType;
106
        if ($virtualType === false) {
107
            $result['type'] = $type['type'];
108
            DebugTool::getInstance()->addMessage('Deprecated', 'Correct the data type ' . $type['type'] . ' in MySql database');
109
        }
110
        $result['length'] = $type['length'] ?? null;
111
        $result['default'] = $row['Default'] ?? null;
112
        $result['nullable'] = $row['Null'];
113
        $result['primary'] = $row['Key'];
114
        $result['autoincrement'] = $row['Extra'] == 'auto_increment' ? 1 : 0;
115
116
        return $result;
117
    }
118
119
    /**
120
     * Divide the data type of a MySQL field into its various components: type,
121
     * length, unsigned or zerofill, if applicable.
122
     *
123
     * @param string $originalType
124
     *
125
     * @return array
126
     */
127
    private static function splitType(string $originalType): array
128
    {
129
        $explode = explode(' ', strtolower($originalType));
130
131
        $pos = strpos($explode[0], '(');
132
133
        $type = $pos ? substr($explode[0], 0, $pos) : $explode[0];
134
        $length = $pos ? intval(substr($explode[0], $pos + 1)) : null;
135
136
        $pos = array_search('unsigned', $explode);
137
        $unsigned = $pos ? 'unsigned' : null;
138
139
        $pos = array_search('zerofill', $explode);
140
        $zerofill = $pos ? 'zerofill' : null;
141
142
        return ['type' => $type, 'length' => $length, 'unsigned' => $unsigned, 'zerofill' => $zerofill];
143
    }
144
145
    /**
146
     * Returns an array with the index information, and if there are, also constraints.
147
     *
148
     * @param array $row
149
     *
150
     * @return array
151
     */
152
    public function normalizeIndexes(array $row): array
153
    {
154
        $result = [];
155
        $result['index'] = $row['Key_name'];
156
        $result['column'] = $row['Column_name'];
157
        $result['unique'] = $row['Non_unique'] == '0' ? 1 : 0;
158
        $result['nullable'] = $row['Null'] == 'YES' ? 1 : 0;
159
        $constrait = $this->getConstraintData($row['Table'], $row['Key_name']);
160
        if (count($constrait) > 0) {
161
            $result['constraint'] = $constrait[0]['CONSTRAINT_NAME'];
162
            $result['referencedtable'] = $constrait[0]['REFERENCED_TABLE_NAME'];
163
            $result['referencedfield'] = $constrait[0]['REFERENCED_COLUMN_NAME'];
164
        }
165
        $constrait = $this->getConstraintRules($row['Table'], $row['Key_name']);
166
        if (count($constrait) > 0) {
167
            $result['matchoption'] = $constrait[0]['MATCH_OPTION'];
168
            $result['updaterule'] = $constrait[0]['UPDATE_RULE'];
169
            $result['deleterule'] = $constrait[0]['DELETE_RULE'];
170
        }
171
        return $result;
172
    }
173
174
    /**
175
     * The data about the constraint that is found in the KEY_COLUMN_USAGE table
176
     * is returned.
177
     * Attempting to return the consolidated data generates an extremely slow query
178
     * in some MySQL installations, so 2 additional simple queries are made.
179
     *
180
     * @param string $tableName
181
     * @param string $constraintName
182
     *
183
     * @return array
184
     */
185
    private function getConstraintData(string $tableName, string $constraintName): array
186
    {
187
        $dbName = Config::getVar('dbName') ?? 'Unknown';
0 ignored issues
show
Bug introduced by
The call to Alxarafe\Core\Singletons\Config::getVar() has too few arguments starting with section. ( Ignorable by Annotation )

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

187
        $dbName = Config::/** @scrutinizer ignore-call */ getVar('dbName') ?? 'Unknown';

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
188
189
        return DB::select('
190
SELECT
191
	TABLE_NAME,
192
	COLUMN_NAME,
193
	CONSTRAINT_NAME,
194
	REFERENCED_TABLE_NAME,
195
	REFERENCED_COLUMN_NAME
196
FROM
197
	INFORMATION_SCHEMA.KEY_COLUMN_USAGE
198
WHERE
199
	TABLE_SCHEMA = ' . $this->quoteFieldName($dbName) . ' AND
200
	TABLE_NAME = ' . $this->quoteFieldName($tableName) . ' AND
201
	constraint_name = ' . $this->quoteFieldName($constraintName) . ' AND
202
	REFERENCED_COLUMN_NAME IS NOT NULL;
203
        ');
204
    }
205
206
    /**
207
     * The rules for updating and deleting data with constraint (table
208
     * REFERENTIAL_CONSTRAINTS) are returned.
209
     * Attempting to return the consolidated data generates an extremely slow query
210
     * in some MySQL installations, so 2 additional simple queries are made.
211
     *
212
     * @param string $tableName
213
     * @param string $constraintName
214
     *
215
     * @return array
216
     */
217
    private function getConstraintRules(string $tableName, string $constraintName): array
218
    {
219
        $dbName = Config::getVar('dbName') ?? 'Unknown';
0 ignored issues
show
Bug introduced by
The call to Alxarafe\Core\Singletons\Config::getVar() has too few arguments starting with section. ( Ignorable by Annotation )

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

219
        $dbName = Config::/** @scrutinizer ignore-call */ getVar('dbName') ?? 'Unknown';

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
220
221
        return DB::selectselect('
0 ignored issues
show
Bug introduced by
The method selectselect() does not exist on Alxarafe\Database\DB. Did you maybe mean select()? ( Ignorable by Annotation )

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

221
        return DB::/** @scrutinizer ignore-call */ selectselect('

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...
222
SELECT
223
	MATCH_OPTION,
224
	UPDATE_RULE,
225
	DELETE_RULE
226
FROM information_schema.REFERENTIAL_CONSTRAINTS
227
WHERE
228
	constraint_schema = ' . $this->quoteFieldName($dbName) . ' AND
229
	table_name = ' . $this->quoteFieldName($tableName) . ' AND
230
	constraint_name = ' . $this->quoteFieldName($constraintName) . ';
231
        ');
232
    }
233
234
    /**
235
     * Obtain an array with the basic information about the indexes of the table,
236
     * which will be supplemented with the restrictions later.
237
     *
238
     * @param string $tableName
239
     *
240
     * @return string
241
     */
242
    public function getIndexesSql(string $tableName): string
243
    {
244
        // https://stackoverflow.com/questions/5213339/how-to-see-indexes-for-a-database-or-table-in-mysql
245
246
        return 'SHOW INDEX FROM ' . Config::getInstance()->getSqlHelper()->quoteTableName($tableName);
0 ignored issues
show
Bug introduced by
The method getInstance() does not exist on Alxarafe\Core\Singletons\Config. ( Ignorable by Annotation )

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

246
        return 'SHOW INDEX FROM ' . Config::/** @scrutinizer ignore-call */ getInstance()->getSqlHelper()->quoteTableName($tableName);

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...
247
    }
248
}
249