Passed
Push — main ( b94a81...f6c2a3 )
by Pranjal
02:29
created

WriteManager::saveForeignMtm()   A

Complexity

Conditions 5
Paths 39

Size

Total Lines 33
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 28
c 1
b 0
f 0
nc 39
nop 2
dl 0
loc 33
rs 9.1608
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->createTables($model);
42
        $this->connection->beginTransaction();
43
44
        try {
45
            $id = $this->createRecords($model);
46
            $model->set('id', $id);
47
            $this->connection->commit();
48
        } catch (\Exception $e) {
49
            $this->connection->rollBack();
50
            throw $e;
51
        }
52
53
        if ($model->hasForeign('otm')) {
54
            $this->saveForeignOtm($model, $id);
55
        }
56
57
        if ($model->hasForeign('mtm')) {
58
            $this->saveForeignMtm($model, $id);
59
        }
60
61
        $model->cleanModel();
62
        $model->setLoaded();
63
64
        return $id;
65
    }
66
67
    /**
68
     * Create tables.
69
     */
70
    private function createTables(Model $model): void
71
    {
72
        if (!$this->config->isFrozen()) {
73
            $table = $this->tableManager->createTable($model);
74
            $this->tableManager->saveOrUpdateTable($model->getName(), $table);
75
        }
76
    }
77
78
    /**
79
     * Create records.
80
     */
81
    private function createRecords(Model $model): mixed
82
    {
83
        if ($model->isLoaded()) {
84
            return $this->recordManager->update($model);
85
        }
86
87
        if ($model->hasIdError()) {
88
            throw new InvalidIdException();
89
        }
90
91
        return $this->recordManager->insert($model);
92
    }
93
94
    /**
95
     * Save One to One related model into database.
96
     */
97
    private function saveForeignOto(Model $model): void
98
    {
99
        foreach ($model->getForeignModels('oto') as $foreign) {
100
            $this->createTables($foreign);
101
        }
102
103
        $this->connection->beginTransaction();
104
        try {
105
            foreach ($model->getForeignModels('oto') as $foreign) {
106
                $id = $this->createRecords($foreign);
107
                $foreign->cleanModel();
108
                $foreign->setLoaded();
109
                $name = $foreign->getName().'_id';
110
                $model->$name = $id;
111
            }
112
            $this->connection->commit();
113
        } catch (\Exception $e) {
114
            $this->connection->rollBack();
115
            throw $e;
116
        }
117
    }
118
119
    /**
120
     * Save One to Many related model into database.
121
     */
122
    private function saveForeignOtm(Model $model, mixed $id): void
123
    {
124
        foreach ($model->getForeignModels('otm') as $foreign) {
125
            $key = $model->getName().'_id';
126
            $foreign->$key = $id;
127
            $this->createTables($foreign);
128
        }
129
        $this->connection->beginTransaction();
130
        try {
131
            foreach ($model->getForeignModels('otm') as $foreign) {
132
                $this->createRecords($foreign);
133
                $foreign->cleanModel();
134
                $foreign->setLoaded();
135
            }
136
            $this->connection->commit();
137
        } catch (\Exception $e) {
138
            $this->connection->rollBack();
139
            throw $e;
140
        }
141
    }
142
143
    /**
144
     * Save Many to Many related model into database.
145
     */
146
    private function saveForeignMtm(Model $model, mixed $id): void
147
    {
148
        foreach ($model->getForeignModels('mtm') as $foreign) {
149
            $model_id = $model->getName().'_id';
150
            $foreign_id = $foreign->getName().'_id';
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

150
            $foreign_id = $foreign->/** @scrutinizer ignore-call */ getName().'_id';
Loading history...
151
            $relational_table = $this->modelManager->create($model->getName().'_'.$foreign->getName());
152
            if ($this->config->isUsingUUID()) {
153
                $relational_table->$model_id = '';
154
                $relational_table->$foreign_id = '';
155
            } else {
156
                $relational_table->$model_id = 0;
157
                $relational_table->$foreign_id = 0;
158
            }
159
            $this->createTables($relational_table);
160
            $this->createTables($foreign);
161
        }
162
        $this->connection->beginTransaction();
163
        try {
164
            foreach ($model->getForeignModels('mtm') as $foreign) {
165
                $rel_id = $this->createRecords($foreign);
166
                $foreign->cleanModel();
167
                $foreign->setLoaded();
168
                $model_id = $model->getName().'_id';
169
                $foreign_id = $foreign->getName().'_id';
170
                $relational_table = $this->modelManager->create($model->getName().'_'.$foreign->getName());
171
                $relational_table->$model_id = $id;
172
                $relational_table->$foreign_id = $rel_id;
173
                $this->createRecords($relational_table);
174
            }
175
            $this->connection->commit();
176
        } catch (\Exception $e) {
177
            $this->connection->rollBack();
178
            throw $e;
179
        }
180
    }
181
}
182