Passed
Push — main ( f4a2aa...551259 )
by Pranjal
02:19
created

TableManager::addPrimaryKey()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 12
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 18
rs 9.8666
1
<?php
2
/*
3
 * This file is part of the Scrawler package.
4
 *
5
 * (c) Pranjal Pandey <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Scrawler\Arca\Manager;
12
13
use Doctrine\DBAL\Connection;
14
use Doctrine\DBAL\Schema\AbstractSchemaManager;
15
use Doctrine\DBAL\Schema\Exception\TableDoesNotExist;
16
use Doctrine\DBAL\Schema\Schema;
17
use Doctrine\DBAL\Schema\Table;
18
use Doctrine\DBAL\Types\Type;
19
use Scrawler\Arca\Config;
20
use Scrawler\Arca\Model;
21
22
/**
23
 * Class resposible for creating and modifing table.
24
 */
25
final class TableManager
26
{
27
    /**
28
     * Store the instance of SchemaManager.
29
     */
30
    private AbstractSchemaManager $manager;
31
32
    /**
33
     * Store the instance of Platform.
34
     */
35
    private \Doctrine\DBAL\Platforms\AbstractPlatform $platform;
36
37
    /**
38
     * create TableManager.
39
     */
40
    public function __construct(
41
        private Connection $connection,
42
        private Config $config,
43
    ) {
44
        $this->manager = $this->connection->createSchemaManager();
45
        $this->platform = $this->connection->getDatabasePlatform();
46
    }
47
48
    /**
49
     * Creates a table schema from table instance.
50
     */
51
    public function createTableSchema(Table $table): Schema
52
    {
53
        return new Schema([$table]);
54
    }
55
56
    /**
57
     * Get Table schema from existing table.
58
     */
59
    public function getTableSchema(string $table): Schema
60
    {
61
        return new Schema([$this->manager->introspectTable($table)]);
62
    }
63
64
    /**
65
     * Get Table detail from existing table.
66
     */
67
    public function getTable(string $table): Table
68
    {
69
        return $this->manager->introspectTable($table);
70
    }
71
72
    /**
73
     * Create table from model.
74
     *
75
     * @param array<TableConstraint> $constraints
76
     */
77
    public function createTable(Model $model, array $constraints = []): Table
78
    {
79
        $table = new Table($model->getName());
80
        $table = $this->addPrimaryKey($table);
81
        $types = $model->getTypes();
82
        foreach ($model->getSelfProperties() as $key => $value) {
83
            $key_array = explode('_', $key);
84
            if ('id' != $key && 'id' == end($key_array)) {
85
                $table = $this->addIdColumn($table, $key);
86
            } elseif ('id' != $key) {
87
                $table->addColumn(
88
                    $key,
89
                    $types[$key],
90
                    ['notnull' => false, 'comment' => $types[$key]]
91
                );
92
            }
93
        }
94
95
        foreach ($constraints as $constraint) {
96
            $table->addForeignKeyConstraint(
97
                $constraint->getForeignTableName(),
98
                [$constraint->getLocalColumnName()],
99
                [$constraint->getForeignColumnName()],
100
                ['onUpdate' => 'CASCADE', 'onDelete' => 'CASCADE']
101
            );
102
        }
103
104
        return $table;
105
    }
106
107
    private function addPrimaryKey(Table $table): Table
108
    {
109
        if ($this->config->isUsingUUID()) {
110
            $table->addColumn(
111
                'id',
112
                'string',
113
                ['length' => 36, 'notnull' => true, 'comment' => 'string']
114
            );
115
        } else {
116
            $table->addColumn(
117
                'id',
118
                'integer',
119
                ['unsigned' => true, 'autoincrement' => true, 'comment' => 'integer']
120
            );
121
        }
122
        $table->setPrimaryKey(['id']);
123
124
        return $table;
125
    }
126
127
    /**
128
     * Add id column to table.
129
     */
130
    private function addIdColumn(Table $table, string $key): Table
131
    {
132
        if ($this->config->isUsingUUID()) {
133
            $table->addColumn(
134
                $key,
135
                'string',
136
                ['length' => 36, 'notnull' => true, 'comment' => 'string']
137
            );
138
        } else {
139
            $table->addColumn(
140
                $key,
141
                'integer',
142
                ['unsigned' => true, 'notnull' => true, 'comment' => 'integer']
143
            );
144
        }
145
146
        return $table;
147
    }
148
149
    /**
150
     * Save table to database.
151
     */
152
    public function saveTable(Table $table): void
153
    {
154
        $schema = $this->createTableSchema($table);
155
        $queries = $schema->toSql($this->platform);
156
        foreach ($queries as $query) {
157
            $this->connection->executeQuery($query);
158
        }
159
    }
160
161
    /**
162
     * Add missing column to existing table from given table.
163
     */
164
    public function updateTable(string $table_name, Table $new_table): void
165
    {
166
        $comparator = $this->manager->createComparator();
167
        $old_table = $this->getTable($table_name);
168
        $old_schema = $this->getTableSchema($table_name);
169
170
        $tableDiff = $comparator->compareTables($old_table, $new_table);
171
        $mod_table = $old_table;
172
        foreach ($tableDiff->getAddedColumns() as $column) {
173
            $mod_table->addColumn(
174
                $column->getName(),
175
                Type::getTypeRegistry()->lookupName($column->getType()),
176
                [
177
                    'notnull' => $column->getNotnull(),
178
                    'comment' => $column->getComment(),
179
                    'default' => $column->getDefault(),
180
                ]
181
            );
182
        }
183
        $new_schema = $this->createTableSchema($mod_table);
184
        $schemaDiff = $comparator->compareSchemas($old_schema, $new_schema);
185
186
        $queries = $this->platform->getAlterSchemaSQL($schemaDiff);
187
188
        foreach ($queries as $query) {
189
            $this->connection->executeQuery($query);
190
        }
191
    }
192
193
    /**
194
     * Check if table exists.
195
     */
196
    public function tableExists(string $table_name): bool
197
    {
198
        try {
199
            $this->getTable($table_name);
200
201
            return true;
202
        } catch (TableDoesNotExist $e) {
203
            return false;
204
        }
205
    }
206
207
    /**
208
     * If table exist update it else create it.
209
     */
210
    public function saveOrUpdateTable(string $table_name, Table $new_table): void
211
    {
212
        if ($this->tableExists($table_name)) {
213
            $this->updateTable($table_name, $new_table);
214
215
            return;
216
        }
217
218
        $this->saveTable($new_table);
219
220
        return;
221
    }
222
}
223