Passed
Pull Request — master (#385)
by Wilmer
02:48
created

Connection::queryCacheEnable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
ccs 0
cts 0
cp 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Connection;
6
7
use Closure;
8
use Psr\Log\LoggerAwareTrait;
9
use Psr\Log\LogLevel;
10
use Throwable;
11
use Yiisoft\Cache\Dependency\Dependency;
12
use Yiisoft\Db\Cache\QueryCache;
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\ProfilerAwareTrait;
19
20
/**
21
 * Connection is the base class for all database connection classes.
22
 */
23
abstract class Connection implements ConnectionInterface
24
{
25
    use LoggerAwareTrait;
26
    use ProfilerAwareTrait;
27
28
    protected TransactionInterface|null $transaction = null;
29
    private bool $enableSavepoint = true;
30
    private int $serverRetryInterval = 600;
0 ignored issues
show
introduced by
The private property $serverRetryInterval is not used, and could be removed.
Loading history...
31
    private string $tablePrefix = '';
32
33
    public function __construct(private QueryCache $queryCache)
34
    {
35
    }
36
37
    public function beginTransaction(string $isolationLevel = null): TransactionInterface
38
    {
39
        $this->open();
40
        $this->transaction = $this->getTransaction();
41
42
        if ($this->transaction === null) {
43
            $this->transaction = $this->createTransaction();
44
        }
45
46
        if ($this->logger !== null) {
47
            $this->transaction->setLogger($this->logger);
48
        }
49
50
        $this->transaction->begin($isolationLevel);
51
52
        return $this->transaction;
53
    }
54
55
    public function cache(Closure $closure, int $duration = null, Dependency $dependency = null): mixed
56
    {
57
        $this->queryCache->setInfo(
58
            [$duration ?? $this->queryCache->getDuration(), $dependency]
59
        );
60
        /** @var mixed */
61
        $result = $closure($this);
62
        $this->queryCache->removeLastInfo();
63
64
        return $result;
65
    }
66
67
    public function createBatchQueryResult(QueryInterface $query, bool $each = false): BatchQueryResultInterface
68
    {
69
        return new BatchQueryResult($query, $each);
70
    }
71
72
    public function getTablePrefix(): string
73
    {
74
        return $this->tablePrefix;
75
    }
76
77
    public function getTableSchema(string $name, bool $refresh = false): TableSchemaInterface|null
78
    {
79
        return $this->getSchema()->getTableSchema($name, $refresh);
80
    }
81
82
    public function getTransaction(): TransactionInterface|null
83
    {
84
        return $this->transaction && $this->transaction->isActive() ? $this->transaction : null;
85
    }
86
87
    public function isSavepointEnabled(): bool
88
    {
89
        return $this->enableSavepoint;
90
    }
91
92
    public function noCache(Closure $closure): mixed
93
    {
94
        $queryCache = $this->queryCache;
95
        $queryCache->setInfo(false);
96
        /** @var mixed */
97
        $result = $closure($this);
98
        $queryCache->removeLastInfo();
99
100
        return $result;
101
    }
102
103
    public function notProfiler(): void
104
    {
105
        $this->profiler = null;
106
    }
107
108
    public function queryCacheEnable(bool $value): void
109
    {
110
        $this->queryCache->setEnable($value);
111
    }
112
113
    public function setEnableSavepoint(bool $value): void
114
    {
115
        $this->enableSavepoint = $value;
116
    }
117
118
    public function setTablePrefix(string $value): void
119
    {
120
        $this->tablePrefix = $value;
121
    }
122
123
    public function transaction(Closure $closure, string $isolationLevel = null): mixed
124
    {
125
        $transaction = $this->beginTransaction($isolationLevel);
126
127
        $level = $transaction->getLevel();
128
129
        try {
130
            /** @var mixed */
131
            $result = $closure($this);
132
133
            if ($transaction->isActive() && $transaction->getLevel() === $level) {
134
                $transaction->commit();
135
            }
136
        } catch (Throwable $e) {
137
            $this->rollbackTransactionOnLevel($transaction, $level);
138
139
            throw $e;
140
        }
141
142
        return $result;
143
    }
144
145
    /**
146
     * Rolls back given {@see TransactionInterface} object if it's still active and level match. In some cases rollback
147
     * can fail, so this method is fail-safe. Exceptions thrown from rollback will be caught and just logged with
148
     * {@see logger->log()}.
149
     *
150
     * @param TransactionInterface $transaction TransactionInterface object given from {@see beginTransaction()}.
151
     * @param int $level TransactionInterface level just after {@see beginTransaction()} call.
152
     */
153
    private function rollbackTransactionOnLevel(TransactionInterface $transaction, int $level): void
154
    {
155
        if ($transaction->isActive() && $transaction->getLevel() === $level) {
156
            /**
157
             * {@see https://github.com/yiisoft/yii2/pull/13347}
158
             */
159
            try {
160
                $transaction->rollBack();
161
            } catch (\Exception $e) {
162
                $this->logger?->log(LogLevel::ERROR, (string) $e, [__METHOD__]);
163
                /** hide this exception to be able to continue throwing original exception outside */
164
            }
165
        }
166
    }
167
}
168