Completed
Push — 4.x ( 626ee6...0f520e )
by Kit Loong
01:36
created

SchemaGenerator   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 149
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 0
Metric Value
wmc 8
lcom 1
cbo 10
dl 0
loc 149
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A initialize() 0 53 2
A getTables() 0 4 1
A getFields() 0 9 1
A getForeignKeyConstraints() 0 4 1
A registerCustomDoctrineType() 0 14 2
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: liow.kitloong
5
 */
6
7
namespace KitLoong\MigrationsGenerator\Generators;
8
9
use Doctrine\DBAL\Types\Type;
10
use Illuminate\Support\Facades\DB;
11
use KitLoong\MigrationsGenerator\MigrationGeneratorSetting;
12
use KitLoong\MigrationsGenerator\Types\DoubleType;
13
use KitLoong\MigrationsGenerator\Types\EnumType;
14
use KitLoong\MigrationsGenerator\Types\GeometryCollectionType;
15
use KitLoong\MigrationsGenerator\Types\GeometryType;
16
use KitLoong\MigrationsGenerator\Types\IpAddressType;
17
use KitLoong\MigrationsGenerator\Types\JsonbType;
18
use KitLoong\MigrationsGenerator\Types\LineStringType;
19
use KitLoong\MigrationsGenerator\Types\LongTextType;
20
use KitLoong\MigrationsGenerator\Types\MacAddressType;
21
use KitLoong\MigrationsGenerator\Types\MediumIntegerType;
22
use KitLoong\MigrationsGenerator\Types\MediumTextType;
23
use KitLoong\MigrationsGenerator\Types\MultiLineStringType;
24
use KitLoong\MigrationsGenerator\Types\MultiPointType;
25
use KitLoong\MigrationsGenerator\Types\MultiPolygonType;
26
use KitLoong\MigrationsGenerator\Types\PointType;
27
use KitLoong\MigrationsGenerator\Types\PolygonType;
28
use KitLoong\MigrationsGenerator\Types\SetType;
29
use KitLoong\MigrationsGenerator\Types\TimestampType;
30
use KitLoong\MigrationsGenerator\Types\TimestampTzType;
31
use KitLoong\MigrationsGenerator\Types\TimeTzType;
32
use KitLoong\MigrationsGenerator\Types\UUIDType;
33
use KitLoong\MigrationsGenerator\Types\YearType;
34
use Xethron\MigrationsGenerator\Generators\ForeignKeyGenerator;
35
36
class SchemaGenerator
37
{
38
    /**
39
     * @var \Doctrine\DBAL\Schema\AbstractSchemaManager
40
     */
41
    protected $schema;
42
43
    /**
44
     * @var FieldGenerator
45
     */
46
    protected $fieldGenerator;
47
48
    /**
49
     * @var ForeignKeyGenerator
50
     */
51
    protected $foreignKeyGenerator;
52
53
    private $indexGenerator;
54
55
    /**
56
     * @var string
57
     */
58
    protected $database;
59
    /**
60
     * @var bool
61
     */
62
    private $ignoreIndexNames;
63
    /**
64
     * @var bool
65
     */
66
    private $ignoreForeignKeyNames;
67
68
    public function __construct(
69
        FieldGenerator $fieldGenerator,
70
        IndexGenerator $indexGenerator,
71
        ForeignKeyGenerator $foreignKeyGenerator
72
    ) {
73
        $this->fieldGenerator = $fieldGenerator;
74
        $this->indexGenerator = $indexGenerator;
75
        $this->foreignKeyGenerator = $foreignKeyGenerator;
76
    }
77
78
    /**
79
     * @param  string  $database
80
     * @param  bool  $ignoreIndexNames
81
     * @param  bool  $ignoreForeignKeyNames
82
     * @throws \Doctrine\DBAL\DBALException
83
     */
84
    public function initialize(string $database, bool $ignoreIndexNames, bool $ignoreForeignKeyNames)
85
    {
86
        /** @var MigrationGeneratorSetting $setting */
87
        $setting = resolve(MigrationGeneratorSetting::class);
88
89
        $this->registerCustomDoctrineType(DoubleType::class, 'double', 'double');
90
        $this->registerCustomDoctrineType(EnumType::class, 'enum', 'enum');
91
        $this->registerCustomDoctrineType(GeometryType::class, 'geometry', 'geometry');
92
        $this->registerCustomDoctrineType(GeometryCollectionType::class, 'geometrycollection', 'geometrycollection');
93
        $this->registerCustomDoctrineType(LineStringType::class, 'linestring', 'linestring');
94
        $this->registerCustomDoctrineType(LongTextType::class, 'longtext', 'longtext');
95
        $this->registerCustomDoctrineType(MediumIntegerType::class, 'mediumint', 'mediumint');
96
        $this->registerCustomDoctrineType(MediumTextType::class, 'mediumtext', 'mediumtext');
97
        $this->registerCustomDoctrineType(MultiLineStringType::class, 'multilinestring', 'multilinestring');
98
        $this->registerCustomDoctrineType(MultiPointType::class, 'multipoint', 'multipoint');
99
        $this->registerCustomDoctrineType(MultiPolygonType::class, 'multipolygon', 'multipolygon');
100
        $this->registerCustomDoctrineType(PointType::class, 'point', 'point');
101
        $this->registerCustomDoctrineType(PolygonType::class, 'polygon', 'polygon');
102
        $this->registerCustomDoctrineType(SetType::class, 'set', 'set');
103
        $this->registerCustomDoctrineType(TimestampType::class, 'timestamp', 'timestamp');
104
        $this->registerCustomDoctrineType(UUIDType::class, 'uuid', 'uuid');
105
        $this->registerCustomDoctrineType(YearType::class, 'year', 'year');
106
107
        // Postgres types
108
        $this->registerCustomDoctrineType(IpAddressType::class, 'ipaddress', 'inet');
109
        $this->registerCustomDoctrineType(JsonbType::class, 'jsonb', 'jsonb');
110
        $this->registerCustomDoctrineType(MacAddressType::class, 'macaddress', 'macaddr');
111
        $this->registerCustomDoctrineType(TimeTzType::class, 'timetz', 'timetz');
112
        $this->registerCustomDoctrineType(TimestampTzType::class, 'timestamptz', 'timestamptz');
113
114
        /** @var \Doctrine\DBAL\Connection $connection */
115
        $connection = DB::connection($database)->getDoctrineConnection();
116
117
        $connection->getDatabasePlatform()->registerDoctrineTypeMapping('bit', 'boolean');
118
        $connection->getDatabasePlatform()->registerDoctrineTypeMapping('json', 'json');
119
120
        switch ($setting->getPlatform()) {
121
            case Platform::POSTGRESQL:
122
                $connection->getDatabasePlatform()->registerDoctrineTypeMapping('_text', 'text');
123
                $connection->getDatabasePlatform()->registerDoctrineTypeMapping('_int4', 'integer');
124
                $connection->getDatabasePlatform()->registerDoctrineTypeMapping('_numeric', 'float');
125
                $connection->getDatabasePlatform()->registerDoctrineTypeMapping('cidr', 'string');
126
                break;
127
            default:
128
        }
129
130
        $this->database = $connection->getDatabase();
131
132
        $this->schema = $connection->getSchemaManager();
133
134
        $this->ignoreIndexNames = $ignoreIndexNames;
135
        $this->ignoreForeignKeyNames = $ignoreForeignKeyNames;
136
    }
137
138
    /**
139
     * @return string[]
140
     */
141
    public function getTables(): array
142
    {
143
        return $this->schema->listTableNames();
144
    }
145
146
    public function getFields(string $tableName): array
147
    {
148
        $table = $this->schema->listTableDetails($tableName);
149
        $indexes = $this->indexGenerator->generate($table, $this->ignoreIndexNames);
150
        $singleColIndexes = $indexes['single'];
151
        $multiColIndexes = $indexes['multi'];
152
        $fields = $this->fieldGenerator->generate($table, $singleColIndexes);
153
        return array_merge($fields, $multiColIndexes->toArray());
154
    }
155
156
    public function getForeignKeyConstraints(string $table): array
157
    {
158
        return $this->foreignKeyGenerator->generate($table, $this->schema, $this->ignoreForeignKeyNames);
159
    }
160
161
    /**
162
     * Register custom doctrineType
163
     * Will override if exists
164
     *
165
     * @param $class
166
     * @param $name
167
     * @param $type
168
     * @throws \Doctrine\DBAL\DBALException
169
     */
170
    public function registerCustomDoctrineType($class, $name, $type)
171
    {
172
        /** @var MigrationGeneratorSetting $setting */
173
        $setting = resolve(MigrationGeneratorSetting::class);
174
175
        if (!Type::hasType($name)) {
176
            Type::addType($name, $class);
177
        } else {
178
            Type::overrideType($name, $class);
179
        }
180
181
        $setting->getDatabasePlatform()
182
            ->registerDoctrineTypeMapping($type, $name);
183
    }
184
}
185