Completed
Push — dev-0.1.x ( cbb4c7...945d1b )
by Josué
07:31
created

PdoOci8   C

Complexity

Total Complexity 57

Size/Duplication

Total Lines 521
Duplicated Lines 4.22 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 85.71%

Importance

Changes 4
Bugs 1 Features 1
Metric Value
wmc 57
c 4
b 1
f 1
lcom 1
cbo 6
dl 22
loc 521
ccs 204
cts 238
cp 0.8571
rs 6.433

25 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 5 45 5
A getAutocommitMode() 0 4 1
A getCharset() 0 6 1
A getConnection() 0 4 1
B getOracleConnection() 0 31 3
A getConnectionString() 0 10 1
B getConnectionStringItems() 0 34 6
A getDsnRegex() 0 12 1
A beginTransaction() 0 11 2
A commit() 0 12 2
A errorCode() 13 13 2
A errorInfo() 0 19 2
A exec() 0 11 2
A getStatementType() 0 11 1
A getAttribute() 0 8 2
A getAvailableDrivers() 0 4 1
A inTransaction() 0 4 1
A lastInsertId() 0 7 1
B prepare() 0 24 5
B query() 0 24 5
B quote() 0 22 4
A restoreAutocommitMode() 0 5 1
A rollback() 0 16 3
A setAutocommitMode() 0 4 1
A setAttribute() 4 20 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like PdoOci8 often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use PdoOci8, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Jpina\PdoOci8;
4
5
use Jpina\Oci8\Oci8Connection;
6
use Jpina\Oci8\Oci8ConnectionInterface;
7
use Jpina\Oci8\Oci8Exception;
8
use Jpina\Oci8\Oci8PersistentConnection;
9
use Jpina\Oci8\Oci8StatementInterface;
10
11
/**
12
 * Custom PDO_OCI implementation via OCI8 driver
13
 *
14
 * @see http://php.net/manual/en/class.pdo.php
15
 */
