Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
181 / 181
100.00% covered (success)
100.00%
12 / 12
CRAP
100.00% covered (success)
100.00%
1 / 1
Column
100.00% covered (success)
100.00%
181 / 181
100.00% covered (success)
100.00%
12 / 12
109
100.00% covered (success)
100.00%
1 / 1
 getColumnSchema
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getValidDataType
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
6
 getValidMysqlDataType
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
1 / 1
7
 getValidPgsqlDataType
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
1 / 1
15
 getValidSqliteDataType
100.00% covered (success)
100.00%
33 / 33
100.00% covered (success)
100.00%
1 / 1
20
 getValidSqlsrvDataType
100.00% covered (success)
100.00%
29 / 29
100.00% covered (success)
100.00%
1 / 1
16
 formatColumn
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
6
 formatMysqlColumn
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
10
 formatPgsqlColumn
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
7
 formatSqliteColumn
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 formatSqlsrvColumn
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
9
 formatCommonParameters
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
8
1<?php
2/**
3 * Pop PHP Framework (http://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@nolainteractive.com>
7 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
8 * @license    http://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Db\Sql\Schema\Formatter;
15
16use Pop\Db\Sql;
17
18/**
19 * Schema column formatter class
20 *
21 * @category   Pop
22 * @package    Pop\Db
23 * @author     Nick Sagona, III <dev@nolainteractive.com>
24 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
25 * @license    http://www.popphp.org/license     New BSD License
26 * @version    6.5.0
27 */
28class Column extends AbstractFormatter
29{
30
31    /**
32     * Get column schema
33     *
34     * @param  string $dbType
35     * @param  string $name
36     * @param  array  $column
37     * @param  string $table
38     * @throws Exception
39     * @return string
40     */
41    public static function getColumnSchema(string $dbType, string $name, array $column, string $table): string
42    {
43        if (!isset($column['type'])) {
44            throw new Exception('Error: The column type was not set.');
45        }
46
47        $dataType = self::getValidDataType($dbType, $column['type']);
48
49        return self::formatColumn($dbType, $name, $dataType, $column, $table);
50    }
51
52    /**
53     * Get valid column data type
54     *
55     * @param  string $dbType
56     * @param  string $type
57     * @return string
58     */
59    public static function getValidDataType(string $dbType, string $type): string
60    {
61        switch ($dbType) {
62            case Sql::MYSQL:
63                return self::getValidMysqlDataType($type);
64                break;
65            case Sql::PGSQL:
66                return self::getValidPgsqlDataType($type);
67                break;
68            case Sql::SQLITE:
69                return self::getValidSqliteDataType($type);
70                break;
71            case Sql::SQLSRV:
72                return self::getValidSqlsrvDataType($type);
73                break;
74            default:
75                return $type;
76        }
77    }
78
79    /**
80     * Get valid MySQL data type
81     *
82     * @param  string $type
83     * @return string
84     */
85    public static function getValidMysqlDataType(string $type): string
86    {
87        $type = strtoupper($type);
88
89        switch ($type) {
90            case 'INTEGER':
91                $type = 'INT';
92                break;
93            case 'SERIAL':
94                $type = 'INT';
95                break;
96            case 'BIGSERIAL':
97                $type = 'BIGINT';
98                break;
99            case 'SMALLSERIAL':
100                $type = 'SMALLINT';
101                break;
102            case 'CHARACTER VARYING':
103                $type = 'VARCHAR';
104                break;
105            case 'CHARACTER':
106                $type = 'CHAR';
107                break;
108        }
109
110        return $type;
111    }
112
113    /**
114     * Get valid PostgreSQL data type
115     *
116     * @param  string $type
117     * @return string
118     */
119    public static function getValidPgsqlDataType(string $type): string
120    {
121        $type = strtoupper($type);
122
123        switch ($type) {
124            case 'INT':
125            case 'MEDIUMINT':
126                $type = 'INTEGER';
127                break;
128            case 'TINYINT':
129                $type = 'SMALLINT';
130                break;
131                break;
132            case 'DOUBLE':
133                $type = 'DOUBLE PRECISION';
134                break;
135            case 'BLOB':
136            case 'TINYBLOB':
137            case 'MEDIUMBLOB':
138            case 'LONGBLOB':
139            case 'TINYTEXT':
140            case 'MEDIUMTEXT':
141            case 'LONGTEXT':
142                $type = 'TEXT';
143                break;
144            case 'BINARY':
145            case 'VARBINARY':
146                $type = 'BYTEA';
147                break;
148            case 'DATETIME':
149                $type = 'TIMESTAMP';
150                break;
151        }
152
153        return $type;
154    }
155
156    /**
157     * Get valid SQLite data type
158     *
159     * @param  string $type
160     * @return string
161     */
162    public static function getValidSqliteDataType(string $type): string
163    {
164        $type = strtoupper($type);
165
166        switch ($type) {
167            case 'INT':
168            case 'SMALLINT':
169            case 'TINYINT':
170            case 'MEDIUMINT':
171            case 'BIGINT':
172            case 'SERIAL':
173            case 'BIGSERIAL':
174            case 'SMALLSERIAL':
175                $type = 'INTEGER';
176                break;
177            case 'FLOAT':
178            case 'DOUBLE':
179            case 'DOUBLE PRECISION':
180                $type = 'REAL';
181                break;
182            case 'DECIMAL':
183                $type = 'NUMERIC';
184                break;
185            case 'TINYBLOB':
186            case 'MEDIUMBLOB':
187            case 'LONGBLOB':
188                $type = 'BLOB';
189                break;
190            case 'TINYTEXT':
191            case 'MEDIUMTEXT':
192            case 'LONGTEXT':
193                $type = 'TEXT';
194                break;
195            case 'TIMESTAMP':
196                $type = 'DATETIME';
197                break;
198        }
199
200        return $type;
201    }
202
203    /**
204     * Get valid SQL Server data type
205     *
206     * @param  string $type
207     * @return string
208     */
209    public static function getValidSqlsrvDataType(string $type): string
210    {
211        $type = strtoupper($type);
212
213        switch ($type) {
214            case 'INTEGER':
215            case 'MEDIUMINT':
216            case 'SERIAL':
217                $type = 'INT';
218                break;
219            case 'BIGSERIAL':
220                $type = 'BIGINT';
221                break;
222            case 'SMALLSERIAL':
223                $type = 'SMALLINT';
224                break;
225            case 'DOUBLE':
226            case 'DOUBLE PRECISION':
227                $type = 'REAL';
228                break;
229            case 'BLOB':
230            case 'TINYBLOB':
231            case 'MEDIUMBLOB':
232            case 'LONGBLOB':
233            case 'TINYTEXT':
234            case 'MEDIUMTEXT':
235            case 'LONGTEXT':
236                $type = 'TEXT';
237                break;
238            case 'TIMESTAMP':
239                $type = 'DATETIME';
240                break;
241        }
242
243        return $type;
244    }
245
246    /**
247     * Format column
248     *
249     * @param  string $dbType
250     * @param  string $name
251     * @param  string $dataType
252     * @param  array  $column
253     * @param  string $table
254     * @throws Exception
255     * @return string
256     */
257    public static function formatColumn(string $dbType, string $name, string $dataType, array $column, string $table): string
258    {
259        switch ($dbType) {
260            case Sql::MYSQL:
261                return self::formatMysqlColumn($name, $dataType, $column);
262                break;
263            case Sql::PGSQL:
264                return self::formatPgsqlColumn($name, $dataType, $column, $table);
265                break;
266            case Sql::SQLITE:
267                return self::formatSqliteColumn($name, $dataType, $column);
268                break;
269            case Sql::SQLSRV:
270                return self::formatSqlsrvColumn($name, $dataType, $column);
271                break;
272            default:
273                throw new Exception("Error: The database type '" . $dbType . "' is not supported.");
274        }
275    }
276
277    /**
278     * Format MySQL column
279     *
280     * @param  string $name
281     * @param  string $dataType
282     * @param  array  $column
283     * @return string
284     */
285    public static function formatMysqlColumn(string $name, string $dataType, array $column): string
286    {
287        $columnString = $name . ' ' . $dataType;
288        $sizeAllowed  = ['DECIMAL', 'NUMERIC', 'FLOAT', 'DOUBLE', 'REAL', 'DOUBLE PRECISION'];
289
290        if (!empty($column['size']) &&
291            ((stripos($dataType, 'INT') !== false) || (stripos($dataType, 'CHAR') !== false) ||
292                (stripos($dataType, 'BINARY') !== false) || in_array($dataType, $sizeAllowed))) {
293            $columnString .= '(' . $column['size'];
294            $columnString .= (!empty($column['precision']) && in_array($dataType, $sizeAllowed)) ?
295                ', ' . $column['precision'] . ')' : ')';
296        }
297
298        if ($column['unsigned'] !== false) {
299            $columnString .= ' UNSIGNED';
300        }
301
302        $columnString = self::formatCommonParameters($columnString, $column);
303
304        if ($column['increment'] !== false) {
305            $columnString .= ' AUTO_INCREMENT';
306        }
307
308        return $columnString;
309    }
310
311    /**
312     * Format PostgreSQL column
313     *
314     * @param  string $name
315     * @param  string $dataType
316     * @param  array  $column
317     * @param  string $table
318     * @return string
319     */
320    public static function formatPgsqlColumn(string $name, string $dataType, array $column, string $table): string
321    {
322        $columnString     = $name . ' ' . $dataType;
323        $unquotedName     = self::unquoteId($name);
324        $sizeAllowed      = ['DECIMAL', 'NUMERIC', 'FLOAT', 'REAL'];
325        $precisionAllowed = ['DECIMAL', 'NUMERIC'];
326
327        if (!empty($column['size']) &&
328            ((stripos($dataType, 'CHAR') !== false) || in_array($dataType, $sizeAllowed))) {
329            $columnString .= '(' . $column['size'];
330            $columnString .= (!empty($column['precision']) && in_array($dataType, $precisionAllowed)) ?
331                ', ' . $column['precision'] . ')' : ')';
332        }
333
334        $columnString = self::formatCommonParameters($columnString, $column);
335
336        if ($column['increment'] !== false) {
337            $columnString .= ' DEFAULT nextval(\'' . $table . '_' . $unquotedName . '_seq\')';
338        }
339
340        return $columnString;
341    }
342
343    /**
344     * Format SQLite column
345     *
346     * @param  string $name
347     * @param  string $dataType
348     * @param  array  $column
349     * @return string
350     */
351    public static function formatSqliteColumn(string $name, string $dataType, array $column): string
352    {
353        $columnString = $name . ' ' . $dataType;
354        $columnString = self::formatCommonParameters($columnString, $column);
355
356        if ($column['increment'] !== false) {
357            $columnString .= (($column['primary'] !== false) ? ' PRIMARY KEY' : null) . ' AUTOINCREMENT';
358        }
359
360        return $columnString;
361    }
362
363    /**
364     * Format SQL Server column
365     *
366     * @param  string $name
367     * @param  string $dataType
368     * @param  array  $column
369     * @return string
370     */
371    public static function formatSqlsrvColumn(string $name, string $dataType, array $column): string
372    {
373        $columnString = $name . ' ' . $dataType;
374        $sizeAllowed      = ['DECIMAL', 'NUMERIC', 'FLOAT', 'REAL'];
375        $precisionAllowed = ['DECIMAL', 'NUMERIC'];
376
377        if (!empty($column['size']) &&
378            ((stripos($dataType, 'CHAR') !== false) || (stripos($dataType, 'BINARY') !== false) ||
379              in_array($dataType, $sizeAllowed))) {
380            $columnString .= '(' . $column['size'];
381            $columnString .= (!empty($column['precision']) && in_array($dataType, $precisionAllowed)) ?
382                ', ' . $column['precision'] . ')' : ')';
383        }
384
385        $columnString = self::formatCommonParameters($columnString, $column);
386
387        if ($column['increment'] !== false) {
388            $columnString .= (($column['primary'] !== false) ? ' PRIMARY KEY' : null) .
389                ' IDENTITY(' . (int)$column['increment'] . ', 1)';
390        }
391
392        return $columnString;
393    }
394
395    /**
396     * Format common column parameters
397     *
398     * @param  string $columnString
399     * @param  array  $column
400     * @return string
401     */
402    public static function formatCommonParameters(string $columnString, array $column): string
403    {
404        if (count($column['attributes']) > 0) {
405            $columnString .= ' ' . implode(' ', $column['attributes']);
406        }
407
408        if (($column['nullable'] === false) || (strtoupper((string)$column['default']) == 'NOT NULL')) {
409            $columnString .= ' NOT NULL';
410        }
411
412        if (($column['default'] === null) && ($column['nullable'] === true)) {
413            $columnString .= ' DEFAULT NULL';
414        } else if (strtoupper((string)$column['default']) == 'NULL') {
415            $columnString .= ' DEFAULT NULL';
416        } else if ($column['default'] !== null) {
417            $columnString .= " DEFAULT '" . $column['default'] . "'";
418        }
419
420        return $columnString;
421    }
422
423}