ConnectionHandler::prepare()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
5
 * @license For full copyright and license information view LICENSE file distributed with this source code.
6
 */
7
namespace eZ\Publish\Core\Persistence\Doctrine;
8
9
use eZ\Publish\Core\Persistence\Database\DatabaseHandler;
10
use eZ\Publish\Core\Persistence\Database\QueryException;
11
use Doctrine\DBAL\Connection;
12
use Doctrine\DBAL\DriverManager;
13
use Doctrine\DBAL\DBALException;
14
15
/**
16
 * Class ConnectionHandler.
17
 *
18
 * @deprecated Since 6.13, please use Doctrine DBAL instead (@ezpublish.persistence.connection)
19
 *             it provides richer and more powerful DB abstraction which is also easier to use.
20
 */
21
class ConnectionHandler implements DatabaseHandler
0 ignored issues
show
Deprecated Code introduced by
The interface eZ\Publish\Core\Persiste...atabase\DatabaseHandler has been deprecated with message: Since 6.13, please use Doctrine DBAL instead (@ezpublish.persistence.connection) it provides richer and more powerful DB abstraction which is also easier to use.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
22
{
23
    /** @var \Doctrine\DBAL\Connection */
24
    protected $connection;
25
26
    /**
27
     * @param string|array $dsn
28
     *
29
     * @return \Doctrine\DBAL\Connection
30
     */
31
    public static function createConnectionFromDSN($dsn)
32
    {
33
        if (is_string($dsn)) {
34
            $parsed = self::parseDSN($dsn);
35
        } else {
36
            $parsed = $dsn;
37
        }
38
39
        /**
40
         * @todo retry connection here.
41
         */
42
        return DriverManager::getConnection($parsed);
43
    }
44
45
    /**
46
     * Create a Connection Handler from given Doctrine $connection.
47
     *
48
     * @param \Doctrine\DBAL\Connection $connection
49
     *
50
     * @return \eZ\Publish\Core\Persistence\Doctrine\ConnectionHandler
51
     */
52
    public static function createFromConnection(Connection $connection)
53
    {
54
        $driver = $connection->getDriver()->getName();
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\DBAL\Driver::getName() has been deprecated.

This method has been deprecated.

Loading history...
55
56
        if ($driver === 'pdo_sqlite') {
57
            return new ConnectionHandler\SqliteConnectionHandler($connection);
58
        }
59
60
        if ($driver === 'pdo_pgsql') {
61
            return new ConnectionHandler\PostgresConnectionHandler($connection);
62
        }
63
64
        return new self($connection);
0 ignored issues
show
Deprecated Code introduced by
The class eZ\Publish\Core\Persiste...trine\ConnectionHandler has been deprecated with message: Since 6.13, please use Doctrine DBAL instead (@ezpublish.persistence.connection) it provides richer and more powerful DB abstraction which is also easier to use.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
65
    }
66
67
    /**
68
     * Create a Connection Handler with corresponding Doctrine connection from DSN.
69
     *
70
     * @param string|array $dsn
71
     *
72
     * @return ConnectionHandler
73
     */
74
    public static function createFromDSN($dsn)
75
    {
76
        if (is_string($dsn)) {
77
            $parsed = self::parseDSN($dsn);
78
        } else {
79
            $parsed = $dsn;
80
        }
81
82
        $connection = DriverManager::getConnection($parsed);
83
84
        if ($parsed['driver'] === 'pdo_sqlite') {
85
            return new ConnectionHandler\SqliteConnectionHandler($connection);
86
        }
87
88
        if ($parsed['driver'] === 'pdo_pgsql') {
89
            return new ConnectionHandler\PostgresConnectionHandler($connection);
90
        }
91
92
        return new self($connection);
0 ignored issues
show
Deprecated Code introduced by
The class eZ\Publish\Core\Persiste...trine\ConnectionHandler has been deprecated with message: Since 6.13, please use Doctrine DBAL instead (@ezpublish.persistence.connection) it provides richer and more powerful DB abstraction which is also easier to use.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
93
    }
94
95
    /**
96
     * Returns the Data Source Name as a structure containing the various parts of the DSN.
97
     *
98
     * Additional keys can be added by appending a URI query string to the
99
     * end of the DSN.
100
     *
101
     * The format of the supplied DSN is in its fullest form:
102
     * <code>
103
     *  driver://user:password@protocol+host/database?option=8&another=true
104
     * </code>
105
     *
106
     * Most variations are allowed:
107
     * <code>
108
     *  driver://user:password@protocol+host:110//usr/db_file.db?mode=0644
109
     *  driver://user:password@host/dbname
110
     *  driver://user:password@host
111
     *  driver://user@host
112
     *  driver://host/dbname
113
     *  driver://host
114
     *  driver
115
     * </code>
116
     *
117
     * This function is 'borrowed' from PEAR /DB.php .
118
     *
119
     * @license Apache2 from Zeta Components Database project
120
     *
121
     * @param string $dsn Data Source Name to be parsed
122
     *
123
     * @return array an associative array with the following keys:
124
     *  + driver:  Database backend used in PHP (mysql, odbc etc.)
125
     *  + host: Host specification (hostname[:port])
126
     *  + dbname: Database to use on the DBMS server
127
     *  + username: User name for login
128
     *  + password: Password for login
129
     */
130
    public static function parseDSN($dsn)
131
    {
132
        $parsed = [
133
            'driver' => false,
134
            'user' => false,
135
            'password' => false,
136
            'host' => false,
137
            'port' => false,
138
            'unix_socket' => false,
139
            'dbname' => false,
140
            'memory' => false,
141
            'path' => false,
142
        ];
143
144
        // Find driver and dbsyntax
145
        if (($pos = strpos($dsn, '://')) !== false) {
146
            $str = substr($dsn, 0, $pos);
147
            $dsn = substr($dsn, $pos + 3);
148
        } else {
149
            $str = $dsn;
150
            $dsn = null;
151
        }
152
153
        // Get driver and dbsyntax
154
        // $str => driver(dbsyntax)
155
        if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {
156
            $parsed['driver'] = $arr[1];
157
        } else {
158
            $parsed['driver'] = $str;
159
        }
160
161
        if (empty($dsn)) {
162
            return $parsed;
163
        }
164
165
        // Get (if found): username and password
166
        // $dsn => username:password@protocol+host/database
167
        if (($at = strrpos((string)$dsn, '@')) !== false) {
168
            $str = substr($dsn, 0, $at);
169
            $dsn = substr($dsn, $at + 1);
170
            if (($pos = strpos($str, ':')) !== false) {
171
                $parsed['user'] = rawurldecode(substr($str, 0, $pos));
172
                $parsed['password'] = rawurldecode(substr($str, $pos + 1));
173
            } else {
174
                $parsed['user'] = rawurldecode($str);
175
            }
176
        }
177
178
        // Find protocol and host
179
180
        if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) {
181
            // $dsn => proto(proto_opts)/database
182
            $proto = $match[1];
183
            $proto_opts = $match[2] ?: false;
184
            $dsn = $match[3];
185
        } else {
186
            // $dsn => protocol+host/database (old format)
187 View Code Duplication
            if (strpos($dsn, '+') !== 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...
188
                list($proto, $dsn) = explode('+', $dsn, 2);
189
            }
190
            if (strpos($dsn, '/') !== false) {
191
                list($proto_opts, $dsn) = explode('/', $dsn, 2);
192
            } else {
193
                $proto_opts = $dsn;
194
                $dsn = null;
195
            }
196
        }
197
198
        // process the different protocol options
199
        $protocol = (!empty($proto)) ? $proto : 'tcp';
200
        $proto_opts = rawurldecode($proto_opts);
201
        if ($protocol === 'tcp') {
202
            if (strpos($proto_opts, ':') !== false) {
203
                list($parsed['host'], $parsed['port']) = explode(':', $proto_opts);
204
            } else {
205
                $parsed['host'] = $proto_opts;
206
            }
207
        } elseif ($protocol === 'unix') {
208
            $parsed['unix_socket'] = $proto_opts;
209
        }
210
211
        // Get dabase if any
212
        // $dsn => database
213
        if ($dsn) {
214
            if (($pos = strpos($dsn, '?')) === false) {
215
                // /database
216
                $parsed['dbname'] = rawurldecode($dsn);
217
            } else {
218
                // /database?param1=value1&param2=value2
219
                $parsed['dbname'] = rawurldecode(substr($dsn, 0, $pos));
220
                $dsn = substr($dsn, $pos + 1);
221 View Code Duplication
                if (strpos($dsn, '&') !== 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...
222
                    $opts = explode('&', $dsn);
223
                } else {
224
                    $opts = [$dsn];
225
                }
226
227
                foreach ($opts as $opt) {
228
                    list($key, $value) = explode('=', $opt);
229
                    if (!isset($parsed[$key])) {
230
                        // don't allow params overwrite
231
                        $parsed[$key] = rawurldecode($value);
232
                    }
233
                }
234
            }
235
        }
236
237
        if ($parsed['driver'] === 'sqlite') {
238
            if (isset($parsed['port']) && $parsed['port'] === 'memory') {
239
                $parsed['memory'] = true;
240
                unset($parsed['port']);
241
                unset($parsed['host']);
242
            } elseif (isset($parsed['dbname'])) {
243
                $parsed['path'] = $parsed['dbname'];
244
                unset($parsed['dbname']);
245
                unset($parsed['host']);
246
            }
247
        }
248
249
        $driverMap = [
250
            'mysql' => 'pdo_mysql',
251
            'pgsql' => 'pdo_pgsql',
252
            'sqlite' => 'pdo_sqlite',
253
        ];
254
255
        if (isset($driverMap[$parsed['driver']])) {
256
            $parsed['driver'] = $driverMap[$parsed['driver']];
257
        }
258
259
        return array_filter(
260
            $parsed,
261
            function ($element) {
262
                return $element !== false;
263
            }
264
        );
265
    }