16
class PdoOci8 extends \PDO
17
{
18
    const OCI_ATTR_SESSION_MODE = 8000;
19
20
    const OCI_ATTR_RETURN_LOBS = 8001;
21
22
    /**
23
     * @var Oci8ConnectionInterface
24
     */
25
    protected $connection;
26
27
    /**
28
     * @var bool
29
     */
30
    private $autoCommitMode = false;
31
32
    /** @var bool */
33
    private $isTransactionStarted = false;
34
35
    /**
36
     * @var array
37
     */
38
    protected $options = array();
39
40
    // TODO Receive Oci8ConnectionInterface?
41 14
    public function __construct($dsn, $username = '', $password = '', $options = array())
42
    {
43 14
        $this->options = array(
44 14
            \PDO::ATTR_AUTOCOMMIT         => true,
45 14
            \PDO::ATTR_CASE               => \PDO::CASE_NATURAL,
46 14
            \PDO::ATTR_CLIENT_VERSION     => '',
47 14
            \PDO::ATTR_CONNECTION_STATUS  => '',
48 14
            \PDO::ATTR_DRIVER_NAME        => 'oci',
49 14
            \PDO::ATTR_ERRMODE            => \PDO::ERRMODE_SILENT,
50 14
            \PDO::ATTR_ORACLE_NULLS       => \PDO::NULL_NATURAL,
51 14
            \PDO::ATTR_PERSISTENT         => false,
52 14
            \PDO::ATTR_PREFETCH           => 100,
53 14
            \PDO::ATTR_SERVER_INFO        => '',
54 14
            \PDO::ATTR_SERVER_VERSION     => '',
55 14
            \PDO::ATTR_TIMEOUT            => 600,
56 14
            \PDO::ATTR_STRINGIFY_FETCHES  => false,
57 14
            \PDO::ATTR_STATEMENT_CLASS    => null,
58 14
            \PDO::ATTR_EMULATE_PREPARES   => false,
59 14
            \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_BOTH,
60 14
            static::OCI_ATTR_SESSION_MODE => OCI_DEFAULT,
61 14
            static::OCI_ATTR_RETURN_LOBS  => false,
62
        );
63
64 14 View Code Duplication
        foreach ($options as $option => $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
65 4
            if (array_key_exists($option, $this->options)) {
66 4
                $this->options[$option] = $value;
67 4
            }
68 14
        }
69
70 14
        foreach ($options as $attribute => $value) {
71 4
            $this->setAttribute($attribute, $value);
72 14
        }
73
74 14
        $connection = $this->getOracleConnection($dsn, $username, $password);
75 12
        $this->setAttribute(\PDO::ATTR_CLIENT_VERSION, $connection->getClientVersion());
76 12
        $this->setAttribute(\PDO::ATTR_SERVER_VERSION, $connection->getServerVersion());
77
78 12
        $autocommitMode = $this->getAttribute(\PDO::ATTR_AUTOCOMMIT);
79 12
        $this->setAutocommitMode($autocommitMode);
80 12
        if ($this->getAttribute(\PDO::ATTR_AUTOCOMMIT) === false) {
81 1
            $this->beginTransaction();
82 1
        }
83
84 12
        $this->connection = $connection;
85 12
    }
86
87
    /**
88
     * @return bool
89
     */
90 3
    protected function getAutocommitMode()
91
    {
92 3
        return $this->autoCommitMode;
93
    }
94
95
    /**
96
     * @param string $dsn
97
     * @return string
98
     */
99 13
    protected function getCharset($dsn)
100
    {
101 13
        $connectionStringItems = $this->getConnectionStringItems($dsn);
102
103 13
        return $connectionStringItems['charset'];
104
    }
105
106
    /**
107
     * @return Oci8ConnectionInterface
108
     */
109 43
    protected function getConnection()
110
    {
111 43
        return $this->connection;
112
    }
113
114
    /**
115
     * @param string $dsn
116
     * @param string $username
117
     * @param string $password
118
     * @return Oci8ConnectionInterface
119
     */
120 14
    protected function getOracleConnection($dsn, $username = null, $password = null)
121
    {
122 14
        $connectionString = $this->getConnectionString($dsn);
123 13
        $charset = $this->getCharset($dsn);
124 13
        $sessionMode = $this->getAttribute(static::OCI_ATTR_SESSION_MODE);
125
126 13
        $connection = null;
127
        try {
128 13
            if ($this->getAttribute(\PDO::ATTR_PERSISTENT)) {
129 1
                $connection = new Oci8PersistentConnection(
130 1
                    $username,
131 1
                    $password,
132 1
                    $connectionString,
133 1
                    $charset,
134
                    $sessionMode
135 1
                );
136 1
            } else {
137 12
                $connection = new Oci8Connection(
138 12
                    $username,
139 12
                    $password,
140 12
                    $connectionString,
141 12
                    $charset,
142
                    $sessionMode
143 12
                );
144
            }
145 13
        } catch (Oci8Exception $ex) {
146 1
            throw new PdoOci8Exception($ex->getMessage(), $ex->getCode(), $ex);
147
        }
148
149 12
        return $connection;
150
    }
151
152
    /**
153
     * @param string $dsn
154
     * @return string
155
     */
156 14
    protected function getConnectionString($dsn)
157
    {
158 14
        $connectionStringItems = $this->getConnectionStringItems($dsn);
159 13
        $hostname = $connectionStringItems['hostname'];
160 13
        $port = $connectionStringItems['port'];
161 13
        $database = $connectionStringItems['database'];
162 13
        $connectionString = "//{$hostname}:{$port}/{$database}";
163
164 13
        return $connectionString;
165
    }
166
167
    /**
168
     * @param string $dsn
169
     * @return array
170
     */
171 14
    protected function getConnectionStringItems($dsn)
172
    {
173 14
        $dsnRegex = $this->getDsnRegex();
174 14
        $matches = array();
175 14
        if (preg_match("/^{$dsnRegex}$/i", $dsn, $matches) !== 1) {
176 1
            throw new PdoOci8Exception('Invalid DSN');
177
        }
178
179
        // TODO Remove the variables below
180 13
        $hostname = 'localhost';
181 13
        $port     = 1521;
182 13
        $database = null;
0 ignored issues
show
Unused Code introduced by
$database is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
183 13
        $charset  = 'AL32UTF8';
184
185 13
        switch (count($matches)) {
186 13
            case 16:
187 11
                $charset  = empty($matches[15]) ? $charset : $matches[15];
188
                // fall through next case to get the rest of the variables
189 13
            case 14:
190 13
                $port     = empty($matches[12]) ? $port : (int)$matches[12];
191 13
                $hostname = $matches[4];
192 13
                $database = $matches[13];
193 13
                break;
194
            default:
195
                $database = $matches[1];
196 13
        }
197
198
        return array(
199 13
            'hostname' => $hostname,
200 13
            'port'     => $port,
201 13
            'database' => $database,
202 13
            'charset'  => $charset,
203 13
        );
204
    }
205
206
    /**
207
     * @return string
208
     */
209 14
    protected function getDsnRegex()
210
    {
211 14
        $hostnameRegrex = "(([a-z]|[a-z][a-z0-9\-_]*[a-z0-9])\.)*([a-z]|[a-z][a-z0-9\-_]*[a-z0-9])";
212
        $validIpAddressRegex = "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}" .
213 14
            "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])";
214 14
        $hostnameOrIpAddressRegrex = "\/\/({$hostnameRegrex}|{$validIpAddressRegex})";
215 14
        $databaseRegex = "([a-z_][a-z\-_\d]*)|({$hostnameOrIpAddressRegrex}(:(\d+))?\/([a-z_][a-z\-_\d]*))";
216 14
        $charsetRegex = "(charset=([a-z\d\-_]+))?";
217 14
        $dsnRegex = "oci\:database=({$databaseRegex});?{$charsetRegex}";
218
219 14
        return $dsnRegex;
220
    }
221
222
    /**
223
     * @link http://php.net/manual/en/pdo.begintransaction.php
224
     * @return bool
225
     */
226 5
    public function beginTransaction()
227
    {
228 5
        if ($this->inTransaction()) {
229 2
            return false;
230
        }
231
232 5
        $this->setAttribute(\PDO::ATTR_AUTOCOMMIT, false);
233 5
        $this->isTransactionStarted = true;
234
235 5
        return true;
236
    }
237
238
    /**
239
     * @link http://php.net/manual/en/pdo.commit.php
240
     * @return bool
241
     */
242 1
    public function commit()
243
    {
244
        try {
245 1
            $isSuccess = $this->getConnection()->commit();
246 1
        } catch (Oci8Exception $ex) {
247
            $isSuccess = false;
248
        }
249
250 1
        $this->restoreAutocommitMode();
251
252 1
        return $isSuccess;
253
    }
254
255
    /**
256
     * @link http://php.net/manual/en/pdo.errorcode.php
257
     * @return null|string
258
     */
259 1 View Code Duplication
    public function errorCode()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
260
    {
261 1
        $connection = $this->getConnection();
262 1
        $driverError = $connection->getError();
263 1
        if (!$driverError) {
264 1
            return null;
265
        }
266
267
        $error = $this->errorInfo();
268
        $sqlStateErrorCode = $error[0];
269
270
        return $sqlStateErrorCode;
271
    }
272
273
    /**
274
     * @link http://php.net/manual/en/pdo.errorinfo.php
275
     * @return array
276
     */
277 1
    public function errorInfo()
278
    {
279 1
        $error = $this->getConnection()->getError();
280 1
        if (is_array($error)) {
281
            $errorInfo = array(
282
                OracleSqlStateCode::getSqlStateErrorCode((int)$error['code']),
283
                $error['message'],
284
                $error['code']
285
            );
286
        } else {
287
            $errorInfo = array(
288 1
                '00000',
289 1
                null,
290
                null
291 1
            );
292
        }
293
294 1
        return $errorInfo;
295
    }
296
297
    /**
298
     * @param string $statement
299
     *
300
     * @link http://php.net/manual/en/pdo.exec.php
301
     * @return bool|int
302
     */
303 4
    public function exec($statement)
304
    {
305 4
        $statement = $this->prepare($statement, $this->options);
306 4
        $type      = $this->getStatementType($statement);
0 ignored issues
show
Security Bug introduced by
It seems like $statement defined by $this->prepare($statement, $this->options) on line 305 can also be of type false; however, Jpina\PdoOci8\PdoOci8::getStatementType() does only seem to accept object<Jpina\PdoOci8\PdoOci8Statement>, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
307 4
        if ($type === 'SELECT') {
308 1
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type of the parent method PDO::exec of type integer.

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...
309
        }
310 3
        $statement->execute();
311
312 3
        return $statement->rowCount();
313
    }
314
315
    /**
316
     * @param PdoOci8Statement $statement
317
     * @return string
318
     */
319 4
    protected function getStatementType($statement)
320
    {
321 4
        $class = new \ReflectionClass($statement);
322 4
        $property = $class->getProperty('statement');
323 4
        $property->setAccessible(true);
324
        /** @var Oci8StatementInterface $rawStatement */
325 4
        $oci8Statement = $property->getValue($statement);
326 4
        $type = $oci8Statement->getType();
327
328 4
        return $type;
329
    }
330
331
    /**
332
     * @param int $attribute
333
     *
334
     * @link http://php.net/manual/en/pdo.getattribute.php
335
     * @return mixed
336
     */
337 13
    public function getAttribute($attribute)
338
    {
339 13
        if (array_key_exists($attribute, $this->options)) {
340 13
            return $this->options[$attribute];
341
        }
342
343
        return null;
344
    }
345
346
    /**
347
     * @link http://php.net/manual/en/pdo.getavailabledrivers.php
348
     * @return array
349
     */
350 1
    public static function getAvailableDrivers()
351
    {
352 1
        return array('oci');
353
    }
354
355
    /**
356
     * @link http://php.net/manual/en/pdo.intransaction.php
357
     * @return bool
358
     */
359 6
    public function inTransaction()
360
    {
361 6
        return $this->isTransactionStarted;
362
    }
363
364
    /**
365
     * @param string $name
366
     *
367
     * @link http://php.net/manual/en/pdo.lastinsertid.php
368
     * @return string
369
     */
370
    public function lastInsertId($name = null)
371
    {
372
        $statement = $this->query("select {$name}.currval from dual");
373
        $lastInsertedId = $statement->fetch();
374
375
        return $lastInsertedId;
376
    }
377
378
    /**
379
     * @param string $statement
380
     * @param array $driver_options
381
     *
382
     * @link http://php.net/manual/en/pdo.prepare.php
383
     * @return bool|PdoOci8Statement
384
     */
385 38
    public function prepare($statement, $driver_options = array())
386
    {
387
        // TODO Use $driver_options, eg. configure a cursor
388 38
        $exception = null;
0 ignored issues
show
Unused Code introduced by
$exception is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
389
        try {
390 38
            return new PdoOci8Statement($this->getConnection(), $statement, $driver_options);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Jpina\PdoOci...ment, $driver_options); (Jpina\PdoOci8\PdoOci8Statement) is incompatible with the return type of the parent method PDO::prepare of type PDOStatement.

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...
391
        } catch (\Exception $ex) {
392
            $exception = new PdoOci8Exception($ex->getMessage(), $ex->getCode(), $ex);
393
        }
394
395
        // TODO Create error handler
396
        $errorMode = $this->getAttribute(\PDO::ATTR_ERRMODE);
397
        switch ($errorMode) {
398
            case \PDO::ERRMODE_EXCEPTION:
399
                throw $exception;
400
            case \PDO::ERRMODE_WARNING:
401
                trigger_error($exception->getMessage(), E_WARNING);
402
                break;
403
            case \PDO::ERRMODE_SILENT:
404
            default:
405
        }
406
407
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type of the parent method PDO::prepare of type PDOStatement.

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...
408
    }
