Skip to content

Commit

Permalink
Merge pull request #2958 from morozov/issues/2953
Browse files Browse the repository at this point in the history
Remove hard dependency on PDO
  • Loading branch information
Ocramius authored Jan 25, 2018
2 parents 4adca54 + 83a6c1b commit 7fb41ab
Show file tree
Hide file tree
Showing 75 changed files with 1,101 additions and 688 deletions.
45 changes: 45 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,48 @@
# Upgrade to DEVELOP

## BC BREAK: the PDO symbols are no longer part of the DBAL API

1. The support of `PDO::PARAM_*`, `PDO::FETCH_*`, `PDO::CASE_*` and `PDO::PARAM_INPUT_OUTPUT` constants in the DBAL API is removed.
2. `\Doctrine\DBAL\Driver\PDOStatement` does not extend `\PDOStatement` anymore.

Before:

use Doctrine\DBAL\Portability\Connection;

$params = array(
'wrapperClass' => Connection::class,
'fetch_case' => PDO::CASE_LOWER,
);

$stmt->bindValue(1, 1, PDO::PARAM_INT);
$stmt->fetchAll(PDO::FETCH_COLUMN);

After:

use Doctrine\DBAL\ColumnCase;
use Doctrine\DBAL\FetchMode;
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Portability\Connection;

$params = array(
'wrapperClass' => Connection::class,
'fetch_case' => ColumnCase::LOWER,
);

$stmt->bindValue(1, 1, ParameterType::INTEGER);
$stmt->fetchAll(FetchMode::COLUMN);

# Upgrade to UNRELEASED

## DEPRECATION: direct usage of the PDO APIs in the DBAL API

1. When calling `Doctrine\DBAL\Driver\Statement` methods, instead of `PDO::PARAM_*` constants, `Doctrine\DBAL\ParameterType` constants should be used.
2. When calling `Doctrine\DBAL\Driver\ResultStatement` methods, instead of `PDO::FETCH_*` constants, `Doctrine\DBAL\FetchMode` constants should be used.
3. When configuring `Doctrine\DBAL\Portability\Connection`, instead of `PDO::CASE_*` constants, `Doctrine\DBAL\ColumnCase` constants should be used.
4. Usage of `PDO::PARAM_INPUT_OUTPUT` in `Doctrine\DBAL\Driver\Statement::bindValue()` is deprecated.
5. Usage of `PDO::FETCH_FUNC` in `Doctrine\DBAL\Driver\ResultStatement::fetch()` is deprecated.
6. Calls to `\PDOStatement` methods on a `\Doctrine\DBAL\Driver\PDOStatement` instance (e.g. `fetchObject()`) are deprecated.

# Upgrade to 2.6

