TableManager::saveTable()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 7
rs 10
c 1
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the Scrawler package.
5
 *
6
 * (c) Pranjal Pandey <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Scrawler\Arca\Manager;
13
14
use Doctrine\DBAL\Connection;
15
use Doctrine\DBAL\Schema\AbstractSchemaManager;
16
use Doctrine\DBAL\Schema\Exception\TableDoesNotExist;
17
use Doctrine\DBAL\Schema\Schema;
18
use Doctrine\DBAL\Schema\Table;
19
use Doctrine\DBAL\Types\Type;
20
use Scrawler\Arca\Config;
21
use Scrawler\Arca\Model;
22
23
/**
24
 * Class resposible for creating and modifing table.
25
 */
26
final class TableManager
27
{
28
    /**
29
     * Store the instance of SchemaManager.
30
     */
31
    private readonly AbstractSchemaManager $manager;
32
33
    /**
34
     * Store the instance of Platform.
35
     */
36
    private readonly \Doctrine\DBAL\Platforms\AbstractPlatform $platform;
37
38
    /**
39
     * create TableManager.
40
     */
41
    public function __construct(
42
        private readonly Connection $connection,
43
        private readonly Config $config,
44
    ) {
45
        $this->manager = $this->connection->createSchemaManager();
0 ignored issues
show
Bug introduced by
The property manager is declared read-only in Scrawler\Arca\Manager\TableManager.
Loading history...
46
        $this->platform = $this->connection->getDatabasePlatform();
0 ignored issues
show
Bug introduced by
The property platform is declared read-only in Scrawler\Arca\Manager\TableManager.
Loading history...
47
    }
48
49
    /**
50
     * Creates a table schema from table instance.
51
     */
52
    public function createTableSchema(Table $table): Schema
53
    {
54
        return new Schema([$table]);
55
    }
56
57
    /**
58
     * Get Table schema from existing table.
59
     */
60
    public function getTableSchema(string $table): Schema
61
    {
62
        return new Schema([$this->manager->introspectTable($table)]);
63
    }
64
65
    /**
66
     * Get Table detail from existing table.
67
     */
68
    public function getTable(string $table): Table
69
    {
70
        return $this->manager->introspectTable($table);
71
    }
72
73
    /**
74
     * Create table from model.
75
     *
76
     * @param array<TableConstraint> $constraints
77
     */
78
    public function createTable(Model $model, array $constraints = []): Table
79
    {
80
        $table = new Table($model->getName());
81
        $table = $this->addPrimaryKey($table);
82
        $types = $model->getTypes();
83
        foreach (array_keys($model->getSelfProperties()) as $key) {
84
            $key_array = explode('_', $key);
85
            if ('id' != $key && 'id' === end($key_array)) {
86
                $table = $this->addIdColumn($table, $key);
87
            } elseif ('id' != $key) {
88
                $table->addColumn(
89
                    $key,
90
                    $types[$key],
91
                    ['notnull' => false, 'comment' => $types[$key]]
92
                );
93
            }
94
        }
95
96
        foreach ($constraints as $constraint) {
97
            $table->addForeignKeyConstraint(
98
                $constraint->getForeignTableName(),
99
                [$constraint->getLocalColumnName()],
100
                [$constraint->getForeignColumnName()],
101
                ['onUpdate' => 'CASCADE', 'onDelete' => 'CASCADE']
102
            );
103
        }
104
105
        return $table;
106
    }
107
108
    private function addPrimaryKey(Table $table): Table
109
    {
110
        if ($this->config->isUsingUUID()) {
111
            $table->addColumn(
112
                'id',
113
                'string',
114
                ['length' => 36, 'notnull' => true, 'comment' => 'string']
115
            );
116
        } else {
117
            $table->addColumn(
118
                'id',
119
                'integer',
120
                ['unsigned' => true, 'autoincrement' => true, 'comment' => 'integer']
121
            );
122
        }
123
        $table->setPrimaryKey(['id']);
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\DBAL\Schema\Table::setPrimaryKey() has been deprecated: Use {@see addPrimaryKeyConstraint()} instead. ( Ignorable by Annotation )

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

123
        /** @scrutinizer ignore-deprecated */ $table->setPrimaryKey(['id']);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
124
125
        return $table;
126
    }
127
128
    /**
129
     * Add id column to table.
130
     */
131
    private function addIdColumn(Table $table, string $key): Table
132
    {
133
        if ($this->config->isUsingUUID()) {
134
            $table->addColumn(
135
                $key,
136
                'string',
137
                ['length' => 36, 'notnull' => true, 'comment' => 'string']
138
            );
139
        } else {
140
            $table->addColumn(
141
                $key,
142
                'integer',
143
                ['unsigned' => true, 'notnull' => true, 'comment' => 'integer']
144
            );
145
        }
146
147
        return $table;
148
    }
149
150
    /**
151
     * Save table to database.
152
     */
153
    public function saveTable(Table $table): void
154
    {
155
        $schema = $this->createTableSchema($table);
156
        $queries = $schema->toSql($this->platform);
157
158
        foreach ($queries as $query) {
159
            $this->connection->executeQuery($query);
160
        }
161
    }
162
163
    /**
164
     * Add missing column to existing table from given table.
165
     */
166
    public function updateTable(string $table_name, Table $new_table): void
167
    {
168
        $comparator = $this->manager->createComparator();
169
        $old_table = $this->getTable($table_name);
170
        $old_schema = $this->getTableSchema($table_name);
171
172
        $tableDiff = $comparator->compareTables($old_table, $new_table);
173
        $mod_table = $old_table;
174
        foreach ($tableDiff->getAddedColumns() as $columnName => $column) {
175
            $mod_table->addColumn(
176
                $columnName,
177
                Type::getTypeRegistry()->lookupName($column->getType()),
178
                [
179
                    'notnull' => $column->getNotnull(),
180
                    'comment' => $column->getComment(),
181
                    'default' => $column->getDefault(),
182
                ]
183
            );
184
        }
185
        $new_schema = $this->createTableSchema($mod_table);
186
        $schemaDiff = $comparator->compareSchemas($old_schema, $new_schema);
187
188
        $queries = $this->platform->getAlterSchemaSQL($schemaDiff);
189
190
        foreach ($queries as $query) {
191
            $this->connection->executeQuery($query);
192
        }
193
    }
194
195
    /**
196
     * Check if table exists.
197
     */
198
    public function tableExists(string $table_name): bool
199
    {
200
        try {
201
            $this->getTable($table_name);
202
203
            return true;
204
        } catch (TableDoesNotExist) {
205
            return false;
206
        }
207
    }
208
209
    /**
210
     * If table exist update it else create it.
211
     */
212
    public function saveOrUpdateTable(string $table_name, Table $new_table): void
213
    {
214
        if ($this->tableExists($table_name)) {
215
            $this->updateTable($table_name, $new_table);
216
        } else {
217
            $this->saveTable($new_table);
218
        }
219
    }
220
}
221