266
267
    /**
268
     * @param \Doctrine\DBAL\Connection $connection
269
     */
270
    public function __construct(Connection $connection)
271
    {
272
        $this->connection = $connection;
273
    }
274
275
    /**
276
     * @return \Doctrine\DBAL\Connection
277
     */
278
    public function getConnection()
279
    {
280
        return $this->connection;
281
    }
282
283
    /**
284
     * @return string
285
     */
286
    public function getName()
287
    {
288
        return $this->connection->getDatabasePlatform()->getName();
289
    }
290
291
    /**
292
     * Begin a transaction.
293
     */
294
    public function beginTransaction()
295
    {
296
        try {
297
            $this->connection->beginTransaction();
298
        } catch (DBALException $e) {
299
            throw new QueryException($e->getMessage(), $e->getCode(), $e);
0 ignored issues
show
Deprecated Code introduced by
The class eZ\Publish\Core\Persiste...Database\QueryException has been deprecated with message: Since 6.13, please use Doctrine DBAL instead (@ezpublish.persistence.connection) it provides richer and more powerful DB abstraction which is also easier to use.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
300
        }
301
    }
302
303
    /**
304
     * Commit a transaction.
305
     */
306
    public function commit()
307
    {
308
        try {
309
            $this->connection->commit();
310
        } catch (DBALException $e) {
311
            throw new QueryException($e->getMessage(), $e->getCode(), $e);
0 ignored issues
show
Deprecated Code introduced by
The class eZ\Publish\Core\Persiste...Database\QueryException has been deprecated with message: Since 6.13, please use Doctrine DBAL instead (@ezpublish.persistence.connection) it provides richer and more powerful DB abstraction which is also easier to use.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
312
        }
313
    }
