|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Pyjac\ORM; |
|
4
|
|
|
|
|
5
|
|
|
use PDO; |
|
6
|
|
|
use Pyjac\ORM\DatabaseConnectionStringFactoryInterface; |
|
7
|
|
|
use Pyjac\ORM\DatabaseConnectionStringFactory; |
|
8
|
|
|
|
|
9
|
|
View Code Duplication |
class DatabaseConnection |
|
|
|
|
|
|
10
|
|
|
{ |
|
11
|
|
|
/** |
|
12
|
|
|
* The instance of this class. |
|
13
|
|
|
* |
|
14
|
|
|
* @var Pyjac\ORM\DatabaseConnection. |
|
15
|
|
|
*/ |
|
16
|
|
|
private static $instance; |
|
17
|
|
|
|
|
18
|
|
|
/** |
|
19
|
|
|
* The PDO database connection in use. |
|
20
|
|
|
* |
|
21
|
|
|
* @var \PDO |
|
22
|
|
|
*/ |
|
23
|
|
|
public $databaseConnection; |
|
24
|
|
|
|
|
25
|
|
|
/** |
|
26
|
|
|
* The default PDO connection options. |
|
27
|
|
|
* |
|
28
|
|
|
* @var array |
|
29
|
|
|
*/ |
|
30
|
|
|
protected $options = [ |
|
31
|
|
|
PDO::ATTR_CASE => PDO::CASE_NATURAL, |
|
32
|
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, |
|
33
|
|
|
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, |
|
34
|
|
|
PDO::ATTR_STRINGIFY_FETCHES => false, |
|
35
|
|
|
PDO::ATTR_EMULATE_PREPARES => false, |
|
36
|
|
|
]; |
|
37
|
|
|
|
|
38
|
|
|
/** |
|
39
|
|
|
* Create a new Database Connection. |
|
40
|
|
|
* |
|
41
|
|
|
* @param DatabaseConnectionStringFactoryInterface $dbConnStringFactory |
|
42
|
|
|
*/ |
|
43
|
|
|
private function __construct(DatabaseConnectionStringFactoryInterface $dbConnStringFactory) |
|
44
|
|
|
{ |
|
45
|
|
|
//Read config file |
|
46
|
|
|
$this->config = parse_ini_file('config.ini'); |
|
|
|
|
|
|
47
|
|
|
$dsn = $dbConnStringFactory->createDatabaseSourceString($this->config); |
|
48
|
|
|
$this->databaseConnection = $this->createConnection($dsn, $this->options); |
|
49
|
|
|
} |
|
50
|
|
|
|
|
51
|
|
|
/** |
|
52
|
|
|
* Get the instance of the class. |
|
53
|
|
|
* |
|
54
|
|
|
* @return Pyjac\ORM\DatabaseConnection |
|
55
|
|
|
*/ |
|
56
|
|
|
public static function getInstance() |
|
57
|
|
|
{ |
|
58
|
|
|
if (self::$instance === null) { |
|
59
|
|
|
self::$instance = new self(new DatabaseConnectionStringFactory); |
|
60
|
|
|
} |
|
61
|
|
|
return self::$instance; |
|
62
|
|
|
} |
|
63
|
|
|
|
|
64
|
|
|
|
|
65
|
|
|
/** |
|
66
|
|
|
* Create a new PDO connection. |
|
67
|
|
|
* |
|
68
|
|
|
* @param string $dsn |
|
69
|
|
|
* @param array $config |
|
70
|
|
|
* @return \PDO |
|
71
|
|
|
*/ |
|
72
|
|
|
public function createConnection($dsn, array $config) |
|
|
|
|
|
|
73
|
|
|
{ |
|
74
|
|
|
$username = $this->config['USERNAME']; |
|
75
|
|
|
|
|
76
|
|
|
$password = $this->config['PASSWORD']; |
|
77
|
|
|
|
|
78
|
|
|
|
|
79
|
|
|
try { |
|
80
|
|
|
$pdo = new PDO($dsn, $username, $password, $this->options); |
|
81
|
|
|
} catch (\Exception $e) { |
|
82
|
|
|
$pdo = $this->tryAgainIfCausedByLostConnection( |
|
83
|
|
|
$e, $dsn, $username, $password, $options |
|
|
|
|
|
|
84
|
|
|
); |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
|
|
return $pdo; |
|
88
|
|
|
} |
|
89
|
|
|
|
|
90
|
|
|
/** |
|
91
|
|
|
* Get the default PDO connection options. |
|
92
|
|
|
* |
|
93
|
|
|
* @return array |
|
94
|
|
|
*/ |
|
95
|
|
|
public function getDefaultOptions() |
|
96
|
|
|
{ |
|
97
|
|
|
return $this->options; |
|
98
|
|
|
} |
|
99
|
|
|
|
|
100
|
|
|
/** |
|
101
|
|
|
* Set the default PDO connection options. |
|
102
|
|
|
* |
|
103
|
|
|
* @param array $options |
|
104
|
|
|
* @return void |
|
105
|
|
|
*/ |
|
106
|
|
|
public function setDefaultOptions(array $options) |
|
107
|
|
|
{ |
|
108
|
|
|
$this->options = $options; |
|
109
|
|
|
} |
|
110
|
|
|
|
|
111
|
|
|
/** |
|
112
|
|
|
* Handle a exception that occurred during connect execution. |
|
113
|
|
|
* |
|
114
|
|
|
* @param \Exception $e |
|
115
|
|
|
* @param string $dsn |
|
116
|
|
|
* @param string $username |
|
117
|
|
|
* @param string $password |
|
118
|
|
|
* @param array $options |
|
119
|
|
|
* @return \PDO |
|
120
|
|
|
* |
|
121
|
|
|
* @throws \Exception |
|
122
|
|
|
*/ |
|
123
|
|
|
protected function tryAgainIfCausedByLostConnection(Exception $e, $dsn, $username, $password, $options) |
|
124
|
|
|
{ |
|
125
|
|
|
if ($this->causedByLostConnection($e)) { |
|
126
|
|
|
return new PDO($dsn, $username, $password, $options); |
|
127
|
|
|
} |
|
128
|
|
|
|
|
129
|
|
|
throw $e; |
|
130
|
|
|
} |
|
131
|
|
|
|
|
132
|
|
|
/** |
|
133
|
|
|
* Determine if the given exception was caused by a lost connection. |
|
134
|
|
|
* |
|
135
|
|
|
* @param \Exception $e |
|
136
|
|
|
* @return bool |
|
137
|
|
|
*/ |
|
138
|
|
|
protected function causedByLostConnection(Exception $e) |
|
139
|
|
|
{ |
|
140
|
|
|
$message = $e->getMessage(); |
|
141
|
|
|
|
|
142
|
|
|
return Helpers::contains($message, [ |
|
143
|
|
|
'server has gone away', |
|
144
|
|
|
'no connection to the server', |
|
145
|
|
|
'Lost connection', |
|
146
|
|
|
'is dead or not enabled', |
|
147
|
|
|
'Error while sending', |
|
148
|
|
|
'decryption failed or bad record mac', |
|
149
|
|
|
'SSL connection has been closed unexpectedly', |
|
150
|
|
|
'Deadlock found when trying to get lock', |
|
151
|
|
|
]); |
|
152
|
|
|
} |
|
153
|
|
|
} |
|
154
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.