409
410
    /**
411
     * @param string $statement
412
     * @param int $mode
413
     * @param int|string|object $arg3
414
     * @param array $ctorargs
415
     *
416
     * @link http://php.net/manual/en/pdo.query.php
417
     * @return bool|PdoOci8Statement
418
     */
419 3
    public function query($statement, $mode = \PDO::ATTR_DEFAULT_FETCH_MODE, $arg3 = null, $ctorargs = array())
420
    {
421 3
        $result = false;
422
        try {
423 3
            $statement = $this->prepare($statement);
424
            switch ($mode) {
425 3
                case \PDO::FETCH_CLASS:
426
                    $statement->setFetchMode($mode, $arg3, $ctorargs);
427
                    break;
428 3
                case \PDO::FETCH_INTO:
429
                    $statement->setFetchMode($mode, $arg3);
430
                    break;
431 3
                case \PDO::FETCH_COLUMN:
432 3
                default:
433 3
                    $statement->setFetchMode($mode);
434 3
            }
435 3
            $statement->execute();
436 3
            $result = $statement;
437 3
        } catch (\PDOException $ex) {
438
            //TODO Handle Exception
439
        }
440
441 3
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $result; (Jpina\PdoOci8\PdoOci8Statement|false) is incompatible with the return type of the parent method PDO::query of type PDOStatement.

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...
442
    }
