WriteManager::saveForeignMtm()   A
last analyzed

Complexity

Conditions 5
Paths 39

Size

Total Lines 34
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 29
c 1
b 0
f 0
nc 39
nop 1
dl 0
loc 34
rs 9.1448
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 readonly Connection $connection,
23
        private readonly TableManager $tableManager,
24
        private readonly RecordManager $recordManager,
25
        private readonly ModelManager $modelManager,
26
        private readonly 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
            $constraints[] = new TableConstraint(
93
                $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 RectorPrefix202410\Nette\Utils\Finder or RectorPrefix202410\Nette\Utils\Html or RectorPrefix202410\Nette\Utils\ArrayList or PHPUnit\Architecture\Elements\Layer\Layer or SimpleXMLElement or RectorPrefix202410\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

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