Completed
Push — master ( 5be80c...46b0a8 )
by Ryuichi
08:04
created

DatabaseManager   B

Complexity

Total Complexity 37

Size/Duplication

Total Lines 270
Duplicated Lines 0 %

Test Coverage

Coverage 71.28%

Importance

Changes 0
Metric Value
dl 0
loc 270
ccs 67
cts 94
cp 0.7128
rs 8.6
c 0
b 0
f 0
wmc 37

16 Methods

Rating   Name   Duplication   Size   Complexity  
A connect() 0 8 2
A rollback() 0 16 4
A disconnect() 0 15 3
C beginTransaction() 0 26 7
A commit() 0 16 4
A __construct() 0 5 1
A __destruct() 0 4 1
A enableAutoCommit() 0 3 1
A loadConnection() 0 8 2
A inTransaction() 0 3 1
A query() 0 9 2
A isConnected() 0 3 1
B transactional() 0 21 5
A isRollback() 0 3 1
A disableAutoCommit() 0 3 1
A getTransactionIsolation() 0 3 1
1
<?php
2
namespace WebStream\Database;
3
4
use WebStream\DI\Injector;
0 ignored issues
show
Bug introduced by
The type WebStream\DI\Injector 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...
5
use WebStream\Container\Container;
0 ignored issues
show
Bug introduced by
The type WebStream\Container\Container 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
use WebStream\Exception\Extend\DatabaseException;
0 ignored issues
show
Bug introduced by
The type WebStream\Exception\Extend\DatabaseException 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...
7
use Doctrine\DBAL\Connection;
8
9
/**
10
 * DatabaseManager
11
 * @author Ryuichi TANAKA.
12
 * @since 2013/12/07
13
 * @version 0.4
14
 */