314
315
    /**
316
     * Rollback a transaction.
317
     */
318
    public function rollBack()
319
    {
320
        try {
321
            $this->connection->rollBack();
322
        } catch (DBALException $e) {
323
            throw new QueryException($e->getMessage(), $e->getCode(), $e);
0 ignored issues
show
Deprecated Code introduced by
The class eZ\Publish\Core\Persiste...Database\QueryException has been deprecated with message: Since 6.13, please use Doctrine DBAL instead (@ezpublish.persistence.connection) it provides richer and more powerful DB abstraction which is also easier to use.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
324
        }
325
    }
326
327
    public function prepare($query)
328
    {
329
        return $this->connection->prepare($query);
330
    }
331
332
    /**
333
     * Retrieve the last auto incremet or sequence id.
334
     *
335
     * @param string $sequenceName
336
     *
337
     * @return string
338
     */
339
    public function lastInsertId($sequenceName = null)
340
    {
341
        return $this->connection->lastInsertId($sequenceName);
342
    }
343
344
    /**
345
     * @return bool
346
     */
347
    public function useSequences()
348
    {
349
        return $this->connection->getDatabasePlatform()->supportsSequences();
350
    }
351
352
    /**
353
     * Execute a query against the database.
354
     *
355
     * @param string $query
356
     */
357
    public function exec($query)
358
    {
359
        try {
360
            $this->connection->exec($query);
361
        } catch (DBALException $e) {
362
            throw new QueryException($e->getMessage(), $e->getCode(), $e);
0 ignored issues
show
Deprecated Code introduced by
The class eZ\Publish\Core\Persiste...Database\QueryException has been deprecated with message: Since 6.13, please use Doctrine DBAL instead (@ezpublish.persistence.connection) it provides richer and more powerful DB abstraction which is also easier to use.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
363
        }
364
    }
365
366
    /**
367
     * Create Select Query object.
368
     *
369
     * @return \eZ\Publish\Core\Persistence\Database\SelectQuery
370
     */
371
    public function createSelectQuery()
372
    {
373
        return new SelectDoctrineQuery($this->connection);
0 ignored issues
show
Deprecated Code introduced by
The class eZ\Publish\Core\Persiste...ine\SelectDoctrineQuery has been deprecated with message: Since 6.13, please use Doctrine DBAL instead (@ezpublish.persistence.connection) it provides richer and more powerful DB abstraction which is also easier to use.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
374
    }
