1
|
|
|
<?php |
2
|
|
|
/* |
3
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
4
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
5
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
6
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
7
|
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
8
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
9
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
10
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
11
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
12
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
13
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
14
|
|
|
* |
15
|
|
|
* This software consists of voluntary contributions made by many individuals |
16
|
|
|
* and is licensed under the MIT license. For more information, see |
17
|
|
|
* <http://www.doctrine-project.org>. |
18
|
|
|
*/ |
19
|
|
|
|
20
|
|
|
namespace Doctrine\DBAL\Driver; |
21
|
|
|
|
22
|
|
|
use PDO; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* PDO implementation of the Connection interface. |
26
|
|
|
* Used by all PDO-based drivers. |
27
|
|
|
* |
28
|
|
|
* @since 2.0 |
29
|
|
|
*/ |
30
|
|
|
class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection |
31
|
|
|
{ |
32
|
|
|
/** |
33
|
|
|
* @var LastInsertId |
34
|
|
|
*/ |
35
|
|
|
private $lastInsertId; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @param string $dsn |
39
|
|
|
* @param string|null $user |
40
|
|
|
* @param string|null $password |
41
|
|
|
* @param array|null $options |
42
|
|
|
* |
43
|
|
|
* @throws PDOException in case of an error. |
44
|
|
|
*/ |
45
|
80 |
|
public function __construct($dsn, $user = null, $password = null, array $options = null) |
46
|
|
|
{ |
47
|
|
|
try { |
48
|
80 |
|
parent::__construct($dsn, $user, $password, $options); |
49
|
79 |
|
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, ['Doctrine\DBAL\Driver\PDOStatement', [$this]]); |
50
|
79 |
|
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); |
51
|
2 |
|
} catch (\PDOException $exception) { |
52
|
2 |
|
throw new PDOException($exception); |
53
|
|
|
} |
54
|
|
|
|
55
|
79 |
|
$this->lastInsertId = new LastInsertId(); |
56
|
79 |
|
} |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* {@inheritdoc} |
60
|
|
|
*/ |
61
|
176 |
|
public function exec($statement) |
62
|
|
|
{ |
63
|
|
|
try { |
64
|
176 |
|
$result = parent::exec($statement); |
65
|
37 |
|
} catch (\PDOException $exception) { |
66
|
37 |
|
throw new PDOException($exception); |
67
|
|
|
} |
68
|
|
|
|
69
|
158 |
|
$this->trackLastInsertId(); |
70
|
|
|
|
71
|
158 |
|
return $result; |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* {@inheritdoc} |
76
|
|
|
*/ |
77
|
|
|
public function getServerVersion() |
78
|
|
|
{ |
79
|
|
|
return PDO::getAttribute(PDO::ATTR_SERVER_VERSION); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* {@inheritdoc} |
84
|
|
|
*/ |
85
|
142 |
|
public function prepare($prepareString, $driverOptions = []) |
86
|
|
|
{ |
87
|
|
|
try { |
88
|
142 |
|
return parent::prepare($prepareString, $driverOptions); |
|
|
|
|
89
|
3 |
|
} catch (\PDOException $exception) { |
90
|
3 |
|
throw new PDOException($exception); |
91
|
|
|
} |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* {@inheritdoc} |
96
|
|
|
*/ |
97
|
172 |
|
public function query() |
98
|
|
|
{ |
99
|
172 |
|
$args = func_get_args(); |
100
|
172 |
|
$argsCount = count($args); |
101
|
|
|
|
102
|
|
|
try { |
103
|
172 |
|
if ($argsCount == 4) { |
104
|
|
|
$stmt = parent::query($args[0], $args[1], $args[2], $args[3]); |
105
|
|
|
|
106
|
|
|
$this->trackLastInsertId(); |
107
|
|
|
|
108
|
|
|
return $stmt; |
|
|
|
|
109
|
|
|
} |
110
|
|
|
|
111
|
172 |
|
if ($argsCount == 3) { |
112
|
|
|
$stmt = parent::query($args[0], $args[1], $args[2]); |
113
|
|
|
|
114
|
|
|
$this->trackLastInsertId(); |
115
|
|
|
|
116
|
|
|
return $stmt; |
|
|
|
|
117
|
|
|
} |
118
|
|
|
|
119
|
172 |
|
if ($argsCount == 2) { |
120
|
|
|
$stmt = parent::query($args[0], $args[1]); |
121
|
|
|
|
122
|
|
|
$this->trackLastInsertId(); |
123
|
|
|
|
124
|
|
|
return $stmt; |
|
|
|
|
125
|
|
|
} |
126
|
|
|
|
127
|
172 |
|
$stmt = parent::query($args[0]); |
128
|
|
|
|
129
|
|
|
|
130
|
166 |
|
$this->trackLastInsertId(); |
131
|
|
|
|
132
|
166 |
|
return $stmt; |
|
|
|
|
133
|
6 |
|
} catch (\PDOException $exception) { |
134
|
6 |
|
throw new PDOException($exception); |
135
|
|
|
} |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* {@inheritdoc} |
140
|
|
|
*/ |
141
|
4 |
|
public function quote($input, $type = \PDO::PARAM_STR) |
142
|
|
|
{ |
143
|
4 |
|
return parent::quote($input, $type); |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
/** |
147
|
|
|
* {@inheritdoc} |
148
|
|
|
*/ |
149
|
33 |
|
public function lastInsertId($name = null) |
150
|
|
|
{ |
151
|
33 |
|
if (null === $name) { |
152
|
33 |
|
return $this->lastInsertId->get(); |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
try { |
156
|
|
|
return $this->fetchLastInsertId($name); |
157
|
|
|
} catch (\PDOException $exception) { |
158
|
|
|
return '0'; |
159
|
|
|
} |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
/** |
163
|
|
|
* {@inheritdoc} |
164
|
|
|
*/ |
165
|
1 |
|
public function requiresQueryForServerVersion() |
166
|
|
|
{ |
167
|
1 |
|
return false; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* Tracks the last insert ID at the current state. |
172
|
|
|
* |
173
|
|
|
* If this PDO driver is not able to fetch the last insert ID for identity columns |
174
|
|
|
* without influencing connection state or transaction state, this is a noop method. |
175
|
|
|
* |
176
|
|
|
* @internal this method is only supposed to be used in DBAL internals |
177
|
|
|
* |
178
|
|
|
* @throws \PDOException |
179
|
|
|
*/ |
180
|
227 |
|
public function trackLastInsertId() : void |
181
|
|
|
{ |
182
|
|
|
// We need to avoid unnecessary exception generation for drivers not supporting this feature, |
183
|
|
|
// by temporarily disabling exception mode. |
184
|
227 |
|
$originalErrorMode = $this->getAttribute(\PDO::ATTR_ERRMODE); |
185
|
|
|
|
186
|
227 |
|
$this->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_SILENT); |
187
|
|
|
|
188
|
|
|
try { |
189
|
227 |
|
$lastInsertId = $this->fetchLastInsertId(null); |
190
|
227 |
|
} finally { |
191
|
|
|
// Reactivate exception mode. |
192
|
227 |
|
$this->setAttribute(\PDO::ATTR_ERRMODE, $originalErrorMode); |
193
|
|
|
} |
194
|
|
|
|
195
|
227 |
|
if (null === $lastInsertId) { |
196
|
|
|
// In case this driver implementation does not support this feature |
197
|
|
|
// or an error occurred while retrieving the last insert ID, there is nothing to track here. |
198
|
|
|
return; |
199
|
|
|
} |
200
|
|
|
|
201
|
227 |
|
$this->lastInsertId->set($lastInsertId); |
202
|
227 |
|
} |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* Fetches the last insert ID generated by this connection. |
206
|
|
|
* |
207
|
|
|
* This method queries the database connection for the last insert ID. |
208
|
|
|
* |
209
|
|
|
* @param string|null $sequenceName The name of the sequence to retrieve the last insert ID from, |
210
|
|
|
* if not given the overall last insert ID is returned. |
211
|
|
|
* |
212
|
|
|
* @return string The last insert ID or '0' in case the last insert ID generated on this connection is unknown. |
213
|
|
|
* |
214
|
|
|
* @throws \PDOException in case of an error. |
215
|
|
|
*/ |
216
|
227 |
|
protected function fetchLastInsertId(?string $sequenceName) : string |
217
|
|
|
{ |
218
|
227 |
|
return parent::lastInsertId($sequenceName); |
|
|
|
|
219
|
|
|
} |
220
|
|
|
} |
221
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.