Passed
Pull Request — master (#356)
by Wilmer
02:11
created

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