Skip to content

Commit

Permalink
Fix #692: Remove PDO from interfaces (#697)
Browse files Browse the repository at this point in the history
  • Loading branch information
samdark committed Apr 11, 2023
1 parent 5964596 commit 1582e80
Show file tree
Hide file tree
Showing 14 changed files with 113 additions and 75 deletions.
15 changes: 8 additions & 7 deletions UPGRADE.md
@@ -1,13 +1,14 @@
Upgrading Instructions for Yii Framework Database 3.0
=====================================================
# Upgrading Instructions for Yii Database

This file contains the upgrade notes for the database layer Yii 3.0.
These notes highlight changes that could break your application when you upgrade Yii from one version to another.
This file contains the upgrade notes for the Yii Database.
These notes highlight changes that could break your application when you upgrade it from one version to another.
Even though we try to ensure backwards compatibility (BC) as much as possible, sometimes
it is not possible or very complicated to avoid it and still create a good solution to
it isn't possible or very complicated to avoid it and still create a good solution to
a problem. While upgrade to Yii 3.0 might require substantial changes to both your application and extensions,
the changes are bearable and require "refactoring", not "rewrite".
All the "Yes, it is" cool stuff and Yii soul are still in place.
All the "Yes, it is" cool stuff, and Yii soul is still in place.

Changes summary:
* `Yiisoft\Db\Connection::$charset` has been removed. All support PDO classes allow you to specify the connection charset in the DSN.

* `Yiisoft\Db\Connection::$charset` has been removed. All supported PDO classes allow you to specify the connection
charset in the DSN.
3 changes: 1 addition & 2 deletions docs/en/README.md
Expand Up @@ -6,8 +6,7 @@ It's designed to be flexible and extensible,
so that it can be used with different databases and different database schemas.
Its database agnostic nature makes it easy to switch from one database to another.