## MINOR BC BREAK: `fetch()` and `fetchAll()` method signatures in `Doctrine\DBAL\Driver\ResultStatement`
Expand Down
1 change: 0 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
],
"require": {
"php": "^7.2",
"ext-pdo": "*",
"doctrine/common": "^2.7.1"
},
"require-dev": {
Expand Down
18 changes: 14 additions & 4 deletions docs/en/reference/data-retrieval-and-manipulation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,13 @@ Binding Types
-------------

Doctrine DBAL extends PDOs handling of binding types in prepared statements
considerably. Besides the well known ``\PDO::PARAM_*`` constants you
considerably. Besides ``Doctrine\DBAL\ParameterType`` constants, you
can make use of two very powerful additional features.

Doctrine\DBAL\Types Conversion
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you don't specify an integer (through a ``PDO::PARAM*`` constant) to
If you don't specify an integer (through one of ``Doctrine\DBAL\ParameterType`` constants) to
any of the parameter binding methods but a string, Doctrine DBAL will
ask the type abstraction layer to convert the passed value from
its PHP to a database representation. This way you can pass ``\DateTime``
Expand Down Expand Up @@ -271,7 +271,14 @@ be specified as well:
// Same SQL WITHOUT usage of Doctrine\DBAL\Connection::PARAM_INT_ARRAY
$stmt = $conn->executeQuery('SELECT * FROM articles WHERE id IN (?, ?, ?, ?, ?, ?)',
array(1, 2, 3, 4, 5, 6),
array(\PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT)
array(
ParameterType::INTEGER,
ParameterType::INTEGER,
ParameterType::INTEGER,
ParameterType::INTEGER,
ParameterType::INTEGER,
ParameterType::INTEGER,
)
);
This is much more complicated and is ugly to write generically.
Expand Down Expand Up @@ -469,8 +476,11 @@ Quote a value:
.. code-block:: php
<?php
use Doctrine\DBAL\ParameterType;
$quoted = $conn->quote('value');
$quoted = $conn->quote('1234', \PDO::PARAM_INT);
$quoted = $conn->quote('1234', ParameterType::INTEGER);
quoteIdentifier()
~~~~~~~~~~~~~~~~~
Expand Down
2 changes: 1 addition & 1 deletion docs/en/reference/known-vendor-issues.rst
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,6 @@ The ``PDO_SQLSRV`` driver currently has a bug when binding values to
VARBINARY/BLOB columns with ``bindValue`` in prepared statements.
This raises an implicit conversion from data type error as it tries
to convert a character type value to a binary type value even if
you explicitly define the value as ``\PDO::PARAM_LOB`` type.
you explicitly define the value as ``ParameterType::LARGE_OBJECT`` type.
Therefore it is highly encouraged to use the native ``sqlsrv``
driver instead which does not have this limitation.
12 changes: 8 additions & 4 deletions docs/en/reference/portability.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,16 @@ Using the following code block in your initialization will:
.. code-block:: php
<?php
use Doctrine\DBAL\ColumnCase;
use Doctrine\DBAL\Portability\Connection as PortableConnection;
$params = array(
// vendor specific configuration
//...
'wrapperClass' => 'Doctrine\DBAL\Portability\Connection',
'portability' => \Doctrine\DBAL\Portability\Connection::PORTABILITY_ALL,
'fetch_case' => \PDO::CASE_LOWER,
'wrapperClass' => PortableConnection::class,
'portability' => PortableConnection::PORTABILITY_ALL,
'fetch_case' => PortableConnection::LOWER,
);
This sort of portability handling is pretty expensive because all the result
Expand All @@ -80,4 +84,4 @@ This functionality is only implemented with Doctrine 2.1 upwards.
Doctrine ships with lists of keywords for every supported vendor. You
can access a keyword list through the schema manager of the vendor you
are currently using or just instantiating it from the ``Doctrine\DBAL\Platforms\Keywords``
namespace.
namespace.
4 changes: 2 additions & 2 deletions docs/en/reference/security.rst
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ the ``Connection#quote`` method:
<?php
// Parameter quoting
$sql = "SELECT * FROM users WHERE name = " . $connection->quote($_GET['username'], \PDO::PARAM_STR);
$sql = "SELECT * FROM users WHERE name = " . $connection->quote($_GET['username']);
This method is only available for SQL, not for DQL. For DQL you are always encouraged to use prepared
statements not only for security, but also for caching reasons.
statements not only for security, but also for caching reasons.
54 changes: 31 additions & 23 deletions lib/Doctrine/DBAL/Cache/ArrayStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace Doctrine\DBAL\Cache;

use Doctrine\DBAL\Driver\ResultStatement;
use PDO;
use Doctrine\DBAL\FetchMode;

class ArrayStatement implements \IteratorAggregate, ResultStatement
{
Expand All @@ -25,7 +25,7 @@ class ArrayStatement implements \IteratorAggregate, ResultStatement
/**
* @var integer
*/
private $defaultFetchMode = PDO::FETCH_BOTH;
private $defaultFetchMode = FetchMode::MIXED;

/**
* @param array $data
Expand Down Expand Up @@ -57,9 +57,9 @@ public function columnCount()
/**
* {@inheritdoc}
*/
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null)
public function setFetchMode($fetchMode, ...$args)
{
if ($arg2 !== null || $arg3 !== null) {
if (count($args) > 0) {
throw new \InvalidArgumentException("Caching layer does not support 2nd/3rd argument to setFetchMode()");
}

Expand All @@ -81,34 +81,41 @@ public function getIterator()
/**
* {@inheritdoc}
*/
public function fetch($fetchMode = null, $cursorOrientation = \PDO::FETCH_ORI_NEXT, $cursorOffset = 0)
public function fetch($fetchMode = null, ...$args)
{
if (isset($this->data[$this->num])) {
$row = $this->data[$this->num++];
$fetchMode = $fetchMode ?: $this->defaultFetchMode;
if ($fetchMode === PDO::FETCH_ASSOC) {
return $row;
} elseif ($fetchMode === PDO::FETCH_NUM) {
return array_values($row);
} elseif ($fetchMode === PDO::FETCH_BOTH) {
return array_merge($row, array_values($row));
} elseif ($fetchMode === PDO::FETCH_COLUMN) {
return reset($row);
} else {
throw new \InvalidArgumentException("Invalid fetch-style given for fetching result.");
}
if ( ! isset($this->data[$this->num])) {
return false;
}

$row = $this->data[$this->num++];
$fetchMode = $fetchMode ?: $this->defaultFetchMode;

if ($fetchMode === FetchMode::ASSOCIATIVE) {
return $row;
}

if ($fetchMode === FetchMode::NUMERIC) {
return array_values($row);
}

return false;
if ($fetchMode === FetchMode::MIXED) {
return array_merge($row, array_values($row));
}

if ($fetchMode === FetchMode::COLUMN) {
return reset($row);
}

throw new \InvalidArgumentException("Invalid fetch-style given for fetching result.");
}

/**
* {@inheritdoc}
*/
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null)
public function fetchAll($fetchMode = null, ...$args)
{
$rows = [];
while ($row = $this->fetch($fetchMode)) {
while ($row = $this->fetch($fetchMode, ...$args)) {
$rows[] = $row;
}

Expand All @@ -120,7 +127,8 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n
*/
public function fetchColumn($columnIndex = 0)
{
$row = $this->fetch(PDO::FETCH_NUM);
$row = $this->fetch(FetchMode::NUMERIC);

if (!isset($row[$columnIndex])) {
// TODO: verify this is correct behavior
return false;
Expand Down
37 changes: 23 additions & 14 deletions lib/Doctrine/DBAL/Cache/ResultCacheStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\Common\Cache\Cache;
use PDO;
use Doctrine\DBAL\FetchMode;

/**
* Cache statement for SQL results.
Expand Down Expand Up @@ -63,7 +63,7 @@ class ResultCacheStatement implements \IteratorAggregate, ResultStatement
/**
* @var integer
*/
private $defaultFetchMode = PDO::FETCH_BOTH;
private $defaultFetchMode = FetchMode::MIXED;

/**
* @param \Doctrine\DBAL\Driver\Statement $stmt
Expand Down Expand Up @@ -110,7 +110,7 @@ public function columnCount()
/**
* {@inheritdoc}
*/
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null)
public function setFetchMode($fetchMode, ...$args)
{
$this->defaultFetchMode = $fetchMode;

Expand All @@ -130,30 +130,38 @@ public function getIterator()
/**
* {@inheritdoc}
*/
public function fetch($fetchMode = null, $cursorOrientation = \PDO::FETCH_ORI_NEXT, $cursorOffset = 0)
public function fetch($fetchMode = null, ...$args)
{
if ($this->data === null) {
$this->data = [];
}

$row = $this->statement->fetch(PDO::FETCH_ASSOC);
$row = $this->statement->fetch(FetchMode::ASSOCIATIVE);

if ($row) {
$this->data[] = $row;

$fetchMode = $fetchMode ?: $this->defaultFetchMode;

if ($fetchMode == PDO::FETCH_ASSOC) {
if ($fetchMode == FetchMode::ASSOCIATIVE) {
return $row;
} elseif ($fetchMode == PDO::FETCH_NUM) {
}

if ($fetchMode == FetchMode::NUMERIC) {
return array_values($row);
} elseif ($fetchMode == PDO::FETCH_BOTH) {
}

if ($fetchMode == FetchMode::MIXED) {
return array_merge($row, array_values($row));
} elseif ($fetchMode == PDO::FETCH_COLUMN) {
}

if ($fetchMode == FetchMode::COLUMN) {
return reset($row);
} else {
throw new \InvalidArgumentException("Invalid fetch-style given for caching result.");
}

throw new \InvalidArgumentException('Invalid fetch-style given for caching result.');
}

$this->emptied = true;

return false;
Expand All @@ -162,10 +170,10 @@ public function fetch($fetchMode = null, $cursorOrientation = \PDO::FETCH_ORI_NE
/**
* {@inheritdoc}
*/
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null)
public function fetchAll($fetchMode = null, ...$args)
{
$rows = [];
while ($row = $this->fetch($fetchMode)) {
while ($row = $this->fetch($fetchMode, ...$args)) {
$rows[] = $row;
}

Expand All @@ -177,7 +185,8 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n
*/
public function fetchColumn($columnIndex = 0)
{
$row = $this->fetch(PDO::FETCH_NUM);
$row = $this->fetch(FetchMode::NUMERIC);

if (!isset($row[$columnIndex])) {
// TODO: verify this is correct behavior
return false;
Expand Down
30 changes: 30 additions & 0 deletions lib/Doctrine/DBAL/ColumnCase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Doctrine\DBAL;

/**
* Contains portable column case conversions.
*/
class ColumnCase
{
/**
* Convert column names to upper case.
*
* @see \PDO::CASE_UPPER
*/
public const UPPER = 1;

/**
* Convert column names to lower case.
*
* @see \PDO::CASE_LOWER
*/
public const LOWER = 2;

/**
* This class cannot be instantiated.
*/
final private function __construct()
{
}
}
Loading

0 comments on commit 7fb41ab

Please sign in to comment.