Completed
Branch develop (c2aa4c)
by Anton
05:17
created

ColumnSchema::resolveSchema()   C

Complexity

Conditions 10
Paths 27

Size

Total Lines 48
Code Lines 27

Duplication

Lines 5
Ratio 10.42 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 5
loc 48
rs 5.3455
cc 10
eloc 27
nc 27
nop 1

How to fix   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
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
namespace Spiral\Database\Drivers\MySQL\Schemas;
9
10
use Spiral\Database\DatabaseManager;
11
use Spiral\Database\Drivers\MySQL\MySQLDriver;
12
use Spiral\Database\Entities\Schemas\AbstractColumn;
13
use Spiral\Database\Injections\Fragment;
14
15
/**
16
 * MySQL column schema.
17
 */
18
class ColumnSchema extends AbstractColumn
19
{
20
    /**
21
     * {@inheritdoc}
22
     */
23
    protected $mapping = [
24
        //Primary sequences
25
        'primary'     => [
26
            'type'          => 'int',
27
            'size'          => 11,
28
            'autoIncrement' => true,
29
            'nullable'      => false
30
        ],
31
        'bigPrimary'  => [
32
            'type'          => 'bigint',
33
            'size'          => 20,
34
            'autoIncrement' => true,
35
            'nullable'      => false
36
        ],
37
38
        //Enum type (mapped via method)
39
        'enum'        => 'enum',
40
41
        //Logical types
42
        'boolean'     => ['type' => 'tinyint', 'size' => 1],
43
44
        //Integer types (size can always be changed with size method), longInteger has method alias
45
        //bigInteger
46
        'integer'     => ['type' => 'int', 'size' => 11],
47
        'tinyInteger' => ['type' => 'tinyint', 'size' => 4],
48
        'bigInteger'  => ['type' => 'bigint', 'size' => 20],
49
50
        //String with specified length (mapped via method)
51
        'string'      => 'varchar',
52
53
        //Generic types
54
        'text'        => 'text',
55
        'tinyText'    => 'tinytext',
56
        'longText'    => 'longtext',
57
58
        //Real types
59
        'double'      => 'double',
60
        'float'       => 'float',
61
62
        //Decimal type (mapped via method)
63
        'decimal'     => 'decimal',
64
65
        //Date and Time types
66
        'datetime'    => 'datetime',
67
        'date'        => 'date',
68
        'time'        => 'time',
69
        'timestamp'   => [
70
            'type'         => 'timestamp',
71
            'defaultValue' => MySQLDriver::DEFAULT_DATETIME
72
        ],
73
74
        //Binary types
75
        'binary'      => 'blob',
76
        'tinyBinary'  => 'tinyblob',
77
        'longBinary'  => 'longblob',
78
79
        //Additional types
80
        'json'        => 'text'
81
    ];
82
83
    /**
84
     * {@inheritdoc}
85
     */
86
    protected $reverseMapping = [
87
        'primary'     => [['type' => 'int', 'autoIncrement' => true]],
88
        'bigPrimary'  => ['serial', ['type' => 'bigint', 'autoIncrement' => true]],
89
        'enum'        => ['enum'],
90
        'boolean'     => ['bool', 'boolean', ['type' => 'tinyint', 'size' => 1]],
91
        'integer'     => ['int', 'integer', 'smallint', 'mediumint'],
92
        'tinyInteger' => ['tinyint'],
93
        'bigInteger'  => ['bigint'],
94
        'string'      => ['varchar', 'char'],
95
        'text'        => ['text', 'mediumtext'],
96
        'tinyText'    => ['tinytext'],
97
        'longText'    => ['longtext'],
98
        'double'      => ['double'],
99
        'float'       => ['float', 'real'],
100
        'decimal'     => ['decimal'],
101
        'datetime'    => ['datetime'],
102
        'date'        => ['date'],
103
        'time'        => ['time'],
104
        'timestamp'   => ['timestamp'],
105
        'binary'      => ['blob', 'binary', 'varbinary'],
106
        'tinyBinary'  => ['tinyblob'],
107
        'longBinary'  => ['longblob']
108
    ];
109
110
    /**
111
     * List of types forbids default value set.
112
     *
113
     * @var array
114
     */
115
    protected $forbiddenDefaults = [
116
        'text',
117
        'mediumtext',
118
        'tinytext',
119
        'longtext',
120
        'blog',
121
        'tinyblob',
122
        'longblob'
123
    ];
124
125
    /**
126
     * Column is auto incremental.
127
     *
128
     * @var bool
129
     */
130
    protected $autoIncrement = false;
131
132
    /**
133
     * {@inheritdoc}
134
     */
135
    public function getDefaultValue()
136
    {
137
        $defaultValue = parent::getDefaultValue();
138
139
        if (in_array($this->type, $this->forbiddenDefaults)) {
140
            return null;
141
        }
142
143
        return $defaultValue;
144
    }
145
146
    /**
147
     * {@inheritdoc}
148
     */
149
    public function sqlStatement()
150
    {
151
        $defaultValue = $this->defaultValue;
152
153
        if (in_array($this->type, $this->forbiddenDefaults)) {
154
            //Flushing default value for forbidden types
155
            $this->defaultValue = null;
156
        }
157
158
        $statement = parent::sqlStatement();
159
160
        $this->defaultValue = $defaultValue;
161
        if ($this->autoIncrement) {
162
            return "{$statement} AUTO_INCREMENT";
163
        }
164
165
        return $statement;
166
    }
167
168
    /**
169
     * {@inheritdoc}
170
     */
171
    protected function resolveSchema($schema)
172
    {
173
        $this->type = $schema['Type'];
174
        $this->nullable = strtolower($schema['Null']) == 'yes';
175
        $this->defaultValue = $schema['Default'];
176
        $this->autoIncrement = stripos($schema['Extra'], 'auto_increment') !== false;
177
178
        if (!preg_match('/^(?P<type>[a-z]+)(?:\((?P<options>[^\)]+)\))?/', $this->type, $matches)) {
179
            return;
180
        }
181
182
        $this->type = $matches['type'];
183
184
        $options = null;
185
        if (!empty($matches['options'])) {
186
            $options = $matches['options'];
187
        }
188
189
        if ($this->abstractType() == 'enum') {
190
191
            //Fetching enum values
192
            $this->enumValues = array_map(function ($value) {
193
                return trim($value, $value[0]);
194
            }, explode(',', $options));
195
196
            return;
197
        }
198
199
        $options = array_map(function ($value) {
200
            return intval($value);
201
        }, explode(',', $options));
202
203 View Code Duplication
        if (count($options) > 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
204
            list($this->precision, $this->scale) = $options;
205
        } elseif (!empty($options)) {
206
            $this->size = $options[0];
207
        }
208
209
        //Default value conversions
210
        if ($this->type == 'bit' && $this->hasDefaultValue()) {
211
            //Cutting b\ and '
212
            $this->defaultValue = new Fragment($this->defaultValue);
213
        }
214
215
        if ($this->abstractType() == 'timestamp' && $this->defaultValue == '0000-00-00 00:00:00') {
216
            $this->defaultValue = MySqlDriver::DEFAULT_DATETIME;
217
        }
218
    }
219
220
    /**
221
     * {@inheritdoc}
222
     */
223
    protected function prepareDefault()
224
    {
225
        if ($this->abstractType() == 'timestamp' && is_scalar($this->defaultValue)) {
226
            if (is_numeric($this->defaultValue)) {
227
                //Nothing to do
228
                return (int)$this->defaultValue;
229
            }
230
231
            $datetime = new \DateTime($this->defaultValue,
232
                new \DateTimeZone(DatabaseManager::DEFAULT_TIMEZONE));
233
234
            return $datetime->getTimestamp();
235
        }
236
237
        return parent::prepareDefault();
238
    }
239
}