CreateTable::sqlColumns()   D
last analyzed

Complexity

Conditions 23
Paths 38

Size

Total Lines 112
Code Lines 60

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 23
eloc 60
c 2
b 0
f 0
nc 38
nop 0
dl 0
loc 112
rs 4.1666

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 declare(strict_types=1);
2
3
/** 
4
 *  ___      _        _
5
 * | _ \__ _| |_ __ _| |__  __ _ ___ ___
6
 * |  _/ _` |  _/ _` | '_ \/ _` (_-</ -_)
7
 * |_| \__,_|\__\__,_|_.__/\__,_/__/\___|
8
 * 
9
 * This file is part of Kristuff\Patabase.
10
 * (c) Kristuff <[email protected]>
11
 *
12
 * For the full copyright and license information, please view the LICENSE
13
 * file that was distributed with this source code.
14
 *
15
 * @version    1.0.1
16
 * @copyright  2017-2022 Christophe Buliard
17
 */
18
19
namespace Kristuff\Patabase\Query;
20
21
use Kristuff\Patabase\Driver\DatabaseDriver;
22
23
/**
24
 * Class CreateTable 
25
 *
26
 * Represents a [CREATE TABLE] SQL query
27
 */
28
class CreateTable extends \Kristuff\Patabase\Query\QueryBuilder
29
{
30
31
    /**
32
     * Supported string keywords for defaults values     
33
     *
34
     * @access private
35
     * @var    array       $supportedDefaults
36
     */
37
    private $supportedDefaults = array('NULL', 'CURRENT_TIMESTAMP');
38
39
    /**
40
     * Table name (CREATE TABLE [?])
41
     *
42
     * @access private
43
     * @var    string       $tableName
44
     */
45
    private $tableName = null;
46
         
47
    /**
48
     * Columns list 
49
     *
50
     * @access private
51
     * @var    array        $columns
52
     */
53
    private $columns = array();
54
55
    /**
56
     * Foreign Keys list 
57
     *
58
     * @access private
59
     * @var    array        $foreignKeys
60
     */
61
    private $foreignKeys = array();
62
63
    /**
64
     * Add or not the [If not exist] statement
65
     *
66
     * @access private
67
     * @var    bool
68
     */
69
    private $isNotExists = false;
70
    
71
    /**
72
     * Constructor
73
     *
74
     * @access public
75
     * @param DatabaseDriver    $driver         The driver instance
76
     * @param string            $tableName      The table name
77
     */
78
    public function __construct(DatabaseDriver $driver, string $tableName)
79
    {
80
        parent::__construct($driver);
81
        $this->tableName = $tableName;
82
    }    
83
    
84
    /**
85
     * Set the IF NOT EXISTS 
86
     *
87
     * @access public
88
     * @return $this
89
     */
90
    public function ifNotExists()
91
    {
92
        $this->isNotExists = true;
93
        return $this;
94
    }
95
96
    /**
97
     * Add a column to the list of column definition
98
     *
99
     * @access public
100
     *
101
     * @return $this
102
     */
103
    public function column()
104
    {
105
       $this->columns[] = func_get_args();
106
       return $this;
107
    }
108
     
109
    /**
110
     * Add a foreign key contraint
111
     *
112
     * @access public
113
     * @param string       $fkName         The name for the foreign key
114
     * @param string       $srcColumn      The column in main table
115
     * @param string       $refTable       The referenced table
116
     * @param string       $refColumn      The column in referenced table
117
     * @param string       $onUpdate       (optional) The on update rule. Default is CASCADE
118
     * @param string       $onDelete       (optional) The on delete rule. Default is RESTRICT
119
     *
120
     * @return $this
121
     */
122
    public function fk(string $fkName, string $srcColumn, string $refTable, string $refColumn, ?string $onUpdate = 'CASCADE', ?string $onDelete = 'RESTRICT')
123
    {
124
       $this->foreignKeys[] = array(
125
            'name'          => $fkName,
126
            'src_column'    => $srcColumn,
127
            'ref_table'     => $refTable,
128
            'ref_column'    => $refColumn,
129
            'on_update'     => $onUpdate,
130
            'on_delete'     => $onDelete
131
       );
132
       return $this;
133
    }
134
135
    /**
136
     * Get the SQL COLUMNS statement
137
     *
138
     * @access public
139
     * @return string
140
     */
141
    private function sqlColumns(): string
142
    {
143
        $result = array();
144
        foreach ($this->columns as $col){
145
146
            // Parse arguments. First item is NAME and second is TYPE
147
            $sqlName   = $this->escape($col[0]);
148
            $sqlType   = $col[1];  //TODO check type
149
            
150
            // following arguments
151
            $args       = array_slice($col, 2);
152
            $currentIndex       = 0;
153
            $defaultValueIndex  = -1;
154
155
            $sqlConstraintUnique    = '';       // UNIQUE ?, not by default
156
            $sqlConstraintNullable  = 'NULL';   // allow null value by default
157
            $isPk                   = false;    // PRIMARY KEY?
158
            $sqlDefault             = '';       // DEFAULT VALUE?
159
160
            foreach ($args as $arg){
161
162
                // last index was DEFAULT, so the current argument 
163
                // is the value for default contsaint
164
                if ($currentIndex === $defaultValueIndex){
165
                    
166
                    // string
167
                    if (is_string($arg)){
168
                            
169
                        // escape everything except constants
170
                        if (in_array(strtoupper($arg), $this->supportedDefaults)){
171
                            $sqlDefault = 'DEFAULT ' . $arg;
172
                        } else {
173
                            $sqlDefault = 'DEFAULT ' . $this->driver->escapeValue($arg);
174
                        }
175
                        
176
                    // int/float are not escaped
177
                    } elseif (is_int($arg) || is_float($arg)){
178
                        $sqlDefault = 'DEFAULT ' . $arg;
179
180
                    // bool Type
181
                    } elseif (is_bool($arg)){
182
                        $sqlDefault = 'DEFAULT ' . ($arg ? 'TRUE' : 'FALSE');                            
183
                    }
184
185
186
                } else {
187
                    switch (strtoupper($arg)){
188
                        
189
                        // NULL  /NOT NULL 
190
                        case 'NULL':
191
                            $sqlConstraintNullable = 'NULL';
192
                            break;
193
194
195
                        case 'NOT NULL':
196
                            $sqlConstraintNullable = 'NOT NULL';
197
                            break;
198
199
                        // UNIQUE
200
                        case 'UNIQUE':
201
                            $sqlConstraintUnique = 'UNIQUE';
202
                            break;
203
204
                        // AUTO INCREMENT
205
                        case 'AUTO INCREMENT':
206
                        case 'AUTO_INCREMENT':
207
                        case 'AI':
208
                            $sqlType = $this->driver->sqlColumnAutoIncrement($sqlType);
209
                            break;                            
210
211
                        // PK
212
                        case 'PRIMARY KEY':
213
                        case 'PRIMARY_KEY':
214
                        case 'PK':
215
                            $isPk = true;
216
                            break;
217
218
                        // DEFAULT
219
                        case 'DEFAULT':
220
                            // define next index as the DefaultValue index
221
                            $defaultValueIndex = $currentIndex +1;
222
                            break;
223
                    
224
                    }
225
                }
226
227
                // update  current index
228
                $currentIndex ++;
229
            }
230
231
            // set optional params
232
            // PK ?, UNIQUE ?, NULL? (PK cannot be null), DEFAULT?
233
            // AI is handle with sqltype
234
            $result[] = trim(implode(' ', [$sqlName, 
235
                                           $sqlType, 
236
                                           $isPk ? 'NOT NULL' : $sqlConstraintNullable,
237
                                           $isPk ? 'PRIMARY KEY' : '',
238
                                           $sqlConstraintUnique,
239
                                           $sqlDefault]));
240
        }
241
242
        // FK CONSTRANT
243
        foreach ($this->foreignKeys as $foreignKey){
244
            $result[] =  trim(sprintf('CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s(%s)', 
245
                            $foreignKey['name'], 
246
                            $this->driver->escapeIdentifier($foreignKey['src_column']), 
247
                            $this->driver->escapeIdentifier($foreignKey['ref_table']),
248
                            $this->driver->escapeIdentifier($foreignKey['ref_column'])
249
            ));
250
        }
251
252
        return implode(', ', $result);
253
    }
254
   
255
    /**
256
     * Build the CREATE TABLE query
257
     *
258
     * @access public
259
     * @return string
260
     */
261
    public function sql(): string
262
    {
263
        $sqlTableName = $this->driver->escape($this->tableName);
264
        $sqlIfNotExists =  $this->isNotExists === true ? 'IF NOT EXISTS' : '';
265
266
        return trim(sprintf(
267
            'CREATE TABLE %s %s (%s) %s',
268
            $sqlIfNotExists,    
269
            $sqlTableName,
270
            $this->sqlColumns(),
271
            $this->driver->sqlCreateTableOptions()
272
        ));
273
    }
274
275
}