Passed
Push — feature/collation ( 3b40b8...35613b )
by Kit Loong
64:11
created

DatetimeField::getPgSQLLength()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 8
rs 10
1
<?php
2
3
namespace KitLoong\MigrationsGenerator\Generators;
4
5
use Doctrine\DBAL\Schema\Column;
6
use Doctrine\DBAL\Types\DateTimeImmutableType;
7
use Doctrine\DBAL\Types\DateTimeType;
8
use Doctrine\DBAL\Types\DateTimeTzImmutableType;
9
use Doctrine\DBAL\Types\DateTimeTzType;
10
use KitLoong\MigrationsGenerator\MigrationMethod\ColumnModifier;
11
use KitLoong\MigrationsGenerator\MigrationMethod\ColumnName;
12
use KitLoong\MigrationsGenerator\MigrationMethod\ColumnType;
13
use KitLoong\MigrationsGenerator\MigrationsGeneratorSetting;
14
use KitLoong\MigrationsGenerator\Repositories\MySQLRepository;
15
use KitLoong\MigrationsGenerator\Repositories\PgSQLRepository;
16
use KitLoong\MigrationsGenerator\Repositories\SQLSrvRepository;
17
use KitLoong\MigrationsGenerator\Support\Regex;
18
use KitLoong\MigrationsGenerator\Types\DBALTypes;
19
20
class DatetimeField
21
{
22
    const SQLSRV_DATETIME_DEFAULT_SCALE = 3;
23
    const SQLSRV_DATETIME_DEFAULT_LENGTH = 8;
24
25
    const SQLSRV_DATETIME_TZ_DEFAULT_SCALE = 7;
26
    const SQLSRV_DATETIME_TZ_DEFAULT_LENGTH = 10;
27
28
    private $decorator;
29
    private $mySQLRepository;
30
    private $pgSQLRepository;
31
    private $sqlSrvRepository;
32
    private $regex;
33
34
    public function __construct(
35
        Decorator $decorator,
36
        MySQLRepository $mySQLRepository,
37
        PgSQLRepository $pgSQLRepository,
38
        SQLSrvRepository $sqlSrvRepository,
39
        Regex $regex
40
    ) {
41
        $this->decorator = $decorator;
42
        $this->mySQLRepository = $mySQLRepository;
43
        $this->pgSQLRepository = $pgSQLRepository;
44
        $this->sqlSrvRepository = $sqlSrvRepository;
45
        $this->regex = $regex;
46
    }
47
48
    public function makeField(string $table, array $field, Column $column, bool $useTimestamps): array
49
    {
50
        if ($useTimestamps) {
51
            if ($field['field'] === ColumnName::CREATED_AT) {
52
                return [];
53
            } elseif ($field['field'] === ColumnName::UPDATED_AT) {
54
                $field['type'] = ColumnType::TIMESTAMPS;
55
                $field['field'] = null;
56
            }
57
        }
58
59
        if ($field['field'] === ColumnName::DELETED_AT && !$column->getNotnull()) {
60
            $field['type'] = ColumnType::SOFT_DELETES;
61
            $field['field'] = null;
62
        }
63
64
        if (isset(FieldGenerator::$fieldTypeMap[$field['type']])) {
65
            $field['type'] = FieldGenerator::$fieldTypeMap[$field['type']];
66
        }
67
68
        $length = $this->getLength($table, $column);
69
        if ($length !== null && $length > 0) {
70
            if ($field['type'] === ColumnType::SOFT_DELETES) {
71
                $field['field'] = ColumnName::DELETED_AT;
72
            }
73
            $field['args'][] = $length;
74
        }
75
76
        if (app(MigrationsGeneratorSetting::class)->getPlatform() === Platform::MYSQL) {
77
            if ($column->getType()->getName() === DBALTypes::TIMESTAMP) {
78
                if ($this->mySQLRepository->useOnUpdateCurrentTimestamp($table, $column->getName())) {
79
                    $field['decorators'][] = ColumnModifier::USE_CURRENT_ON_UPDATE;
80
                }
81
            }
82
        }
83
84
        return $field;
85
    }
86
87
    public function makeDefault(Column $column): string
88
    {
89
        if (in_array($column->getDefault(), ['CURRENT_TIMESTAMP'], true)) {
90
            return ColumnModifier::USE_CURRENT;
91
        } else {
92
            $default = $this->decorator->columnDefaultToString($column->getDefault());
0 ignored issues
show
Bug introduced by
It seems like $column->getDefault() can also be of type null; however, parameter $args of KitLoong\MigrationsGener...columnDefaultToString() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

92
            $default = $this->decorator->columnDefaultToString(/** @scrutinizer ignore-type */ $column->getDefault());
Loading history...
93
            return $this->decorator->decorate(ColumnModifier::DEFAULT, [$default]);
94
        }
95
    }
96
97
    /**
98
     * @param  Column[]  $columns
99
     * @return bool
100
     */
101
    public function isUseTimestamps(array $columns): bool
102
    {
103
        /** @var Column[] $timestampsColumns */
104
        $timestampsColumns = [];
105
        foreach ($columns as $column) {
106
            if ($column->getName() === ColumnName::CREATED_AT || $column->getName() === ColumnName::UPDATED_AT) {
107
                $timestampsColumns[] = $column;
108
            }
109
        }
110
111
        $useTimestamps = false;
112
113
        if (count($timestampsColumns) === 2) {
114
            $useTimestamps = true;
115
            foreach ($timestampsColumns as $timestamp) {
116
                if ($timestamp->getNotnull() || $timestamp->getDefault() !== null) {
117
                    $useTimestamps = false;
118
                }
119
            }
120
        }
121
        return $useTimestamps;
122
    }
123
124
    private function getLength(string $table, Column $column): ?int
125
    {
126
        switch (app(MigrationsGeneratorSetting::class)->getPlatform()) {
127
            case Platform::POSTGRESQL:
128
                return $this->getPgSQLLength($table, $column);
129
            case Platform::SQLSERVER:
130
                return $this->getSQLSrvLength($table, $column);
131
            default:
132
                return $column->getLength();
133
        }
134
    }
135
136
    /**
137
     * @param  string  $table
138
     * @param  \Doctrine\DBAL\Schema\Column  $column
139
     * @return int|null
140
     */
141
    private function getPgSQLLength(string $table, Column $column): ?int
142
    {
143
        $rawType = ($this->pgSQLRepository->getTypeByColumnName($table, $column->getName()));
144
        $length = $this->regex->getTextBetween($rawType);
0 ignored issues
show
Bug introduced by
It seems like $rawType can also be of type null; however, parameter $text of KitLoong\MigrationsGener...Regex::getTextBetween() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

144
        $length = $this->regex->getTextBetween(/** @scrutinizer ignore-type */ $rawType);
Loading history...
145
        if ($length !== null) {
146
            return (int) $length;
147
        } else {
148
            return null;
149
        }
150
    }
151
152
    /**
153
     * @param  string  $table
154
     * @param  \Doctrine\DBAL\Schema\Column  $column
155
     * @return int|null
156
     */
157
    private function getSQLSrvLength(string $table, Column $column): ?int
158
    {
159
        $colDef = $this->sqlSrvRepository->getColumnDefinition($table, $column->getName());
160
161
        switch (get_class($column->getType())) {
162
            case DateTimeType::class:
163
            case DateTimeImmutableType::class:
164
                if ($colDef->getScale() === self::SQLSRV_DATETIME_DEFAULT_SCALE &&
165
                    $colDef->getLength() === self::SQLSRV_DATETIME_DEFAULT_LENGTH) {
166
                    return null;
167
                } else {
168
                    return $column->getScale();
169
                }
170
            case DateTimeTzType::class:
171
            case DateTimeTzImmutableType::class:
172
                if ($colDef->getScale() === self::SQLSRV_DATETIME_TZ_DEFAULT_SCALE &&
173
                    $colDef->getLength() === self::SQLSRV_DATETIME_TZ_DEFAULT_LENGTH) {
174
                    return null;
175
                } else {
176
                    return $column->getScale();
177
                }
178
            default:
179
                return $column->getScale();
180
        }
181
    }
182
}
183