Issues (41)

DatabaseManager.php (6 issues)

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