Failed Conditions
Pull Request — master (#3074)
by Sergei
15:08
created

PDOConnection::lastInsertId()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 4.125

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 3
cts 6
cp 0.5
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 1
crap 4.125
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 Doctrine\DBAL\ParameterType;
23
use PDO;
24
use function func_get_args;
25
26
/**
27
 * PDO implementation of the Connection interface.
28
 * Used by all PDO-based drivers.
29
 *
30
 * @since 2.0
31
 */
32
class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection
33
{
34
    /**
35
     * @var LastInsertId
36
     */
37
    private $lastInsertId;
38
39
    /**
40
     * @param string      $dsn
41
     * @param string|null $user
42
     * @param string|null $password
43
     * @param array|null  $options
44
     *
45
     * @throws PDOException in case of an error.
46
     */
47 80
    public function __construct($dsn, $user = null, $password = null, array $options = null)
48
    {
49
        try {
50 80
            parent::__construct($dsn, $user, $password, $options);
51 79
            $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, ['Doctrine\DBAL\Driver\PDOStatement', [$this]]);
52 79
            $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
53 2
        } catch (\PDOException $exception) {
54 2
            throw new PDOException($exception);
55
        }
56
57 79
        $this->lastInsertId = new LastInsertId();
58 79
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63 189
    public function exec($statement)
64
    {
65
        try {
66 189
            $result = parent::exec($statement);
67 77
        } catch (\PDOException $exception) {
68 77
            throw new PDOException($exception);
69
        }
70
71 161
        $this->trackLastInsertId();
72
73 161
        return $result;
74
    }
75
76
    /**
77
     * {@inheritdoc}
78
     */
79
    public function getServerVersion()
80
    {
81
        return PDO::getAttribute(PDO::ATTR_SERVER_VERSION);
0 ignored issues
show
Bug Best Practice introduced by
The method PDO::getAttribute() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

81
        return PDO::/** @scrutinizer ignore-call */ getAttribute(PDO::ATTR_SERVER_VERSION);
Loading history...
82
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87 143
    public function prepare($prepareString, $driverOptions = [])
88
    {
89
        try {
90 143
            return parent::prepare($prepareString, $driverOptions);
0 ignored issues
show
Bug Best Practice introduced by
The expression return parent::prepare($...String, $driverOptions) returns the type PDOStatement which is incompatible with the return type mandated by Doctrine\DBAL\Driver\Connection::prepare() of Doctrine\DBAL\Driver\Statement.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
91 3
        } catch (\PDOException $exception) {
92 3
            throw new PDOException($exception);
93
        }
94
    }
95
96
    /**
97
     * {@inheritdoc}
98
     */
99 185
    public function query()
100
    {
101
        try {
102 185
            $stmt = parent::query(...func_get_args());
0 ignored issues
show
Bug introduced by
func_get_args() is expanded, but the parameter $statement of PDO::query() does not expect variable arguments. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

102
            $stmt = parent::query(/** @scrutinizer ignore-type */ ...func_get_args());
Loading history...
103
104 179
            $this->trackLastInsertId();
105
106 179
            return $stmt;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $stmt returns the type PDOStatement which is incompatible with the return type mandated by Doctrine\DBAL\Driver\Connection::query() of Doctrine\DBAL\Driver\Statement.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
107 6
        } catch (\PDOException $exception) {
108 6
            throw new PDOException($exception);
109
        }
110
    }
111
112
    /**
113
     * {@inheritdoc}
114
     */
115 4
    public function quote($input, $type = ParameterType::STRING)
116
    {
117 4
        return parent::quote($input, $type);
118
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123 33
    public function lastInsertId($name = null)
124
    {
125 33
        if (null === $name) {
126 33
            return $this->lastInsertId->get();
127
        }
128
129
        try {
130
            return $this->fetchLastInsertId($name);
131
        } catch (\PDOException $exception) {
132
            return '0';
133
        }
134
    }
135
136
    /**
137
     * {@inheritdoc}
138
     */
139 1
    public function requiresQueryForServerVersion()
140
    {
141 1
        return false;
142
    }
143
144
    /**
145
     * Tracks the last insert ID at the current state.
146
     *
147
     * If this PDO driver is not able to fetch the last insert ID for identity columns
148
     * without influencing connection state or transaction state, this is a noop method.
149
     *
150
     * @internal this method is only supposed to be used in DBAL internals
151
     *
152
     * @throws \PDOException
153
     */
154 268
    public function trackLastInsertId() : void
155
    {
156
        // We need to avoid unnecessary exception generation for drivers not supporting this feature,
157
        // by temporarily disabling exception mode.
158 268
        $originalErrorMode = $this->getAttribute(\PDO::ATTR_ERRMODE);
159
160 268
        $this->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_SILENT);
161
162
        try {
163 268
            $lastInsertId = $this->fetchLastInsertId(null);
164 268
        } finally {
165
            // Reactivate exception mode.
166 268
            $this->setAttribute(\PDO::ATTR_ERRMODE, $originalErrorMode);
167
        }
168
169 268
        if (null === $lastInsertId) {
0 ignored issues
show
introduced by
The condition null === $lastInsertId is always false.
Loading history...
170
            // In case this driver implementation does not support this feature
171
            // or an error occurred while retrieving the last insert ID, there is nothing to track here.
172
            return;
173
        }
174
175 268
        $this->lastInsertId->register($lastInsertId);
176 268
    }
177
178
    /**
179
     * Fetches the last insert ID generated by this connection.
180
     *
181
     * This method queries the database connection for the last insert ID.
182
     *
183
     * @param string|null $sequenceName The name of the sequence to retrieve the last insert ID from,
184
     *                                  if not given the overall last insert ID is returned.
185
     *
186
     * @return string The last insert ID or '0' in case the last insert ID generated on this connection is unknown.
187
     *
188
     * @throws \PDOException in case of an error.
189
     */
190 268
    protected function fetchLastInsertId(?string $sequenceName) : string
191
    {
192 268
        return parent::lastInsertId($sequenceName);
193
    }
194
}
195