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

ColumnSchema   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 222
Duplicated Lines 2.25 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 5
loc 222
wmc 19
lcom 1
cbo 2
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getDefaultValue() 0 10 2
C resolveSchema() 5 48 10
A prepareDefault() 0 16 4
A sqlStatement() 0 18 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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
}