Skip to content

Commit

Permalink
Clean code PDO classes. (#551)
Browse files Browse the repository at this point in the history
  • Loading branch information
terabytesoftw committed Mar 1, 2023
1 parent 0e4337d commit c75ab66
Show file tree
Hide file tree
Showing 9 changed files with 52 additions and 136 deletions.
5 changes: 5 additions & 0 deletions src/Command/CommandInterface.php
Expand Up @@ -6,6 +6,7 @@

use Closure;
use JsonException;
use PDOException;
use Throwable;
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidArgumentException;
Expand Down Expand Up @@ -223,6 +224,8 @@ public function batchInsert(string $table, array $columns, iterable $rows): stat
* @throws Exception
*
* @return static The current command being executed.
*
* @link http://www.php.net/manual/en/function.PDOStatement-bindParam.php
*/
public function bindParam(
int|string $name,
Expand Down Expand Up @@ -604,6 +607,8 @@ public function insertWithReturningPks(string $table, array $columns): bool|arra
* should be used to determine whether it is for read or write.
*
* @throws Exception If there is any DB error.
* @throws InvalidConfigException
* @throws PDOException
*/
public function prepare(bool $forRead = null): void;

Expand Down
21 changes: 5 additions & 16 deletions src/Driver/PDO/AbstractCommandPDO.php
Expand Up @@ -12,7 +12,6 @@
use Yiisoft\Db\Command\Param;
use Yiisoft\Db\Command\ParamInterface;
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidConfigException;
use Yiisoft\Db\Exception\InvalidParamException;
use Yiisoft\Db\Query\Data\DataReader;

Expand All @@ -32,7 +31,6 @@ public function __construct(protected ConnectionPDOInterface $db)
}

/**
* @inheritDoc
* This method mainly sets {@see pdoStatement} to be null.
*/
public function cancel(): void
Expand All @@ -45,11 +43,6 @@ public function getPdoStatement(): PDOStatement|null
return $this->pdoStatement;
}

/**
* @inheritDoc
*
* @link http://www.php.net/manual/en/function.PDOStatement-bindParam.php
*/
public function bindParam(
int|string $name,
mixed &$value,
Expand Down Expand Up @@ -106,11 +99,6 @@ public function bindValues(array $values): static
return $this;
}

/**
* @throws Exception
* @throws InvalidConfigException
* @throws PDOException
*/
public function prepare(bool|null $forRead = null): void
{
if (isset($this->pdoStatement)) {
Expand All @@ -120,6 +108,7 @@ public function prepare(bool|null $forRead = null): void
}

$sql = $this->getSql();

/**
* If sql is empty - will be {@see \ValueError} on prepare pdoStatement
*
Expand All @@ -136,7 +125,7 @@ public function prepare(bool|null $forRead = null): void
$this->bindPendingParams();
} catch (PDOException $e) {
$message = $e->getMessage() . "\nFailed to prepare SQL: $sql";
/** @var array|null */
/** @psalm-var array|null $errorInfo */
$errorInfo = $e->errorInfo ?? null;

throw new Exception($message, $errorInfo, $e);
Expand Down Expand Up @@ -184,13 +173,13 @@ protected function internalGetQueryResult(int $queryMode): mixed
/** @psalm-var array|false $result */
$result = $this->pdoStatement?->fetch(PDO::FETCH_ASSOC);
} elseif ($this->is($queryMode, self::QUERY_MODE_COLUMN)) {
/** @var mixed */
/** @psalm-var mixed $result */
$result = $this->pdoStatement?->fetchAll(PDO::FETCH_COLUMN);
} elseif ($this->is($queryMode, self::QUERY_MODE_ALL)) {
/** @var mixed */
/** @psalm-var mixed $result */
$result = $this->pdoStatement?->fetchAll(PDO::FETCH_ASSOC);
} else {
throw new InvalidParamException("Unknown query mode '{$queryMode}'");
throw new InvalidParamException("Unknown query mode '$queryMode'");
}

$this->pdoStatement?->closeCursor();
Expand Down
2 changes: 1 addition & 1 deletion src/Driver/PDO/AbstractConnectionPDO.php
Expand Up @@ -138,7 +138,7 @@ public function getPDO(): PDO|null

