Completed
Pull Request — develop (#3533)
by
unknown
16:31 queued 01:26
created

AbstractMySQLDriver   F

Complexity

Total Complexity 70

Size/Duplication

Total Lines 200
Duplicated Lines 0 %

Test Coverage

Coverage 97.27%

Importance

Changes 0
Metric Value
wmc 70
eloc 103
dl 0
loc 200
rs 2.8
c 0
b 0
f 0
ccs 107
cts 110
cp 0.9727

7 Methods

Rating   Name   Duplication   Size   Complexity  
D convertException() 0 77 53
B createDatabasePlatformForVersion() 0 23 7
A getOracleMysqlVersionNumber() 0 21 5
A getSchemaManager() 0 3 1
A getMariaDbMysqlVersionNumber() 0 14 2
A getDatabasePlatform() 0 3 1
A getDatabase() 0 5 1

How to fix   Complexity   

Complex Class

Complex classes like AbstractMySQLDriver 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.

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 AbstractMySQLDriver, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\DBAL\Driver;
6
7
use Doctrine\DBAL\Connection;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Doctrine\DBAL\Driver\Connection. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
8
use Doctrine\DBAL\DBALException;
9
use Doctrine\DBAL\Driver;
10
use Doctrine\DBAL\Exception;
11
use Doctrine\DBAL\Platforms\MariaDb1027Platform;
12
use Doctrine\DBAL\Platforms\MariaDb1043Platform;
13
use Doctrine\DBAL\Platforms\MySQL57Platform;
14
use Doctrine\DBAL\Platforms\MySQL80Platform;
15
use Doctrine\DBAL\Platforms\MySqlPlatform;
16
use Doctrine\DBAL\Schema\MySqlSchemaManager;
17
use Doctrine\DBAL\VersionAwarePlatformDriver;
18
use function preg_match;
19
use function stripos;
20
use function version_compare;
21
22
/**
23
 * Abstract base implementation of the {@link Doctrine\DBAL\Driver} interface for MySQL based drivers.
24
 */
25
abstract class AbstractMySQLDriver implements Driver, ExceptionConverterDriver, VersionAwarePlatformDriver
26
{
27
    /**
28
     * {@inheritdoc}
29
     *
30
     * @link http://dev.mysql.com/doc/refman/5.7/en/error-messages-client.html
31
     * @link http://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
32
     */
33 2620
    public function convertException($message, DriverException $exception)
34
    {
35 2620
        switch ($exception->getCode()) {
36 3
            case 1213:
37 2620
                return new Exception\DeadlockException($message, $exception);
38 3
            case 1205:
39 2620
                return new Exception\LockWaitTimeoutException($message, $exception);
40 3
            case 1050:
41 2620
                return new Exception\TableExistsException($message, $exception);
42
43 3
            case 1051:
44 3
            case 1146:
45 2620
                return new Exception\TableNotFoundException($message, $exception);
46
47 3
            case 1216:
48 3
            case 1217:
49 3
            case 1451:
50 3
            case 1452:
51 3
            case 1701:
52 2620
                return new Exception\ForeignKeyConstraintViolationException($message, $exception);
53
54 3
            case 1062:
55 3
            case 1557:
56 3
            case 1569:
57 3
            case 1586:
58 2620
                return new Exception\UniqueConstraintViolationException($message, $exception);
59
60 3
            case 1054:
61 3
            case 1166:
62 3
            case 1611:
63 2620
                return new Exception\InvalidFieldNameException($message, $exception);
64
65 3
            case 1052:
66 3
            case 1060:
67 3
            case 1110:
68 2620
                return new Exception\NonUniqueFieldNameException($message, $exception);
69
70 3
            case 1064:
71 3
            case 1149:
72 3
            case 1287:
73 3
            case 1341:
74 3
            case 1342:
75 3
            case 1343:
76 3
            case 1344:
77 3
            case 1382:
78 3
            case 1479:
79 3
            case 1541:
80 3
            case 1554:
81 3
            case 1626:
82 2620
                return new Exception\SyntaxErrorException($message, $exception);
83
84 3
            case 1044:
85 3
            case 1045:
86 3
            case 1046:
87 3
            case 1049:
88 3
            case 1095:
89 3
            case 1142:
90 3
            case 1143:
91 3
            case 1227:
92 3
            case 1370:
93 3
            case 1429:
94 3
            case 2002:
95 3
            case 2005:
96 2620
                return new Exception\ConnectionException($message, $exception);
97
98 3
            case 1048:
99 3
            case 1121:
100 3
            case 1138:
101 3
            case 1171:
102 3
            case 1252:
103 3
            case 1263:
104 3
            case 1364:
105 3
            case 1566:
106 2620
                return new Exception\NotNullConstraintViolationException($message, $exception);
107
        }
108
109 2620
        return new Exception\DriverException($message, $exception);
110
    }
111
112
    /**
113
     * {@inheritdoc}
114
     *
115
     * @throws DBALException
116
     */
117 2597
    public function createDatabasePlatformForVersion($version)
118
    {
119 2597
        $mariadb = stripos($version, 'mariadb') !== false;
120 2597
        if ($mariadb) {
121 2594
            if (version_compare($this->getMariaDbMysqlVersionNumber($version), '10.4.3', '>=')) {
122 2594
                return new MariaDb1043Platform();
123
            }
124 2594
            if (version_compare($this->getMariaDbMysqlVersionNumber($version), '10.2.7', '>=')) {
125 2594
                return new MariaDb1027Platform();
126
            }
127
        }
128
129 2597
        if (! $mariadb) {
130 2597
            $oracleMysqlVersion = $this->getOracleMysqlVersionNumber($version);
131 2594
            if (version_compare($oracleMysqlVersion, '8', '>=')) {
132 2594
                return new MySQL80Platform();
133
            }
134 2594
            if (version_compare($oracleMysqlVersion, '5.7.9', '>=')) {
135 2594
                return new MySQL57Platform();
136
            }
137
        }
138
139 2594
        return $this->getDatabasePlatform();
140
    }
141
142
    /**
143
     * Get a normalized 'version number' from the server string
144
     * returned by Oracle MySQL servers.
145
     *
146
     * @param string $versionString Version string returned by the driver, i.e. '5.7.10'
147
     *
148
     * @throws DBALException
149
     */
150 2597
    private function getOracleMysqlVersionNumber(string $versionString) : string
151
    {
152 2597
        if (! preg_match(
153 6
            '/^(?P<major>\d+)(?:\.(?P<minor>\d+)(?:\.(?P<patch>\d+))?)?/',
154 2597
            $versionString,
155 2597
            $versionParts
156
        )) {
157 2568
            throw DBALException::invalidPlatformVersionSpecified(
158 3
                $versionString,
159 2568
                '<major_version>.<minor_version>.<patch_version>'
160
            );
161
        }
162 2594
        $majorVersion = $versionParts['major'];
163 2594
        $minorVersion = $versionParts['minor'] ?? 0;
164 2594
        $patchVersion = $versionParts['patch'] ?? null;
165
166 2594
        if ($majorVersion === '5' && $minorVersion === '7' && $patchVersion === null) {
167 2594
            $patchVersion = '9';
168
        }
169
170 2594
        return $majorVersion . '.' . $minorVersion . '.' . $patchVersion;
171
    }
172
173
    /**
174
     * Detect MariaDB server version, including hack for some mariadb distributions
175
     * that starts with the prefix '5.5.5-'
176
     *
177
     * @param string $versionString Version string as returned by mariadb server, i.e. '5.5.5-Mariadb-10.0.8-xenial'
178
     *
179
     * @throws DBALException
180
     */
181 2594
    private function getMariaDbMysqlVersionNumber(string $versionString) : string
182
    {
183 2594
        if (! preg_match(
184 3
            '/^(?:5\.5\.5-)?(mariadb-)?(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)/i',
185 2594
            $versionString,
186 2594
            $versionParts
187
        )) {
188
            throw DBALException::invalidPlatformVersionSpecified(
189
                $versionString,
190
                '^(?:5\.5\.5-)?(mariadb-)?<major_version>.<minor_version>.<patch_version>'
191
            );
192
        }
193
194 2594
        return $versionParts['major'] . '.' . $versionParts['minor'] . '.' . $versionParts['patch'];
195
    }
196
197
    /**
198
     * {@inheritdoc}
199
     */
200 2646
    public function getDatabase(Connection $conn)
201
    {
202 2646
        $params = $conn->getParams();
203
204 2646
        return $params['dbname'] ?? $conn->query('SELECT DATABASE()')->fetchColumn();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $params['dbname']...BASE()')->fetchColumn() also could return the type false which is incompatible with the return type mandated by Doctrine\DBAL\Driver::getDatabase() of string.
Loading history...
205
    }
206
207
    /**
208
     * {@inheritdoc}
209
     *
210
     * @return MySqlPlatform
211
     */
212 2597
    public function getDatabasePlatform()
213
    {
214 2597
        return new MySqlPlatform();
215
    }
216
217
    /**
218
     * {@inheritdoc}
219
     *
220
     * @return MySqlSchemaManager
221
     */
222 2516
    public function getSchemaManager(Connection $conn)
223
    {
224 2516
        return new MySqlSchemaManager($conn);
225
    }
226
}
227