443
444
    /**
445
     * @param string $string
446
     * @param int $parameter_type
447
     *
448
     * @link http://php.net/manual/en/pdo.quote.php
449
     * @return bool|string
450
     */
451 5
    public function quote($string, $parameter_type = \PDO::PARAM_STR)
452
    {
453 5
        if (!is_scalar($string)) {
454 1
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type of the parent method PDO::quote of type string.

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...
455
        }
456
457
        try {
458 4
            if ($parameter_type !== \PDO::PARAM_STR) {
459 1
                $quotedString = (string)$string;
460 1
                $quotedString = "'" . $quotedString . "'";
461 1
                return $quotedString;
462
            }
463 4
        } catch (\Exception $ex) {
0 ignored issues
show
Unused Code introduced by
catch (\Exception $ex) { return false; } does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
464
            return false;
465
        }
466
467 4
        $quotedString = str_replace("\'", "'", $string);
468 4
        $quotedString = str_replace("'", "''", $quotedString);
469 4
        $quotedString = "'" . $quotedString . "'";
470
471 4
        return $quotedString;
472
    }
473
474 3
    protected function restoreAutocommitMode()
475
    {
476 3
        $autocommitMode = $this->getAutocommitMode();
477 3
        $this->setAttribute(\PDO::ATTR_AUTOCOMMIT, $autocommitMode);
478 3
    }
