Passed
Push — main ( 03c841...81f215 )
by Pranjal
03:12
created

Database::isUsingUUID()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace Scrawler\Arca;
5
6
/**
7
 * 
8
 * Class that manages all interaction with database
9
 */
10
class Database
11
{
12
    /**
13
     * Store the instance of current connection
14
     * @var \Scrawler\Arca\Connection
15
     */
16
    private Connection $connection;
17
    /**
18
     * When $isFrozen is set to true tables are not updated/created
19
     * @var bool
20
     */
21
    private bool $isFroozen = false;
22
    
23
24
    public function __construct(Connection $connection)
25
    {
26
        $this->connection = $connection;
27
        $this->registerEvents();
28
29
    }
30
31
    public function registerEvents()
32
    {
33
        Event::subscribeTo('system.model.save.'.$this->connection->getConnectionId(), function ($model) {
34
            return $this->save($model);
35
        });
36
        Event::subscribeTo('system.model.delete.'.$this->connection->getConnectionId(), function ($model) {
37
            return $this->delete($model);
38
        });
39
    }
40
41
    /**
42
     * Executes an SQL query and returns the number of row affected
43
     *
44
     * @param string $sql
45
     * @param array $params
46
     * @return integer
47
     */
48
    public function exec(string $sql, array $params=array()): int
49
    {
50
        return  $this->connection->executeStatement($sql, $params);
0 ignored issues
show
Bug introduced by
The method executeStatement() does not exist on Scrawler\Arca\Connection. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

50
        return  $this->connection->/** @scrutinizer ignore-call */ executeStatement($sql, $params);
Loading history...
51
    }
52
53
    /**
54
     * Returns array of data from SQL select statement
55
     *
56
     * @param string $sql
57
     * @param array $params
58
     * @return array
59
     */
60
    public function getAll(string $sql, array $params=[]): array
61
    {
62
        return  $this->connection->executeQuery($sql, $params)->fetchAllAssociative();
0 ignored issues
show
Bug introduced by
The method executeQuery() does not exist on Scrawler\Arca\Connection. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

62
        return  $this->connection->/** @scrutinizer ignore-call */ executeQuery($sql, $params)->fetchAllAssociative();
Loading history...
63
    }
64
65
    /**
66
     * Creates model from name
67
     *
68
     * @param string $name
69
     * @return \Scrawler\Arca\Model
70
     */
71
    public function create(string $name) : Model
72
    {
73
        return $this->connection->getModelManager()->create($name);
74
    }
75
76
    /**
77
     * Save model into database
78
     *
79
     * @param \Scrawler\Arca\Model $model
80
     * @return mixed returns int for id and string for uuid
81
     */
82
    public function save(\Scrawler\Arca\Model $model) : mixed
83
    {
84
        if ($model->hasForeign('oto')) {
85
            $this->saveForeignOto($model);
86
        }
87
        
88
        $this->createTables($model);
89
        $this->connection->beginTransaction();
0 ignored issues
show
Bug introduced by
The method beginTransaction() does not exist on Scrawler\Arca\Connection. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

89
        $this->connection->/** @scrutinizer ignore-call */ 
90
                           beginTransaction();
Loading history...
90
91
        try {
92
            $id = $this->createRecords($model);
93
            $model->id = $id;
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on Scrawler\Arca\Model. Since you implemented __set, consider adding a @property annotation.
Loading history...
94
            $model->setLoaded();
95
            $this->connection->commit();
0 ignored issues
show
Bug introduced by
The method commit() does not exist on Scrawler\Arca\Connection. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

95
            $this->connection->/** @scrutinizer ignore-call */ 
96
                               commit();
Loading history...
96
        } catch (\Exception $e) {
97
            $this->connection->rollBack();
0 ignored issues
show
Bug introduced by
The method rollBack() does not exist on Scrawler\Arca\Connection. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

97
            $this->connection->/** @scrutinizer ignore-call */ 
98
                               rollBack();
Loading history...
98
            throw $e;
99
        }
100
        
101
        if ($model->hasForeign('otm')) {
102
            $this->saveForeignOtm($model, $id);
103
        }
104
105
        if ($model->hasForeign('mtm')) {
106
            $this->saveForeignMtm($model, $id);
107
        }
108
109
        return $id;
110
    }
111
112
    private function createTables($model)
113
    {
114
        if (!$this->isFroozen) {
115
            $table = $this->connection->getTableManager()->createTable($model);
116
            $this->connection->getTableManager()->saveOrUpdateTable($model->getName(), $table);
117
        }
118
    }
119
120
    private function createRecords($model) : mixed
121
    {
122
        if ($model->isLoaded()) {
123
            return $this->connection->getRecordManager()->update($model);
124
        }
125
        return $this->connection->getRecordManager()->insert($model);
126
    }
127
128
129
    /**
130
     * Save One to One related model into database
131
     * @param Model $model
132
     * @return void
133
     */
134
    private function saveForeignOto(\Scrawler\Arca\Model $model): void
135
    {
136
        foreach ($model->getForeignModels('oto') as $foreign) {
137
            $this->createTables($foreign);
138
        }
139
140
        $this->connection->beginTransaction();
141
        try {
142
            foreach ($model->getForeignModels('oto') as $foreign) {
143
                $id = $this->createRecords($foreign);
144
                $name = $foreign->getName().'_id';
145
                $model->$name = $id;
146
            }
147
            $this->connection->commit();
148
        } catch (\Exception $e) {
149
            $this->connection->rollBack();
150
            throw $e;
151
        }
152
    }
153
154
155
    /**
156
     * Save One to Many related model into database
157
     * @param Model $model
158
     * @param mixed $id
159
     * @return void
160
     */
161
    private function saveForeignOtm(\Scrawler\Arca\Model $model, mixed $id): void
162
    {
163
        foreach ($model->getForeignModels('otm') as $foreigns) {
164
            foreach ($foreigns as $foreign) {
165
                $key = $model->getName().'_id';
166
                $foreign->$key = $id;
167
                $this->createTables($foreign);
168
            }
169
        }
170
        $this->connection->beginTransaction();
171
        try {
172
            foreach ($model->getForeignModels('otm') as $foreigns) {
173
                foreach ($foreigns as $foreign) {
174
                    $this->createRecords($foreign);
175
                }
176
            }
177
            $this->connection->commit();
178
        } catch (\Exception $e) {
179
            $this->connection->rollBack();
180
            throw $e;
181
        }
182
    }
183
184
185
    /**
186
     * Save Many to Many related model into database
187
     * @param Model $model
188
     * @param mixed $id
189
     * @return void
190
     */
191
    private function saveForeignMtm(\Scrawler\Arca\Model $model, mixed $id): void
192
    {
193
        foreach ($model->getForeignModels('mtm') as $foreigns) {
194
            foreach ($foreigns as $foreign) {
195
                $model_id = $model->getName().'_id';
196
                $foreign_id = $foreign->getName().'_id';
197
                $relational_table = $this->create($model->getName().'_'.$foreign->getName());
198
                if ($this->isUsingUUID()) {
199
                    $relational_table->$model_id = "";
200
                    $relational_table->$foreign_id = "";
201
                } else {
202
                    $relational_table->$model_id = 0;
203
                    $relational_table->$foreign_id = 0;
204
                }
205
                $this->createTables($relational_table);
206
                $this->createTables($foreign);
207
            }
208
        }
209
        $this->connection->beginTransaction();
210
        try {
211
            foreach ($model->getForeignModels('mtm') as $foreigns) {
212
                foreach ($foreigns as $foreign) {
213
                    $rel_id = $this->createRecords($foreign);
214
                    $model_id = $model->getName().'_id';
215
                    $foreign_id = $foreign->getName().'_id';
216
                    $relational_table = $this->create($model->getName().'_'.$foreign->getName());
217
                    $relational_table->$model_id = $id;
218
                    $relational_table->$foreign_id = $rel_id;
219
                    $this->createRecords($relational_table);
220
                }
221
            }
222
            $this->connection->commit();
223
        } catch (\Exception $e) {
224
            $this->connection->rollBack();
225
            throw $e;
226
        }
227
    }
228
229
    /**
230
     * Delete record from database
231
     *
232
     * @param \Scrawler\Arca\Model $model
233
     * @return mixed
234
     */
235
    public function delete(\Scrawler\Arca\Model $model) : mixed
236
    {
237
        return $this->connection->getRecordManager()->delete($model);
238
    }
239
240
    /**
241
     * Get collection of all records from table
242
     */
243
    public function get(String $table) : Collection
244
    {
245
       
246
        return $this->connection->getRecordManager()->getAll($table);
247
    }
248
249
    /**
250
     * Get single record
251
     *
252
     */
253
    public function getOne(String $table, mixed $id) : Model
254
    {
255
        return $this->connection->getRecordManager()->getById($table, $id);
256
    }
257
258
    /**
259
     * Returns QueryBuilder to build query for finding data
260
     * Eg: db()->find('user')->where('active = 1')->get();
261
     *
262
     * @param string $name
263
     * @return QueryBuilder
264
     */
265
    public function find(string $name) : QueryBuilder
266
    {
267
        return $this->connection->getRecordManager()->find($name);
268
    }
269
270
    /**
271
     * Freezes table for production
272
     * @return void
273
     */
274
    public function freeze() : void
275
    {
276
        $this->isFroozen = true;
277
    }
278
279
    /**
280
     * Checks if database is currently using uuid rather than id
281
     * @return bool
282
     */
283
    public function isUsingUUID() : bool
284
    {
285
        return $this->connection->isUsingUUID();
286
    }
287
288
    /**
289
     * Returns the current connection
290
     * @return Connection
291
     */
292
    public function getConnection() : Connection
293
    {
294
        return $this->connection;
295
    }
296
297
    public function tablesExist($tables) : bool
298
    {
299
        return $this->connection->getSchemaManager()->tablesExist($tables);
300
    }
301
}
302