Test Failed
Pull Request — master (#2765)
by Marco
04:16
created

PDOConnection::exec()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 12
c 0
b 0
f 0
ccs 6
cts 6
cp 1
rs 9.4285
cc 2
eloc 7
nc 2
nop 1
crap 2
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);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return parent::prepare($...tring, $driverOptions); (PDOStatement) is incompatible with the return type declared by the interface Doctrine\DBAL\Driver\Connection::prepare of type Doctrine\DBAL\Driver\Statement.

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:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
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;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $stmt; (PDOStatement) is incompatible with the return type declared by the interface Doctrine\DBAL\Driver\Connection::query of type Doctrine\DBAL\Driver\Statement.

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:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
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;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $stmt; (PDOStatement) is incompatible with the return type declared by the interface Doctrine\DBAL\Driver\Connection::query of type Doctrine\DBAL\Driver\Statement.

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:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
117
            }
118
119 172
            if ($argsCount == 2) {
120
                $stmt = parent::query($args[0], $args[1]);
121
122
                $this->trackLastInsertId();
123
124
                return $stmt;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $stmt; (PDOStatement) is incompatible with the return type declared by the interface Doctrine\DBAL\Driver\Connection::query of type Doctrine\DBAL\Driver\Statement.

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:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
125
            }
126
127 172
            $stmt = parent::query($args[0]);
128
129
130 166
            $this->trackLastInsertId();
131
132 166
            return $stmt;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $stmt; (PDOStatement) is incompatible with the return type declared by the interface Doctrine\DBAL\Driver\Connection::query of type Doctrine\DBAL\Driver\Statement.

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:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
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);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (lastInsertId() instead of fetchLastInsertId()). Are you sure this is correct? If so, you might want to change this to $this->lastInsertId().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
219
    }
220
}
221