public function getLastInsertID(string $sequenceName = null): string
{
if ($this->isActive() && $this->pdo) {
if ($this->pdo !== null) {
return $this->pdo->lastInsertID($sequenceName ?? null);
}

Expand Down
51 changes: 0 additions & 51 deletions src/Driver/PDO/AbstractPDODriver.php
Expand Up @@ -25,13 +25,6 @@ public function __construct(
) {
}

/**
* PDO attributes (name => value) that should be set when calling {@see open()} to establish a DB connection.
* Please refer to the [PHP manual](http://php.net/manual/en/pdo.setattribute.php) for details about available
* attributes.
*
* @param array $attributes the attributes (name => value) to be set on the DB connection.
*/
public function attributes(array $attributes): void
{
$this->attributes = $attributes;
Expand All @@ -42,80 +35,36 @@ public function createConnection(): PDO
return new PDO($this->dsn, $this->username, $this->password, $this->attributes);
}

/**
* The charset used for database connection. The property is only used for MySQL, PostgresSQL databases. Defaults to
* null, meaning using default charset as configured by the database.
*
* For Oracle Database, the charset must be specified in the {@see dsn}, for example for UTF-8 by appending
* `;charset=UTF-8` to the DSN string.
*
* The same applies for if you're using GBK or BIG5 charset with MySQL, then it's highly recommended specifying
* charset via {@see dsn} like `'mysql:dbname=database;host=127.0.0.1;charset=GBK;'`.
*
* @param string|null $charset
*/
public function charset(string|null $charset): void
{
$this->charset = $charset;
}

/**
* Returns the charset currently used for database connection. The returned charset is only applicable for MySQL,
* PostgresSQL databases.
*
* @return string|null the charset of the pdo instance. Null is returned if the charset is not set yet or not
* supported by the pdo driver
*/
public function getCharset(): string|null
{
return $this->charset;
}

abstract public function getDriverName(): string;

/**
* Return dsn string for current driver.
*/
public function getDsn(): string
{
return $this->dsn;
}

/**
* Returns the password for establishing DB connection.
*
* @return string the password for establishing DB connection.
*/
public function getPassword(): string
{
return $this->password;
}

/**
* Returns the username for establishing DB connection.
*
* @return string the username for establishing DB connection.
*/
public function getUsername(): string
{
return $this->username;
}

/**
* The password for establishing DB connection. Defaults to `null` meaning no password to use.
*
* @param string $password the password for establishing DB connection.
*/
public function password(string $password): void
{
$this->password = $password;
}

/**
* The username for establishing DB connection. Defaults to `null` meaning no username to use.
*
* @param string $username the username for establishing DB connection.
*/
public function username(string $username): void
{
$this->username = $username;
Expand Down
48 changes: 10 additions & 38 deletions src/Driver/PDO/AbstractTransactionPDO.php
Expand Up @@ -31,27 +31,20 @@
* throw $e;
* }
* ```
*
* @property bool $isActive Whether this transaction is active. Only an active transaction can {@see commit()} or
* {@see rollBack()}. This property is read-only.
* @property string $isolationLevel The transaction isolation level to use for this transaction. This can be one of
* {@see READ_UNCOMMITTED}, {@see READ_COMMITTED}, {@see REPEATABLE_READ} and {@see SERIALIZABLE} but also a string
* containing DBMS specific syntax to be used after `SET TRANSACTION ISOLATION LEVEL`. This property is write-only.
* @property int $level The current nesting level of the transaction. This property is read-only.
*/
abstract class AbstractTransactionPDO implements TransactionInterface
{
use LoggerAwareTrait;

/**
* @var int The nesting level of the transaction.
*/
private int $level = 0;

public function __construct(protected ConnectionPDOInterface $db)
{
}

/**
* @inheritDoc
*/
public function begin(string $isolationLevel = null): void
{
$this->db->open();
Expand Down Expand Up @@ -89,16 +82,14 @@ public function begin(string $isolationLevel = null): void
$this->level++;
}

/**
* @inheritDoc
*/
public function commit(): void
{
if (!$this->isActive()) {
throw new Exception('Failed to commit transaction: transaction was inactive.');
}

$this->level--;

if ($this->level === 0) {
$this->logger?->log(LogLevel::DEBUG, 'Commit transaction ' . __METHOD__);
$this->db->getPDO()?->commit();
Expand All @@ -117,28 +108,17 @@ public function commit(): void
}
}

/**
* @inheritDoc
*/
public function getLevel(): int
{
return $this->level;
}

/**
* @inheritDoc
*/
public function isActive(): bool
{
/** Additional check pdo->inTransaction {@see https://github.com/yiisoft/yii2/pull/18407/} */
return $this->level > 0 && $this->db->isActive() && $this->db->getPDO()?->inTransaction();
}

/**
* @inheritDoc
*
* @throws Exception|InvalidConfigException|Throwable
*/
public function rollBack(): void
{
if (!$this->isActive()) {
Expand All @@ -150,6 +130,7 @@ public function rollBack(): void
}

$this->level--;

if ($this->level === 0) {
$this->logger?->log(LogLevel::INFO, 'Roll back transaction ' . __METHOD__);
$this->db->getPDO()?->rollBack();
Expand All @@ -168,9 +149,6 @@ public function rollBack(): void
}
}

/**
* @inheritDoc
*/
public function setIsolationLevel(string $level): void
{
if (!$this->isActive()) {
Expand All @@ -184,13 +162,6 @@ public function setIsolationLevel(string $level): void
$this->setTransactionIsolationLevel($level);
}

/**
* Creates a new savepoint.
*
* @param string $name the savepoint name
*
* @throws Exception|InvalidConfigException|Throwable
*/
public function createSavepoint(string $name): void
{
$this->db->createCommand("SAVEPOINT $name")->execute();
Expand All @@ -201,16 +172,17 @@ public function rollBackSavepoint(string $name): void
$this->db->createCommand("ROLLBACK TO SAVEPOINT $name")->execute();
}

/**
* @inheritDoc
*/
public function releaseSavepoint(string $name): void
{
$this->db->createCommand("RELEASE SAVEPOINT $name")->execute();
}

/**
* @throws Exception|InvalidConfigException|Throwable
* Sets the transaction isolation level.
*
* @throws Exception
* @throws InvalidConfigException
* @throws Throwable
*/
protected function setTransactionIsolationLevel(string $level): void
{
Expand Down
4 changes: 2 additions & 2 deletions src/Driver/PDO/ConnectionPDOInterface.php
Expand Up @@ -18,7 +18,7 @@ interface ConnectionPDOInterface extends ConnectionInterface
/**
* Returns the PDO instance for the current connection.
*
* This method will open the DB connection and then return {@see pdo}.
* This method will open the DB connection and then return {@see PDO}.
*
* @throws Exception
* @throws InvalidConfigException
Expand All @@ -34,7 +34,7 @@ public function getActivePDO(string $sql = '', bool $forRead = null): PDO|null;
*
* @return PDO|null The PHP PDO instance associated with this DB connection.
*
* {@see pdoClass}
* {@see PDO}
*/
public function getPDO(): PDO|null;

Expand Down
7 changes: 4 additions & 3 deletions src/Driver/PDO/ConnectionPDOPoolInterface.php
Expand Up @@ -11,6 +11,7 @@

/**
* The ConnectionPDOPoolInterface describes creating a connection pool of PDO (PHP Data Objects) connections.
*
* It defines methods for managing the connections in the pool, such as getting and releasing connections, as well as
* methods for checking the pool's configuration and status. By implementing this interface, developers can create
* custom connection pool classes that can be used with the yiisoft/db library to handle PDO connections in a more
Expand All @@ -25,7 +26,7 @@ interface ConnectionPDOPoolInterface extends ConnectionPoolInterface
*
* @throws Exception|InvalidConfigException
*
* @return PDO|null the PDO instance for the currently active master connection.
* @return PDO|null The PDO instance for the currently active master connection.
*/
public function getMasterPDO(): PDO|null;

Expand All @@ -35,11 +36,11 @@ public function getMasterPDO(): PDO|null;
* When {@see enableSlaves} is true, one of the slaves will be used for read queries, and its PDO instance will be
* returned by this method.
*
* @param bool $fallbackToMaster whether to return a master PDO in case none of the slave connections is available.
* @param bool $fallbackToMaster Whether to return a master PDO in case none of the slave connections is available.
*
* @throws Exception
*
* @return PDO|null the PDO instance for the currently active slave connection. `null` is returned if no slave
* @return PDO|null The PDO instance for the currently active slave connection. `null` is returned if no slave
* connection is available and `$fallbackToMaster` is false.
*/
public function getSlavePDO(bool $fallbackToMaster = true): ?PDO;
Expand Down

0 comments on commit c75ab66

Please sign in to comment.