479
480
    /**
481
     * @link http://php.net/manual/en/pdo.rollback.php
482
     * @return bool
483
     */
484 3
    public function rollback()
485
    {
486 3
        if (!$this->inTransaction()) {
487 1
            throw new PdoOci8Exception('There is no active transaction');
488
        }
489
490
        try {
491 2
            $isSuccess = $this->getConnection()->rollback();
492 2
        } catch (Oci8Exception $ex) {
493
            $isSuccess = false;
494
        }
495
496 2
        $this->restoreAutocommitMode();
497
498 2
        return $isSuccess;
499
    }
500
501
    /**
502
     * @param bool $onOff
503
     */
504 12
    protected function setAutocommitMode($onOff)
505
    {
506 12
        $this->autoCommitMode = $onOff;
507 12
    }
508
509
    /**
510
     * @param int $attribute
511
     * @param mixed $value
512
     *
513
     * @link http://php.net/manual/en/pdo.setattribute.php
514
     * @return bool
515
     */
516 12
    public function setAttribute($attribute, $value)
517
    {
518
        $readOnlyAttributes = array(
519 12
            \PDO::ATTR_CLIENT_VERSION,
520 12
            \PDO::ATTR_CONNECTION_STATUS,
521 12
            \PDO::ATTR_DRIVER_NAME,
522 12
            \PDO::ATTR_PERSISTENT,
523 12
            \PDO::ATTR_SERVER_INFO,
524 12
            \PDO::ATTR_SERVER_VERSION,
525 12
        );
526
527 12 View Code Duplication
        if (array_search($attribute, $readOnlyAttributes) !== false ||
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
528 12
            !array_key_exists($attribute, $this->options)) {
529 12
            return false;
530
        }
531
532 6
        $this->options[$attribute] = $value;
533
534 6
        return true;
535
    }
536
}
537