375
376
    /**
377
     * Create Insert Query object.
378
     *
379
     * @return \eZ\Publish\Core\Persistence\Database\InsertQuery
380
     */
381
    public function createInsertQuery()
382
    {
383
        return new InsertDoctrineQuery($this->connection);
0 ignored issues
show
Deprecated Code introduced by
The class eZ\Publish\Core\Persiste...ine\InsertDoctrineQuery has been deprecated with message: Since 6.13, please use Doctrine DBAL instead (@ezpublish.persistence.connection) it provides richer and more powerful DB abstraction which is also easier to use.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
384
    }
385
386
    /**
387
     * Create update Query object.
388
     *
389
     * @return \eZ\Publish\Core\Persistence\Database\UpdateQuery
390
     */
391
    public function createUpdateQuery()
392
    {
393
        return new UpdateDoctrineQuery($this->connection);
0 ignored issues
show
Deprecated Code introduced by
The class eZ\Publish\Core\Persiste...ine\UpdateDoctrineQuery has been deprecated with message: Since 6.13, please use Doctrine DBAL instead (@ezpublish.persistence.connection) it provides richer and more powerful DB abstraction which is also easier to use.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
394
    }
395
396
    /**
397
     * Create a Delete Query object.
398
     *
399
     * @return \eZ\Publish\Core\Persistence\Database\DeleteQuery
400
     */
401
    public function createDeleteQuery()
402
    {
403
        return new DeleteDoctrineQuery($this->connection);
0 ignored issues
show
Deprecated Code introduced by
The class eZ\Publish\Core\Persiste...ine\DeleteDoctrineQuery has been deprecated with message: Since 6.13, please use Doctrine DBAL instead (@ezpublish.persistence.connection) it provides richer and more powerful DB abstraction which is also easier to use.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
404
    }
405
406
    /**
407
     * Creates an alias for $tableName, $columnName in $query.
408
     *
409
     * @param \eZ\Publish\Core\Persistence\Database\SelectQuery $query
410
     * @param string $columnName
411
     * @param string|null $tableName
412
     *
413
     * @return string
414
     */
415
    public function aliasedColumn($query, $columnName, $tableName = null)
416
    {
417
        return $this->alias(
418
            $this->quoteColumn($columnName, $tableName),
419
            $this->quoteIdentifier(
420
                ($tableName ? $tableName . '_' : '') .
421
                $columnName
422
            )
423
        );
424
    }
425
426
    /**
427
     * Returns a qualified identifier for $columnName in $tableName.
428
     *
429
     * @param string $columnName
430
     * @param string $tableName
431
     *
432
     * @return string
433
     */
434
    public function quoteColumn($columnName, $tableName = null)
435
    {
436
        return
437
            ($tableName ? $this->quoteTable($tableName) . '.' : '') .
438
            $this->quoteIdentifier($columnName);
439
    }
440
441
    /**
442
     * Returns a qualified identifier for $tableName.
443
     *
444
     * @param string $tableName
445
     *
446
     * @return string
447
     */
448
    public function quoteTable($tableName)
449
    {
450
        return $this->quoteIdentifier($tableName);
451
    }
452
453
    /**
454
     * Custom alias method.
455
     *
456
     * Ignores some properties of identifier quoting, but since we use somehow
457
     * sane table and column names, ourselves, this is fine.
458
     *
459
     * This is an optimization and works around the ezcDB implementation.
460
     *
461
     * @param string $identifier
0 ignored issues
show
Bug introduced by
There is no parameter named $identifier. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
462
     *
463
     * @return string
464
     */
465
    public function alias($name, $alias)
466
    {
467
        return $name . ' ' . $alias;
468
    }
469
470
    /**
471
     * Custom quote identifier method.
472
     *
473
     * Ignores some properties of identifier quoting, but since we use somehow
474
     * sane table and column names, ourselves, this is fine.
475
     *
476
     * This is an optimization and works around the ezcDB implementation.
477
     *
478
     * @param string $identifier
479
     *
480
     * @return string
481
     */
482
    public function quoteIdentifier($identifier)
483
    {
484
        return '`' . $identifier . '`';
485
    }
486
487
    /**
488
     * Get auto increment value.
489
     *
490
     * Returns the value used for autoincrement tables. Usually this will just
491
     * be null. In case for sequence based RDBMS this method can return a
492
     * proper value for the given column.
493
     *
494
     * @param string $table
495
     * @param string $column
496
     *
497
     * @return mixed
498
     */
499
    public function getAutoIncrementValue($table, $column)
500
    {
501
        return 'null';
502
    }
503
504
    /**
505
     * Returns the name of the affected sequence.
506
     *
507
     * @param string $table
508
     * @param string $column
509
     *
510
     * @return string
511
     */
512
    public function getSequenceName($table, $column)
513
    {
514
        return null;
515
    }
516
}
517