15
class DatabaseManager
16
{
17
    use Injector;
18
19
    /**
20
     * @var ConnectionManager コネクションマネージャ
21
     */
22
    private $connectionManager;
23
24
    /**
25
     * @var DatabaseDriver データベースコネクション
0 ignored issues
show
Bug introduced by
The type WebStream\Database\DatabaseDriver 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...
26
     */
27
    private $connection;
28
29
    /**
30
     * @var bool 自動コミットフラグ
31
     */
32
    private $isAutoCommit;
33
34
    /**
35
     * @var Query クエリオブジェクト
36
     */
37
    private $query;
38
39
    /**
40
     * @var Logger ロガー
0 ignored issues
show
Bug introduced by
The type WebStream\Database\Logger 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...
41
     */
42
    private $logger;
43
44
    /**
45
     * constructor
46
     * @param Container 依存コンテナ
47
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment 依存コンテナ at position 0 could not be parsed: Unknown type name '依存コンテナ' at position 0 in 依存コンテナ.
Loading history...
48 39
    public function __construct(Container $container)
49
    {
50 39
        $this->connectionManager = new ConnectionManager($container);
51 39
        $this->logger = $container->logger;
52 39
        $this->isAutoCommit = false;
53
    }
54
55
    /**
56
     * destructor
57
     */
58 39
    public function __destruct()
59
    {
60 39
        $this->disconnect();
61 39
        $this->query = null;
62
    }
63
64
    /**
65
     * データベース接続する
66
     * すでに接続中であれば再接続はしない
67
     */
68 39
    public function connect()
69
    {
70
        try {
71 39
            $this->connection->connect();
72 39
            $this->query = new Query($this->connection);
73 39
            $this->query->inject('logger', $this->logger);
74
        } catch (\PDOException $e) {
75
            throw new DatabaseException($e);
76
        }
77
    }
78
79
    /**
80
     * データベース切断する
81
     */
82 39
    public function disconnect()
83
    {
84 39
        if ($this->connection === null) {
85 39
            return;
86
        }
87
88 39
        if ($this->inTransaction()) {
89
            // トランザクションが明示的に開始された状態でcommit/rollbackが行われていない場合
90
            // ログに警告を書き込み、強制的にロールバックする
91 12
            $this->connection->rollback();
92 12
            $this->logger->warn("Not has been executed commit or rollback after the transaction started.");
93
        }
94
95 39
        $this->connection->disconnect();
96 39
        $this->connection = null;
97
    }
98
99
    /**
100
     * トランザクションを開始する
101
     * @param int $isolationLevel トランザクション分離レベル
102
     */
103 12
    public function beginTransaction(int $isolationLevel)
104
    {
105
        // 既にトランザクションが開始されている場合、継続しているトランザクションを有効のままにする
106
        // トランザクションを破棄して再度開始する場合は明示的に破棄してから再呼び出しする
107 12
        if ($this->inTransaction()) {
108
            $this->logger->debug("Transaction already started.");
109
110
            return;
111
        }
112
113 12
        if (!$this->connection->beginTransaction()) {
114
            throw new DatabaseException("Failed to start transaction.");
115
        }
116
117 12
        $this->connection->setAutoCommit($this->isAutoCommit);
118
119 12
        if ($isolationLevel === Connection::TRANSACTION_READ_UNCOMMITTED ||
120 12
            $isolationLevel === Connection::TRANSACTION_READ_COMMITTED ||
121
            $isolationLevel === Connection::TRANSACTION_REPEATABLE_READ ||
122
            $isolationLevel === Connection::TRANSACTION_SERIALIZABLE) {
123 12
            $this->connection->setTransactionIsolation($isolationLevel);
124
        } else {
125
            throw new DatabaseException("Invalid transaction isolation level: " . $isolationLevel);
126
        }
127
128 12
        $this->logger->debug("Transaction start.");
129
    }
130
131
    /**
132
     * コミットする
133
     */
134 6
    public function commit()
135
    {
136
        try {
137 6
            if ($this->connection !== null) {
138 6
                if ($this->inTransaction()) {
139 6
                    $this->connection->commit();
140 6
                    $this->logger->debug("Execute commit.");
141
                } else {
142
                    $this->logger->warn("Not executed commit because the transaction is not started.");
143
                }
144
            } else {
145
                throw new DatabaseException("Can't execute commit.");
146
            }
147
        } catch (\Exception $e) {
148
            $this->query = null;
149
            throw new DatabaseException($e);
150
        }
151
    }
152
153
    /**
154
     * ロールバックする
155
     */
156 6
    public function rollback()
157
    {
158
        try {
159 6
            if ($this->connection !== null) {
160 6
                if ($this->inTransaction()) {
161 6
                    $this->connection->rollback();
162 6
                    $this->logger->debug("Execute rollback.");
163
                } else {
164
                    $this->logger->warn("Not executed rollback because the transaction is not started.");
165
                }
166
            } else {
167
                throw new DatabaseException("Can't execute rollback.");
168
            }
169
        } catch (\Exception $e) {
170
            $this->query = null;
171
            throw new DatabaseException($e);
172
        }
173
    }
174
175
    /**
176
     * トランザクションスコープを使用する
177
     * @param  Closure $closure クロージャ
0 ignored issues
show
Bug introduced by
The type WebStream\Database\Closure was not found. Did you mean Closure? If so, make sure to prefix the type with \.
Loading history...
178
     * @return object 処理結果
179
     */
180 6
    public function transactional(\Closure $closure, $config = [])
181
    {
182 6
        if (!array_key_exists('isolationLevel', $config)) {
183 3
            $config['isolationLevel'] = Connection::TRANSACTION_READ_COMMITTED;
184
        }
185 6
        if (!array_key_exists('autoCommit', $config)) {
186 3
            $config['autoCommit'] = false;
187
        }
188
189 6
        $this->isAutoCommit = $config['autoCommit'];
190 6
        $this->beginTransaction($config['isolationLevel']);
191
        try {
192 6
            $result = $closure($this);
193 3
            $this->commit();
194 3
            return $result;
195 3
        } catch (DatabaseException $e) {
196
            $this->rollback();
197
            throw $e;
198 3
        } catch (\Throwable $e) {
199 3
            $this->rollback();
200 3
            throw new DatabaseException($e);
201
        }
202
    }
203
204
    /**
205
     * 自動コミットを有効化
206
     */
207 12
    public function enableAutoCommit()
208
    {
209 12
        $this->isAutoCommit = true;
210
    }
211
212
    /**
213
     * 自動コミットを無効化
214
     */
215 3
    public function disableAutoCommit()
216
    {
217 3
        $this->isAutoCommit = false;
218
    }
219
220
    /**
221
     * ロールバックが発生したかどうか
222
     * @return boolean ロールバックが発生したかどうか
223
     */
224
    public function isRollback()
225
    {
226
        return $this->isRollback;
227
    }
228
229
    /**
230
     * トランザクション内かどうか
231
     * @return boolean トランザクション内かどうか
232
     */
233 39
    public function inTransaction()
234
    {
235 39
        return $this->connection->inTransaction();
236
    }
237
238
    /**
239
     * DB接続されているか
240
     * @param boolean 接続有無
241
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment 接続有無 at position 0 could not be parsed: Unknown type name '接続有無' at position 0 in 接続有無.
Loading history...
242
    public function isConnected()
243
    {
244
        return $this->connection->isConnected();
245
    }
246
247
    /**
248
     * トランザクション分離レベルを返却する
249
     * @return int トランザクション分離レベル
250
     */
251
    public function getTransactionIsolation()
252
    {
253
        return $this->connection->getTransactionIsolation();
254
    }
255
256
    /**
257
     * データベース接続が可能かどうか
258
     * @param string Modelファイルパス
259
     * @return boolean 接続可否
260
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment Modelファイルパス at position 0 could not be parsed: Unknown type name 'Modelファイルパス' at position 0 in Modelファイルパス.
Loading history...
261 39
    public function loadConnection($filepath)
262
    {
263 39
        $connection = $this->connectionManager->getConnection($filepath);
264 39
        if ($connection !== null) {
265 39
            $this->connection = $connection;
266
        }
267
268 39
        return $this->connection !== null;
269
    }
270
271
    /**
272
     * クエリを設定する
273
     * @param string SQL
274
     * @param array<string> パラメータ
275
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment パラメータ at position 0 could not be parsed: Unknown type name 'パラメータ' at position 0 in パラメータ.
Loading history...
276 39
    public function query($sql, array $bind = [])
277
    {
278 39
        if ($this->query === null) {
279
            throw new DatabaseException("Query does not set because database connection failed.");
280
        }
281 39
        $this->query->setSql($sql);
282 39
        $this->query->setBind($bind);
283
284 39
        return $this->query;
285
    }
286
}
287