Passed
Push — main ( e0d381...c6e32b )
by Pranjal
02:29
created

Database::exec()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 3
rs 10
1
<?php
2
declare(strict_types=1);
3
4
namespace Scrawler\Arca;
5
use \Doctrine\DBAL\Connection;
0 ignored issues
show
Bug introduced by
The type \Doctrine\DBAL\Connection was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
7
/**
8
 * 
9
 * Class that manages all interaction with database
10
 */
11
class Database
12
{
13
    /**
14
     * Doctrine DBAL connection instance
15
     * @var \Doctrine\DBAL\Connection
16
     */
17
    public Connection $connection;
18
    /**
19
     * Store the instance of current platform
20
     * @var \Doctrine\DBAL\Platforms\AbstractPlatform
21
     */
22
    public \Doctrine\DBAL\Platforms\AbstractPlatform $platform;
23
    /**
24
     * Doctrine schema manager
25
     * @var \Doctrine\DBAL\Schema\AbstractSchemaManager
26
     */
27
    public \Doctrine\DBAL\Schema\AbstractSchemaManager $manager;
28
    /**
29
     * When $isFrozen is set to true tables are not updated/created
30
     * @var bool
31
     */
32
    private bool $isFroozen = false;
33
    /**
34
     * You can switch between using uuid & id
35
     * @var bool
36
     */
37
    private bool $useUUID = false;
38
39
    public function __construct(Connection $connection , bool $useUUID = false)
40
    {
41
        $this->connection = $connection;
42
        $this->platform = $this->connection->getDatabasePlatform();
43
        $this->manager = $this->connection->createSchemaManager();
44
        $this->useUUID = $useUUID;
45
        Managers::create($connection, $useUUID);
46
        $this->registerEvents();
47
48
    }
49
50
    public function registerEvents()
51
    {
52
        Event::subscribeTo('model.save', function ($model) {
53
            return $this->save($model);
54
        });
55
        Event::subscribeTo('model.delete', function ($model) {
56
            return $this->delete($model);
57
        });
58
    }
59
60
61
    /**
62
     * Executes an SQL query and returns the number of row affected
63
     *
64
     * @param string $sql
65
     * @param array $params
66
     * @return integer
67
     */
68
    public function exec(string $sql, array $params=array()): int
69
    {
70
        return  $this->connection->executeStatement($sql, $params);
71
    }
72
73
    /**
74
     * Returns array of data from SQL select statement
75
     *
76
     * @param string $sql
77
     * @param array $params
78
     * @return array
79
     */
80
    public function getAll(string $sql, array $params=[]): array
81
    {
82
        return  $this->connection->executeQuery($sql, $params)->fetchAllAssociative();
83
    }
84
85
    /**
86
     * Creates model from name
87
     *
88
     * @param string $name
89
     * @return \Scrawler\Arca\Model
90
     */
91
    public function create(string $name) : Model
92
    {
93
        return new Model($name);
94
    }
95
96
    /**
97
     * Save model into database
98
     *
99
     * @param \Scrawler\Arca\Model $model
100
     * @return mixed returns int for id and string for uuid
101
     */
102
    public function save(\Scrawler\Arca\Model $model) : mixed
103
    {
104
        if ($model->hasForeign('oto')) {
105
            $this->saveForeignOto($model);
106
        }
107
        
108
        $this->createTables($model);
109
        $this->connection->beginTransaction();
110
111
        try {
112
            $id = $this->createRecords($model);
113
            $this->connection->commit();
114
        } catch (\Exception $e) {
115
            $this->connection->rollBack();
116
            throw $e;
117
        }
118
        
119
        if ($model->hasForeign('otm')) {
120
            $this->saveForeignOtm($model, $id);
121
        }
122
123
        if ($model->hasForeign('mtm')) {
124
            $this->saveForeignMtm($model, $id);
125
        }
126
127
        return $id;
128
    }
129
130
    private function createTables($model)
131
    {
132
        if (!$this->isFroozen) {
133
            $table = Managers::tableManager()->createTable($model);
134
            Managers::tableManager()->saveOrUpdateTable($model->getName(), $table);
135
        }
136
    }
137
138
    private function createRecords($model) : mixed
139
    {
140
        if ($model->isLoaded()) {
141
            return Managers::recordManager()->update($model);
142
        }
143
        
144
        return Managers::recordManager()->insert($model);
145
    }
146
147
148
    /**
149
     * Save One to One related model into database
150
     * @param Model $model
151
     * @return void
152
     */
153
    private function saveForeignOto(\Scrawler\Arca\Model $model): void
154
    {
155
        foreach ($model->getForeignModels('oto') as $foreign) {
156
            $this->createTables($foreign);
157
        }
158
159
        $this->connection->beginTransaction();
160
        try {
161
            foreach ($model->getForeignModels('oto') as $foreign) {
162
                $id = $this->createRecords($foreign);
163
                $name = $foreign->getName().'_id';
164
                $model->$name = $id;
165
            }
166
            $this->connection->commit();
167
        } catch (\Exception $e) {
168
            $this->connection->rollBack();
169
            throw $e;
170
        }
171
    }
172
173
174
    /**
175
     * Save One to Many related model into database
176
     * @param Model $model
177
     * @param mixed $id
178
     * @return void
179
     */
180
    private function saveForeignOtm(\Scrawler\Arca\Model $model, mixed $id): void
181
    {
182
        foreach ($model->getForeignModels('otm') as $foreigns) {
183
            foreach ($foreigns as $foreign) {
184
                $key = $model->getName().'_id';
185
                $foreign->$key = $id;
186
                $this->createTables($foreign);
187
            }
188
        }
189
        $this->connection->beginTransaction();
190
        try {
191
            foreach ($model->getForeignModels('otm') as $foreigns) {
192
                foreach ($foreigns as $foreign) {
193
                    $this->createRecords($foreign);
194
                }
195
            }
196
            $this->connection->commit();
197
        } catch (\Exception $e) {
198
            $this->connection->rollBack();
199
            throw $e;
200
        }
201
    }
202
203
204
    /**
205
     * Save Many to Many related model into database
206
     * @param Model $model
207
     * @param mixed $id
208
     * @return void
209
     */
210
    private function saveForeignMtm(\Scrawler\Arca\Model $model, mixed $id): void
211
    {
212
        foreach ($model->getForeignModels('mtm') as $foreigns) {
213
            foreach ($foreigns as $foreign) {
214
                $model_id = $model->getName().'_id';
215
                $foreign_id = $foreign->getName().'_id';
216
                $relational_table = $this->create($model->getName().'_'.$foreign->getName());
217
                if ($this->isUsingUUID()) {
218
                    $relational_table->$model_id = "";
219
                    $relational_table->$foreign_id = "";
220
                } else {
221
                    $relational_table->$model_id = 0;
222
                    $relational_table->$foreign_id = 0;
223
                }
224
                $this->createTables($relational_table);
225
                $this->createTables($foreign);
226
            }
227
        }
228
        $this->connection->beginTransaction();
229
        try {
230
            foreach ($model->getForeignModels('mtm') as $foreigns) {
231
                foreach ($foreigns as $foreign) {
232
                    $rel_id = $this->createRecords($foreign);
233
                    $model_id = $model->getName().'_id';
234
                    $foreign_id = $foreign->getName().'_id';
235
                    $relational_table = $this->create($model->getName().'_'.$foreign->getName());
236
                    $relational_table->$model_id = $id;
237
                    $relational_table->$foreign_id = $rel_id;
238
                    $this->createRecords($relational_table);
239
                }
240
            }
241
            $this->connection->commit();
242
        } catch (\Exception $e) {
243
            $this->connection->rollBack();
244
            throw $e;
245
        }
246
    }
247
248
    /**
249
     * Delete record from database
250
     *
251
     * @param \Scrawler\Arca\Model $model
252
     * @return mixed
253
     */
254
    public function delete(\Scrawler\Arca\Model $model) : mixed
255
    {
256
        return Managers::recordManager()->delete($model);
257
    }
258
259
    /**
260
     * Get collection of all records from table
261
     */
262
    public function get(String $table,mixed $id = null) : Model|Collection
263
    {
264
        // For backward compatibility reason
265
        if($id != null){
266
            return $this->getOne($table,$id);
267
        }
268
269
        return Managers::recordManager()->getAll($table);
270
    }
271
272
    /**
273
     * Get single record
274
     *
275
     */
276
    public function getOne(String $table, mixed $id) : Model
277
    {
278
        return Managers::recordManager()->getById($this->create($table), $id);
279
    }
280
281
    /**
282
     * Returns QueryBuilder to build query for finding data
283
     * Eg: db()->find('user')->where('active = 1')->get();
284
     *
285
     * @param string $name
286
     * @return QueryBuilder
287
     */
288
    public function find(string $name) : QueryBuilder
289
    {
290
        return Managers::recordManager()->find($name);
291
    }
292
293
    /**
294
     * Freezes table for production
295
     * @return void
296
     */
297
    public function freeze() : void
298
    {
299
        $this->isFroozen = true;
300
    }
301
302
    /**
303
     * Checks if database is currently using uuid rather than id
304
     * @return bool
305
     */
306
    public function isUsingUUID() : bool
307
    {
308
        return $this->useUUID;
309
    }
310
}
311