Built on top of [PDO](https://www.php.net/manual/en/book.pdo.php), Yii DB provides an object-oriented API for accessing
relational databases.
Yii DB provides an object-oriented API for accessing relational databases.
It's the foundation for other more advanced database access methods, including [Query Builder](query-builder.md).

When using Yii DB, you mainly need to deal with plain SQLs and PHP arrays.
Expand Down
13 changes: 7 additions & 6 deletions docs/en/queries/transactions.md
Expand Up @@ -9,6 +9,7 @@ declare(strict_types=1);

use Yiisoft\Db\Connection\ConnectionInterface;
use Yiisoft\Db\Query\Query;
use Yiisoft\Db\Command\DataType;

/** @var ConnectionInterface $db */

Expand All @@ -23,12 +24,12 @@ try {

$insertTagCommand = $db
->createCommand("INSERT INTO {{%tags}} ([[id]], [[name]]) VALUES (:id, :name)")
->bindParam(':id', $id, PDO::PARAM_INT)
->bindParam(':name', $name, PDO::PARAM_STR);
->bindParam(':id', $id, DataType::INTEGER)
->bindParam(':name', $name, DataType::STRING);

$insertPostTagCommand = $db
->createCommand("INSERT INTO {{%post_tag}} ([[tag_id]], [[post_id]]) VALUES (:tag_id, :post_id)")
->bindParam(':tag_id', $id, PDO::PARAM_INT)
->bindParam(':tag_id', $id, DataType::INTEGER)
->bindValue(':post_id', 1);

$tags = [
Expand Down Expand Up @@ -69,12 +70,12 @@ $db->transaction(function (ConnectionInterface $db) {

$insertTagCommand = $db
->createCommand("INSERT INTO {{%tags}} ([[id]], [[name]]) VALUES (:id, :name)")
->bindParam(':id', $id, PDO::PARAM_INT)
->bindParam(':name', $name, PDO::PARAM_STR);
->bindParam(':id', $id, DataType::INTEGER)
->bindParam(':name', $name, DataType::STRING);

$insertPostTagCommand = $db
->createCommand("INSERT INTO {{%post_tag}} ([[tag_id]], [[post_id]]) VALUES (:tag_id, :post_id)")
->bindParam(':tag_id', $id, PDO::PARAM_INT)
->bindParam(':tag_id', $id, DataType::INTEGER)
->bindValue(':post_id', 1);

$tags = [
Expand Down
18 changes: 7 additions & 11 deletions src/Command/CommandInterface.php
Expand Up @@ -6,7 +6,6 @@

use Closure;
use JsonException;
use PDOException;
use Throwable;
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidArgumentException;
Expand Down Expand Up @@ -188,14 +187,12 @@ public function batchInsert(string $table, array $columns, iterable $rows): stat
* a parameter name of the form `:name`. For a prepared statement using question mark placeholders, this will be the
* 1-indexed position of the parameter.
* @param mixed $value The PHP variable to bind to the SQL statement parameter (passed by reference).
* @param int|null $dataType The SQL data type of the parameter. If `null`, the type is determined by the PHP type of
* the value.
* @param int|null $dataType The {@see DataType SQL data type} of the parameter. If `null`, the type is determined
* by the PHP type of the value.
* @param int|null $length The length of the data type.
* @param mixed|null $driverOptions The driver-specific options.
*
* @throws Exception
*
* @link https://www.php.net/manual/en/function.PDOStatement-bindParam.php
*/
public function bindParam(
int|string $name,
Expand Down Expand Up @@ -224,8 +221,8 @@ public function addUnique(string $table, string $name, array|string $columns): s
* parameter name of the form `:name`. For a prepared statement using question mark placeholders, this will be the
* 1-indexed position of the parameter.
* @param mixed $value The value to bind to the parameter.
* @param int|null $dataType The SQL data type of the parameter. If null, the type is determined by the PHP type of
* the value.
* @param int|null $dataType The {@see DataType SQL data type} of the parameter. If null, the type is determined
* by the PHP type of the value.
*/
public function bindValue(int|string $name, mixed $value, int $dataType = null): static;

Expand All @@ -239,9 +236,9 @@ public function bindValue(int|string $name, mixed $value, int $dataType = null):
* @param array|ParamInterface[] $values The values to bind. This must be given in terms of an associative
* array with array keys being the parameter names, and an array values the corresponding parameter values,
* for example, `[':name' => 'John', ':age' => 25]`.
* By default, the {@see PDO} type of each value is determined by its PHP type. You may explicitly specify the
* {@see PDO} type by using a {@see Param} class: `new Param(value, type)`, for example,
* `[':name' => 'John', ':profile' => new Param($profile, PDO::PARAM_LOB)]`.
* By default, the SQL data type of each value is determined by its PHP type.
* You may explicitly specify the {@see DataType SQL data type} type by using a {@see Param} class:
* `new Param(value, type)`, for example, `[':name' => 'John', ':profile' => new Param($profile, DataType::LOB)]`.
*/
public function bindValues(array $values): static;

Expand Down Expand Up @@ -579,7 +576,6 @@ public function insertWithReturningPks(string $table, array $columns): bool|arra
*
* @throws Exception If there is any DB error.
* @throws InvalidConfigException
* @throws PDOException
*/
public function prepare(bool $forRead = null): void;

Expand Down
42 changes: 42 additions & 0 deletions src/Command/DataType.php
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Db\Command;

/**
* Types of data.
* Usually used when binding parameters.
*/
final class DataType
{
/**
* SQL `NULL` data type.
*/
public const NULL = 0;

/**
* SQL `INTEGER` data type.
*/
public const INTEGER = 1;

/**
* SQL `CHAR`, `VARCHAR`, or another string data type.
*/
public const STRING = 2;

/**
* SQL large object data type.
*/
public const LOB = 3;

/**
* Represents a recordset type. Not currently supported by any drivers.
*/
public const STMT = 4;

/**
* Boolean data type.
*/
public const BOOLEAN = 5;
}
2 changes: 0 additions & 2 deletions src/Connection/ConnectionInterface.php
Expand Up @@ -99,8 +99,6 @@ public function getDriverName(): string;
* @throws InvalidCallException
*
* @return string The row ID of the last row inserted, or the last value retrieved from the sequence object.
*
* @link https://php.net/manual/en/pdo.lastinsertid.php'>https://php.net/manual/en/pdo.lastinsertid.php
*/
public function getLastInsertID(string $sequenceName = null): string;

Expand Down
6 changes: 3 additions & 3 deletions src/Driver/Pdo/AbstractPdoCommand.php
Expand Up @@ -70,7 +70,7 @@ public function bindParam(
$this->prepare();

if ($dataType === null) {
$dataType = $this->db->getSchema()->getPdoType($value);
$dataType = $this->db->getSchema()->getDataType($value);
}

if ($length === null) {
Expand All @@ -87,7 +87,7 @@ public function bindParam(
public function bindValue(int|string $name, mixed $value, int|null $dataType = null): static
{
if ($dataType === null) {
$dataType = $this->db->getSchema()->getPdoType($value);
$dataType = $this->db->getSchema()->getDataType($value);
}

$this->params[$name] = new Param($value, $dataType);
Expand All @@ -108,7 +108,7 @@ public function bindValues(array $values): static
if ($value instanceof ParamInterface) {
$this->params[$name] = $value;
} else {
$type = $this->db->getSchema()->getPdoType($value);
$type = $this->db->getSchema()->getDataType($value);
$this->params[$name] = new Param($value, $type);
}
}
Expand Down
20 changes: 10 additions & 10 deletions src/Schema/AbstractColumnSchema.php
Expand Up @@ -4,7 +4,7 @@

namespace Yiisoft\Db\Schema;

use PDO;
use Yiisoft\Db\Command\DataType;
use Yiisoft\Db\Command\Param;
use Yiisoft\Db\Expression\ExpressionInterface;
use Yiisoft\Db\Helper\DbStringHelper;
Expand Down Expand Up @@ -275,7 +275,7 @@ protected function typecast(mixed $value): mixed
is_array($value)
&& count($value) === 2
&& isset($value[1])
&& in_array($value[1], $this->getPdoParamTypes(), true)
&& in_array($value[1], $this->getDataTypes(), true)
) {
return new Param((string) $value[0], $value[1]);
}
Expand Down Expand Up @@ -314,17 +314,17 @@ protected function typecast(mixed $value): mixed
}

/**
* @return int[] Array of numbers that represent possible PDO parameter types.
* @return int[] Array of numbers that represent possible parameter types.
*/
private function getPdoParamTypes(): array
private function getDataTypes(): array
{
return [
PDO::PARAM_BOOL,
PDO::PARAM_INT,
PDO::PARAM_STR,
PDO::PARAM_LOB,
PDO::PARAM_NULL,
PDO::PARAM_STMT,
DataType::BOOLEAN,
DataType::INTEGER,
DataType::STRING,
DataType::LOB,
DataType::NULL,
DataType::STMT,
];
}
}
18 changes: 9 additions & 9 deletions src/Schema/AbstractSchema.php
Expand Up @@ -4,10 +4,10 @@

namespace Yiisoft\Db\Schema;

use PDO;
use Psr\SimpleCache\InvalidArgumentException;
use Throwable;
use Yiisoft\Db\Cache\SchemaCache;
use Yiisoft\Db\Command\DataType;
use Yiisoft\Db\Connection\ConnectionInterface;
use Yiisoft\Db\Constraint\Constraint;
use Yiisoft\Db\Exception\NotSupportedException;
Expand Down Expand Up @@ -131,21 +131,21 @@ public function getDefaultSchema(): string|null
return $this->defaultSchema;
}

public function getPdoType(mixed $data): int
public function getDataType(mixed $data): int
{
/** @psalm-var array<string, int> $typeMap */
$typeMap = [
// php type => PDO type
SchemaInterface::PHP_TYPE_BOOLEAN => PDO::PARAM_BOOL,
SchemaInterface::PHP_TYPE_INTEGER => PDO::PARAM_INT,
SchemaInterface::PHP_TYPE_STRING => PDO::PARAM_STR,
SchemaInterface::PHP_TYPE_RESOURCE => PDO::PARAM_LOB,
SchemaInterface::PHP_TYPE_NULL => PDO::PARAM_NULL,
// php type => SQL data type
SchemaInterface::PHP_TYPE_BOOLEAN => DataType::BOOLEAN,
SchemaInterface::PHP_TYPE_INTEGER => DataType::INTEGER,
SchemaInterface::PHP_TYPE_STRING => DataType::STRING,
SchemaInterface::PHP_TYPE_RESOURCE => DataType::LOB,
SchemaInterface::PHP_TYPE_NULL => DataType::NULL,
];

$type = gettype($data);

return $typeMap[$type] ?? PDO::PARAM_STR;
return $typeMap[$type] ?? DataType::STRING;
}

public function getRawTableName(string $name): string
Expand Down
11 changes: 6 additions & 5 deletions src/Schema/SchemaInterface.php
Expand Up @@ -5,6 +5,7 @@
namespace Yiisoft\Db\Schema;

use Throwable;
use Yiisoft\Db\Command\DataType;
use Yiisoft\Db\Constraint\ConstraintSchemaInterface;
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidConfigException;
Expand Down Expand Up @@ -262,15 +263,15 @@ public function createColumn(string $type, array|int|string $length = null): Col
public function getDefaultSchema(): string|null;

/**
* Determines the PDO type for the given PHP data value.
* Determines the SQL data type for the given PHP data value.
*
* @param mixed $data The data to find PDO type for.
* @param mixed $data The data to find a type for.
*
* @return int The PDO type.
* @return int The type.
*
* @link https://www.php.net/manual/en/pdo.constants.php
* @see DataType
*/
public function getPdoType(mixed $data): int;
public function getDataType(mixed $data): int;

/**
* Returns the actual name of a given table name.
Expand Down
4 changes: 2 additions & 2 deletions tests/AbstractQueryBuilderTest.php
Expand Up @@ -7,10 +7,10 @@
use Closure;
use Generator;
use JsonException;
use PDO;
use PHPUnit\Framework\TestCase;
use stdClass;
use Throwable;
use Yiisoft\Db\Command\DataType;
use Yiisoft\Db\Command\Param;
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidArgumentException;
Expand Down Expand Up @@ -2245,7 +2245,7 @@ public function testOverrideParameters1(): void
$query->select('*')
->from('{{%animal}}')
->andWhere($expression)
->andWhere(['type' => new Param('test1', PDO::PARAM_STR)])
->andWhere(['type' => new Param('test1', DataType::STRING)])
;

$command = $query->createCommand();
Expand Down
24 changes: 12 additions & 12 deletions tests/AbstractSchemaTest.php
Expand Up @@ -4,8 +4,8 @@

namespace Yiisoft\Db\Tests;

use PDO;
use PHPUnit\Framework\TestCase;
use Yiisoft\Db\Command\DataType;
use Yiisoft\Db\Schema\Builder\ColumnInterface;
use Yiisoft\Db\Schema\SchemaInterface;
use Yiisoft\Db\Tests\Support\Assert;
Expand Down Expand Up @@ -45,18 +45,18 @@ public function testGetDefaultSchema(): void
$this->assertNull($schema->getDefaultSchema());
}

public function testGetPDOType(): void
public function testGetDataType(): void
{
$values = [
[null, PDO::PARAM_NULL],
['', PDO::PARAM_STR],
['hello', PDO::PARAM_STR],
[0, PDO::PARAM_INT],
[1, PDO::PARAM_INT],
[1337, PDO::PARAM_INT],
[true, PDO::PARAM_BOOL],
[false, PDO::PARAM_BOOL],
[$fp = fopen(__FILE__, 'rb'), PDO::PARAM_LOB],
[null, DataType::NULL],
['', DataType::STRING],
['hello', DataType::STRING],
[0, DataType::INTEGER],
[1, DataType::INTEGER],
[1337, DataType::INTEGER],
[true, DataType::BOOLEAN],
[false, DataType::BOOLEAN],
[$fp = fopen(__FILE__, 'rb'), DataType::LOB],
];

$db = $this->getConnection();
Expand All @@ -66,7 +66,7 @@ public function testGetPDOType(): void
foreach ($values as $value) {
$this->assertSame(
$value[1],
$schema->getPdoType($value[0]),
$schema->getDataType($value[0]),
'type for value ' . print_r($value[0], true) . ' does not match.',
);
}
Expand Down

0 comments on commit 1582e80

Please sign in to comment.