GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#161)
by joseph
15:40
created

PingingAndReconnectingConnection::query()   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
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 3
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace EdmondsCommerce\DoctrineStaticMeta\EntityManager\RetryConnection;
4
5
use Doctrine\Common\EventManager;
6
use Doctrine\DBAL\Cache\QueryCacheProfile;
7
use Doctrine\DBAL\Configuration;
8
use Doctrine\DBAL\Connection;
9
use Doctrine\DBAL\DBALException;
10
use Doctrine\DBAL\Driver;
11
12
/**
13
 * This is a connection wrapper that enables some retry functionality should the connection to the DB be lost for any
14
 * reason. Especially useful on long running processes
15
 */
16
class PingingAndReconnectingConnection extends Connection
17
{
18
    /**
19
     * How many seconds between pings
20
     *
21
     * @var float
22
     */
23
    private const PING_INTERVAL_SECONDS = 1.0;
24
25
    /** @var \ReflectionProperty */
26
    private $selfReflectionNestingLevelProperty;
27
28
    /** @var float */
29
    private $pingTimer = 0;
30
31
    /**
32
     * RetryConnection constructor.
33
     *
34
     * @param array              $params
35
     * @param Driver             $driver
36
     * @param Configuration|null $config
37
     * @param EventManager|null  $eventManager
38
     *
39
     * @throws \Doctrine\DBAL\DBALException
40
     * @SuppressWarnings(PHPMD.StaticAccess)
41
     */
42
    public function __construct(
43
        array $params,
44
        Driver $driver,
45
        ?Configuration $config = null,
46
        ?EventManager $eventManager = null
47
    ) {
48
        parent::__construct($params, $driver, $config, $eventManager);
49
    }
50
51
    public function executeUpdate($query, array $params = [], array $types = [])
52
    {
53
        $args = [$query, $params, $types];
54
55
        return $this->pingBeforeMethodCall(__FUNCTION__, $args);
56
    }
57
58
    private function pingBeforeMethodCall(string $function, array $args)
59
    {
60
        $this->pingAndReconnectOnFailure();
61
62
        return parent::$function(...$args);
63
    }
64
65
    public function pingAndReconnectOnFailure(): void
66
    {
67
        if (microtime(true) < ($this->pingTimer + self::PING_INTERVAL_SECONDS)) {
68
            return;
69
        }
70
        $this->pingTimer = microtime(true);
71
        if (false === $this->ping()) {
72
            $this->close();
73
            $this->resetTransactionNestingLevel();
74
            parent::connect();
75
        }
76
    }
77
78
    /**
79
     * Overriding the ping method so we explicitly call the raw unwrapped methods as required, otherwise we go into
80
     * infinite loop
81
     *
82
     * @return bool
83
     */
84
    public function ping(): bool
85
    {
86
        parent::connect();
87
88
        if ($this->_conn instanceof Driver\PingableConnection) {
89
            return $this->_conn->ping();
90
        }
91
92
        try {
93
            parent::query($this->getDatabasePlatform()->getDummySelectSQL());
94
95
            return true;
96
        } catch (DBALException $e) {
97
            return false;
98
        }
99
    }
100
101
102
    /**
103
     * This is required because beginTransaction increment _transactionNestingLevel
104
     * before the real query is executed, and results incremented also on gone away error.
105
     * This should be safe for a new established connection.
106
     */
107
    private function resetTransactionNestingLevel(): void
108
    {
109
        if (!$this->selfReflectionNestingLevelProperty instanceof \ReflectionProperty) {
0 ignored issues
show
introduced by
$this->selfReflectionNestingLevelProperty is always a sub-type of ReflectionProperty.
Loading history...
110
            $reflection                               = new \ReflectionClass(Connection::class);
111
            $this->selfReflectionNestingLevelProperty = $reflection->getProperty('_transactionNestingLevel');
112
            $this->selfReflectionNestingLevelProperty->setAccessible(true);
113
        }
114
115
        $this->selfReflectionNestingLevelProperty->setValue($this, 0);
116
    }
117
118
    public function query(...$args)
119
    {
120
        return $this->pingBeforeMethodCall(__FUNCTION__, $args);
121
    }
122
123
    public function executeQuery($query, array $params = [], $types = [], QueryCacheProfile $qcp = null)
124
    {
125
        $args = [$query, $params, $types, $qcp];
126
127
        return $this->pingBeforeMethodCall(__FUNCTION__, $args);
128
    }
129
130
    public function beginTransaction()
131
    {
132
        $this->pingBeforeMethodCall(__FUNCTION__, []);
133
    }
134
135
    /**
136
     * @param string $sql
137
     *
138
     * @return Statement
139
     */
140
    public function prepare($sql): Statement
141
    {
142
        return $this->prepareWrapped($sql);
143
    }
144
145
    /**
146
     * returns a reconnect-wrapper for Statements.
147
     *
148
     * @param string $sql
149
     *
150
     * @return Statement
151
     */
152
    protected function prepareWrapped(string $sql): Statement
153
    {
154
        $this->pingAndReconnectOnFailure();
155
156
        return new Statement($sql, $this/*, $this->shouldConnectionByRetried*/);
157
    }
158
159
    /**
160
     * do not use, only used by Statement-class
161
     * needs to be public for access from the Statement-class.
162
     *
163
     * @internal
164
     *
165
     * @param string $sql
166
     *
167
     * @return Driver\Statement
168
     * @throws \Doctrine\DBAL\DBALException
169
     */
170
    public function prepareUnwrapped(string $sql): Driver\Statement
171
    {
172
        // returns the actual statement
173
        return parent::prepare($sql);
174
    }
175
}
176