Completed
Push — feature/collation ( dfda64...a60b97 )
by Kit Loong
05:53
created

FieldGenerator   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 173
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 89
c 3
b 0
f 0
dl 0
loc 173
rs 10
wmc 30

3 Methods

Rating   Name   Duplication   Size   Complexity  
C generate() 0 66 13
A __construct() 0 28 1
C makeLaravelFieldTypeMethod() 0 32 16
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: liow.kitloong
5
 * Date: 2020/03/28
6
 */
7
8
namespace KitLoong\MigrationsGenerator\Generators;
9
10
use Doctrine\DBAL\Schema\Column;
11
use Illuminate\Support\Collection;
12
use KitLoong\MigrationsGenerator\Generators\Modifier\CommentModifier;
13
use KitLoong\MigrationsGenerator\Generators\Modifier\DefaultModifier;
14
use KitLoong\MigrationsGenerator\Generators\Modifier\IndexModifier;
15
use KitLoong\MigrationsGenerator\Generators\Modifier\NullableModifier;
16
use KitLoong\MigrationsGenerator\MigrationMethod\ColumnModifier;
17
use KitLoong\MigrationsGenerator\MigrationMethod\ColumnType;
18
use KitLoong\MigrationsGenerator\Support\CheckLaravelVersion;
19
use KitLoong\MigrationsGenerator\Types\DBALTypes;
20
21
class FieldGenerator
22
{
23
    use CheckLaravelVersion;
24
25
    private $decorator;
26
    private $integerField;
27
    private $datetimeField;
28
    private $decimalField;
29
    private $geometryField;
30
    private $stringField;
31
    private $enumField;
32
    private $setField;
33
    private $otherField;
34
    private $nullableModifier;
35
    private $defaultModifier;
36
    private $indexModifier;
37
    private $commentModifier;
38
39
    public function __construct(
40
        Decorator $decorator,
41
        IntegerField $integerField,
42
        DatetimeField $datetimeField,
43
        DecimalField $decimalField,
44
        GeometryField $geometryField,
45
        StringField $stringField,
46
        EnumField $enumField,
47
        SetField $setField,
48
        OtherField $otherField,
49
        NullableModifier $nullableModifier,
50
        DefaultModifier $defaultModifier,
51
        IndexModifier $indexModifier,
52
        CommentModifier $commentModifier
53
    ) {
54
        $this->decorator = $decorator;
55
        $this->integerField = $integerField;
56
        $this->datetimeField = $datetimeField;
57
        $this->decimalField = $decimalField;
58
        $this->geometryField = $geometryField;
59
        $this->stringField = $stringField;
60
        $this->enumField = $enumField;
61
        $this->setField = $setField;
62
        $this->otherField = $otherField;
63
        $this->nullableModifier = $nullableModifier;
64
        $this->defaultModifier = $defaultModifier;
65
        $this->indexModifier = $indexModifier;
66
        $this->commentModifier = $commentModifier;
67
    }
68
69
    /**
70
     * Convert dbal types to Laravel Migration Types
71
     * @var array
72
     */
73
    public static $fieldTypeMap = [
74
        DBALTypes::SMALLINT => ColumnType::SMALL_INTEGER,
75
        DBALTypes::BIGINT => ColumnType::BIG_INTEGER,
76
        DBALTypes::DATETIME_MUTABLE => ColumnType::DATETIME,
77
        DBALTypes::BLOB => ColumnType::BINARY,
78
    ];
79
80
    /**
81
     * @param  string  $table
82
     * @param  Column[]  $columns
83
     * @param  Collection  $indexes
84
     * @return array
85
     */
86
    public function generate(string $table, $columns, Collection $indexes): array
87
    {
88
        if (count($columns) === 0) {
89
            return [];
90
        }
91
92
        $useTimestamps = $this->datetimeField->isUseTimestamps($columns);
93
94
        $fields = [];
95
96
        foreach ($columns as $column) {
97
            /**
98
             * return [
99
             *  field : Field name,
100
             *  type  : Migration type method, eg: increments, string
101
             *  args  : Migration type arguments,
102
             *      eg: decimal('amount', 8, 2) => decimal('amount', args[0], args[1])
103
             *  decorators
104
             * ]
105
             */
106
            $dbalType = $column->getType()->getName();
107
108
            $field = [
109
                'field' => $this->decorator->addSlash($column->getName()),
110
                'type' => $dbalType,
111
                'args' => [],
112
                'decorators' => []
113
            ];
114
115
            $field = $this->makeLaravelFieldTypeMethod($table, $field, $column, $indexes, $useTimestamps);
116
117
            if (empty($field)) {
118
                continue;
119
            }
120
121
            if (!$column->getNotnull()) {
122
                if ($this->nullableModifier->shouldAddNullableModifier($field['type'])) {
123
                    $field['decorators'][] = ColumnModifier::NULLABLE;
124
                }
125
            }
126
127
            if ($column->getDefault() !== null) {
128
                $field['decorators'][] = $this->defaultModifier->generate($dbalType, $column);
129
            }
130
131
            if ($indexes->has($field['field'])) {
132
                $field['decorators'][] = $this->indexModifier->generate($indexes->get($field['field']));
133
            }
134
135
            if ($column->getComment() !== null) {
136
                $field['decorators'][] = $this->commentModifier->generate($column->getComment());
137
            }
138
139
            if (!$this->atLeastLaravel8()) {
140
                if ($field['type'] === DBALTypes::TIMESTAMP) {
141
                    if (($key1 = array_search(ColumnModifier::USE_CURRENT, $field['decorators'])) !== false &&
142
                        ($key2 = array_search(ColumnModifier::USE_CURRENT_ON_UPDATE, $field['decorators'])) !== false) {
143
                        unset($field['decorators'][$key1]);
144
                        unset($field['decorators'][$key2]);
145
                    }
146
                }
147
            }
148
149
            $fields[] = $field;
150
        }
151
        return $fields;
152
    }
153
154
    /**
155
     * @param  string  $tableName
156
     * @param  array  $field
157
     * @param  Column  $column
158
     * @param  Collection  $indexes
159
     * @param  bool  $useTimestamps
160
     * @return array
161
     */
162
    private function makeLaravelFieldTypeMethod(
163
        string $tableName,
164
        array $field,
165
        Column $column,
166
        Collection $indexes,
167
        bool $useTimestamps
168
    ): array {
169
        switch ($field['type']) {
170
            case DBALTypes::INTEGER:
171
            case DBALTypes::BIGINT:
172
            case DBALTypes::MEDIUMINT:
173
            case DBALTypes::SMALLINT:
174
            case DBALTypes::TINYINT:
175
                return $this->integerField->makeField($tableName, $field, $column, $indexes);
176
            case DBALTypes::DATETIME_MUTABLE:
177
            case DBALTypes::TIMESTAMP:
178
            case DBALTypes::TIME_MUTABLE:
179
                return $this->datetimeField->makeField($tableName, $field, $column, $useTimestamps);
180
            case DBALTypes::DECIMAL:
181
            case DBALTypes::FLOAT:
182
            case DBALTypes::DOUBLE:
183
                return $this->decimalField->makeField($field, $column);
184
            case DBALTypes::ENUM:
185
                return $this->enumField->makeField($tableName, $field, $column);
186
            case DBALTypes::GEOMETRY:
187
                return $this->geometryField->makeField($tableName, $field);
188
            case DBALTypes::SET:
189
                return $this->setField->makeField($tableName, $field, $column);
190
            case DBALTypes::STRING:
191
                return $this->stringField->makeField($tableName, $field, $column);
192
            default:
193
                return $this->otherField->makeField($tableName, $field, $column);
194
        }
195
    }
196
}
197