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

WriteManager::createConstraintsMtm()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 14
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 21
rs 9.7998
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
declare(strict_types=1);
11
12
namespace Scrawler\Arca\Manager;
13
14
use Doctrine\DBAL\Connection;
15
use Scrawler\Arca\Config;
16
use Scrawler\Arca\Exception\InvalidIdException;
17
use Scrawler\Arca\Model;
18
19
final class WriteManager
20
{
21
    public function __construct(
22
        private Connection $connection,
23
        private TableManager $tableManager,
24
        private RecordManager $recordManager,
25
        private ModelManager $modelManager,
26
        private Config $config,
27
    ) {
28
    }
29
30
    /**
31
     * Save model into database.
32
     *
33
     * @return mixed returns int for id and string for uuid
34
     */
35
    public function save(Model $model): mixed
36
    {
37
        if ($model->hasForeign('oto')) {
38
            $this->saveForeignOto($model);
39
        }
40
41
        $this->createTable(
42
            $model,
43
            $this->createConstraintsOto($model)
44
        );
45
        $this->connection->beginTransaction();
46
47
        try {
48
            $id = $this->createRecords($model);
49
            $model->set('id', $id);
50
            $this->connection->commit();
51
        } catch (\Exception $e) {
52
            $this->connection->rollBack();
53
            throw $e;
54
        }
55
56
        if ($model->hasForeign('otm')) {
57
            $this->saveForeignOtm($model);
58
        }
59
60
        if ($model->hasForeign('mtm')) {
61
            $this->saveForeignMtm($model);
62
        }
63
64
        $model->cleanModel();
65
        $model->setLoaded();
66
67
        return $id;
68
    }
69
70
    /**
71
     * Create tables.
72
     *
73
     * @param array<TableConstraint> $constraints
74
     */
75
    private function createTable(Model $model, array $constraints = []): void
76
    {
77
        if (!$this->config->isFrozen()) {
78
            $table = $this->tableManager->createTable($model, $constraints);
79
            $this->tableManager->saveOrUpdateTable($model->getName(), $table);
80
        }
81
    }
82
83
    /**
84
     * Add constraint to table.
85
     *
86
     * @return array<TableConstraint>
87
     */
88
    private function createConstraintsOto(Model $model): array
89
    {
90
        $constraints = [];
91
        foreach ($model->getForeignModels('oto') as $foreign) {
92
            array_push(
93
                $constraints,
94
                new TableConstraint(
95
                    $foreign->getName(),
0 ignored issues
show
Bug introduced by
The method getName() does not exist on Traversable. It seems like you code against a sub-type of Traversable such as SimpleXMLElement or Scrawler\Arca\Model or Pest\Arch\Layer or RectorPrefix202312\Nette\Utils\Html or RectorPrefix202312\Nette\Utils\ArrayList or PHPUnit\Architecture\Elements\Layer\Layer or SimpleXMLElement or RectorPrefix202312\Nette\Iterators\CachingIterator or SimpleXMLElement or SimpleXMLIterator. ( Ignorable by Annotation )

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

95
                    $foreign->/** @scrutinizer ignore-call */ 
96
                              getName(),
Loading history...
96
                    $foreign->getName().'_id',
97
                    'id',
98
                )
99
            );
100
        }
101
102
        return $constraints;
103
    }
104
105
    /**
106
     * Add constraint to table.
107
     *
108
     * @return array<TableConstraint>
109
     */
110
    private function createConstraintsOtm(Model $model, Model $foreign): array
0 ignored issues
show
Unused Code introduced by
The parameter $foreign is not used and could be removed. ( Ignorable by Annotation )

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

110
    private function createConstraintsOtm(Model $model, /** @scrutinizer ignore-unused */ Model $foreign): array

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
111
    {
112
        $constraints = [];
113
        array_push(
114
            $constraints,
115
            new TableConstraint(
116
                $model->getName(),
117
                $model->getName().'_id',
118
                'id'
119
            )
120
        );
121
122
        return $constraints;
123
    }
124
125
    /**
126
     * Add constraint to table.
127
     *
128
     * @return array<TableConstraint>
129
     */
130
    private function createConstraintsMtm(Model $model, Model $foreign): array
131
    {
132
        $constraints = [];
133
        array_push(
134
            $constraints,
135
            new TableConstraint(
136
                $model->getName(),
137
                $model->getName().'_id',
138
                'id'
139
            )
140
        );
141
        array_push(
142
            $constraints,
143
            new TableConstraint(
144
                $foreign->getName(),
145
                $foreign->getName().'_id',
146
                'id'
147
            )
148
        );
149
150
        return $constraints;
151
    }
152
153
    /**
154
     * Create records.
155
     */
156
    private function createRecords(Model $model): mixed
157
    {
158
        if ($model->isLoaded()) {
159
            return $this->recordManager->update($model);
160
        }
161
162
        if ($model->hasIdError()) {
163
            throw new InvalidIdException();
164
        }
165
166
        return $this->recordManager->insert($model);
167
    }
168
169
    /**
170
     * Save One to One related model into database.
171
     */
172
    private function saveForeignOto(Model $model): void
173
    {
174
        foreach ($model->getForeignModels('oto') as $foreign) {
175
            $this->createTable($foreign);
176
        }
177
        $this->connection->beginTransaction();
178
        try {
179
            foreach ($model->getForeignModels('oto') as $foreign) {
180
                $id = $this->createRecords($foreign);
181
                $foreign->cleanModel();
182
                $foreign->setLoaded();
183
                $name = $foreign->getName().'_id';
184
                $model->$name = $id;
185
            }
186
            $this->connection->commit();
187
        } catch (\Exception $e) {
188
            $this->connection->rollBack();
189
            throw $e;
190
        }
191
    }
192
193
    /**
194
     * Save One to Many related model into database.
195
     */
196
    private function saveForeignOtm(Model $model): void
197
    {
198
        $id = $model->getId();
199
        foreach ($model->getForeignModels('otm') as $foreign) {
200
            $key = $model->getName().'_id';
201
            $foreign->$key = $id;
202
            $this->createTable($foreign, $this->createConstraintsOtm($model, $foreign));
203
        }
204
        $this->connection->beginTransaction();
205
        try {
206
            foreach ($model->getForeignModels('otm') as $foreign) {
207
                $this->createRecords($foreign);
208
                $foreign->cleanModel();
209
                $foreign->setLoaded();
210
            }
211
            $this->connection->commit();
212
        } catch (\Exception $e) {
213
            $this->connection->rollBack();
214
            throw $e;
215
        }
216
    }
217
218
    /**
219
     * Save Many to Many related model into database.
220
     */
221
    private function saveForeignMtm(Model $model): void
222
    {
223
        $id = $model->getId();
224
        foreach ($model->getForeignModels('mtm') as $foreign) {
225
            $model_id = $model->getName().'_id';
226
            $foreign_id = $foreign->getName().'_id';
227
            $relational_table = $this->modelManager->create($model->getName().'_'.$foreign->getName());
228
            if ($this->config->isUsingUUID()) {
229
                $relational_table->$model_id = '';
230
                $relational_table->$foreign_id = '';
231
            } else {
232
                $relational_table->$model_id = 0;
233
                $relational_table->$foreign_id = 0;
234
            }
235
            $this->createTable($foreign);
236
            $this->createTable($relational_table, $this->createConstraintsMtm($model, $foreign));
237
        }
238
        $this->connection->beginTransaction();
239
        try {
240
            foreach ($model->getForeignModels('mtm') as $foreign) {
241
                $rel_id = $this->createRecords($foreign);
242
                $foreign->cleanModel();
243
                $foreign->setLoaded();
244
                $model_id = $model->getName().'_id';
245
                $foreign_id = $foreign->getName().'_id';
246
                $relational_table = $this->modelManager->create($model->getName().'_'.$foreign->getName());
247
                $relational_table->$model_id = $id;
248
                $relational_table->$foreign_id = $rel_id;
249
                $this->createRecords($relational_table);
250
            }
251
            $this->connection->commit();
252
        } catch (\Exception $e) {
253
            $this->connection->rollBack();
254
            throw $e;
255
        }
256
    }
257
}
258