Completed
Push — master ( ec9260...5e51f5 )
by Marco
42:35 queued 27:36
created

Connector::causedByLostConnection()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 15
nc 1
nop 1
1
<?php
2
namespace Childish\connection;
3
4
use Childish\support\Tools;
5
use PDO;
6
/**
7
 * Connector
8
 *
9
 * @author    Pu ShaoWei <[email protected]>
10
 * @date      2017/12/7
11
 * @package   Childish\connection
12
 * @version   1.0
13
 */
14
class Connector
15
{
16
17
    /**
18
     * The default PDO connection options.
19
     *
20
     * @var array
21
     */
22
    protected $options = [
23
        PDO::ATTR_CASE => PDO::CASE_NATURAL,
24
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
25
        PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
26
        PDO::ATTR_STRINGIFY_FETCHES => false,
27
        PDO::ATTR_EMULATE_PREPARES => false,
28
    ];
29
30
    /**
31
     * Create a new PDO connection.
32
     *
33
     * @param  string  $dsn
34
     * @param  array   $config
35
     * @param  array   $options
36
     * @return \PDO
37
     */
38
    public function createConnection($dsn, array $config, array $options)
39
    {
40
        list($username, $password) = [
41
            $config['username'] ?? null, $config['password'] ?? null,
42
        ];
43
44
        try {
45
            return $this->createPdoConnection(
46
                $dsn, $username, $password, $options
47
            );
48
        } catch (\Exception $e) {
49
            return $this->tryAgainIfCausedByLostConnection(
50
                $e, $dsn, $username, $password, $options
51
            );
52
        }
53
    }
54
55
    /**
56
     * Create a new PDO connection instance.
57
     *
58
     * @param  string  $dsn
59
     * @param  string  $username
60
     * @param  string  $password
61
     * @param  array  $options
62
     * @return \PDO
63
     */
64
    protected function createPdoConnection($dsn, $username, $password, $options)
65
    {
66
        return new PDO($dsn, $username, $password, $options);
67
    }
68
69
    /**
70
     * Determine if the connection is persistent.
71
     *
72
     * @param  array  $options
73
     * @return bool
74
     */
75
    protected function isPersistentConnection($options)
76
    {
77
        return isset($options[PDO::ATTR_PERSISTENT]) &&
78
               $options[PDO::ATTR_PERSISTENT];
79
    }
80
81
    /**
82
     * Handle an exception that occurred during connect execution.
83
     *
84
     * @param  \Exception  $e
85
     * @param  string  $dsn
86
     * @param  string  $username
87
     * @param  string  $password
88
     * @param  array   $options
89
     * @return \PDO
90
     *
91
     * @throws \Exception
92
     */
93
    protected function tryAgainIfCausedByLostConnection(\Exception $e, $dsn, $username, $password, $options)
94
    {
95
        if ($this->causedByLostConnection($e)) {
96
            return $this->createPdoConnection($dsn, $username, $password, $options);
97
        }
98
99
        throw $e;
100
    }
101
102
    /**
103
     * Get the PDO options based on the configuration.
104
     *
105
     * @param  array  $config
106
     * @return array
107
     */
108
    public function getOptions(array $config)
109
    {
110
        $options = $config['options'] ?? [];
111
112
        return array_diff_key($this->options, $options) + $options;
113
    }
114
115
    /**
116
     * Get the default PDO connection options.
117
     *
118
     * @return array
119
     */
120
    public function getDefaultOptions()
121
    {
122
        return $this->options;
123
    }
124
125
    /**
126
     * Set the default PDO connection options.
127
     *
128
     * @param  array  $options
129
     * @return void
130
     */
131
    public function setDefaultOptions(array $options)
132
    {
133
        $this->options = $options;
134
    }
135
    /**
136
     * Determine if the given exception was caused by a lost connection.
137
     *
138
     * @param  \Exception  $e
139
     * @return bool
140
     */
141
    protected function causedByLostConnection(\Exception $e)
142
    {
143
        $message = $e->getMessage();
144
        return Tools::contains($message, [
145
            'server has gone away',
146
            'no connection to the server',
147
            'Lost connection',
148
            'is dead or not enabled',
149
            'Error while sending',
150
            'decryption failed or bad record mac',
151
            'server closed the connection unexpectedly',
152
            'SSL connection has been closed unexpectedly',
153
            'Error writing data to the connection',
154
            'Resource deadlock avoided',
155
            'Transaction() on null',
156
            'child connection forced to terminate due to client_idle_limit',
157
        ]);
158
    }
159
}