Passed
Pull Request — master (#466)
by Def
02:13
created

AbstractConnection::notProfiler()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Connection;
6
7
use Closure;
8
use Exception;
9
use Psr\Log\LoggerAwareInterface;
10
use Psr\Log\LoggerAwareTrait;
11
use Psr\Log\LogLevel;
12
use Throwable;
13
use Yiisoft\Db\Query\BatchQueryResult;
14
use Yiisoft\Db\Query\BatchQueryResultInterface;
15
use Yiisoft\Db\Query\QueryInterface;
16
use Yiisoft\Db\Schema\TableSchemaInterface;
17
use Yiisoft\Db\Transaction\TransactionInterface;
18
use Yiisoft\Profiler\ProfilerAwareInterface;
19
use Yiisoft\Profiler\ProfilerAwareTrait;
20
21
/**
22
 * The AbstractConnection class represents a connection to a database. It provides methods for interacting with the
23
 * database, such as executing SQL queries and performing data manipulation.
24
 */
25
abstract class AbstractConnection implements ConnectionInterface, LoggerAwareInterface, ProfilerAwareInterface
26
{
27
    use LoggerAwareTrait;
28
    use ProfilerAwareTrait;
29
30
    protected TransactionInterface|null $transaction = null;
31
    private bool $enableSavepoint = true;
32
    private int $serverRetryInterval = 600;
0 ignored issues
show
introduced by
The private property $serverRetryInterval is not used, and could be removed.
Loading history...
33
    private string $tablePrefix = '';
34
35
    public function beginTransaction(string $isolationLevel = null): TransactionInterface
36
    {
37
        $this->open();
38
        $this->transaction = $this->getTransaction();
39
40
        if ($this->transaction === null) {
41
            $this->transaction = $this->createTransaction();
42
        }
43
44
        if ($this->logger !== null) {
45
            $this->transaction->setLogger($this->logger);
46
        }
47
48
        $this->transaction->begin($isolationLevel);
49
50
        return $this->transaction;
51
    }
52
53
    public function createBatchQueryResult(QueryInterface $query, bool $each = false): BatchQueryResultInterface
54
    {
55
        return new BatchQueryResult($query, $each);
56
    }
57
58
    public function getTablePrefix(): string
59
    {
60
        return $this->tablePrefix;
61
    }
62
63
    public function getTableSchema(string $name, bool $refresh = false): TableSchemaInterface|null
64
    {
65
        return $this->getSchema()->getTableSchema($name, $refresh);
66
    }
67
68
    public function getTransaction(): TransactionInterface|null
69
    {
70
        return $this->transaction && $this->transaction->isActive() ? $this->transaction : null;
71
    }
72
73
    public function isSavepointEnabled(): bool
74
    {
75
        return $this->enableSavepoint;
76
    }
77
78
    public function notProfiler(): void
79
    {
80
        $this->profiler = null;
81
    }
82
83
    public function setEnableSavepoint(bool $value): void
84
    {
85
        $this->enableSavepoint = $value;
86
    }
87
88
    public function setTablePrefix(string $value): void
89
    {
90
        $this->tablePrefix = $value;
91
    }
92
93
    public function transaction(Closure $closure, string $isolationLevel = null): mixed
94
    {
95
        $transaction = $this->beginTransaction($isolationLevel);
96
        $level = $transaction->getLevel();
97
98
        try {
99
            /** @psalm-var mixed $result */
100
            $result = $closure($this);
101
102
            if ($transaction->isActive() && $transaction->getLevel() === $level) {
103
                $transaction->commit();
104
            }
105
        } catch (Throwable $e) {
106
            $this->rollbackTransactionOnLevel($transaction, $level);
107
108
            throw $e;
109
        }
110
111
        return $result;
112
    }
113
114
    /**
115
     * Rolls back given {@see TransactionInterface} object if it's still active and level match. In some cases rollback
116
     * can fail, so this method is fail-safe. Exceptions thrown from rollback will be caught and just logged with
117
     * {@see logger->log()}.
118
     *
119
     * @param TransactionInterface $transaction TransactionInterface object given from {@see beginTransaction()}.
120
     * @param int $level TransactionInterface level just after {@see beginTransaction()} call.
121
     */
122
    private function rollbackTransactionOnLevel(TransactionInterface $transaction, int $level): void
123
    {
124
        if ($transaction->isActive() && $transaction->getLevel() === $level) {
125
            /**
126
             * @link https://github.com/yiisoft/yii2/pull/13347
127
             */
128
            try {
129
                $transaction->rollBack();
130
            } catch (Exception $e) {
131
                $this->logger?->log(LogLevel::ERROR, (string) $e, [__METHOD__]);
132
                /** hide this exception to be able to continue throwing original exception outside */
133
            }
134
        }
135
    }
136
}
137