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 (#214)
by joseph
21:10
created

PingingAndReconnectingConnection::__construct()   A

Complexity

Conditions 1
Paths 1

Size

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