Skip to content

Commit

Permalink
Merge pull request #44 from facile-it/full-statement-support
Browse files Browse the repository at this point in the history
Full Statement support. Fixes #43
  • Loading branch information
thomasvargiu authored Jan 7, 2021
2 parents 42e550f + 19b8ae9 commit 660ac11
Show file tree
Hide file tree
Showing 9 changed files with 314 additions and 433 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [1.9.0] - TBD
## [1.10.0] - TBD
### Added
* Added compatibility with doctrine/dbal > 2.11 Statement
* Added ability to reconnect when creating `Mysqli` statement
### Changed
* `Statement` now extends the original one, so all methods are implemented now
* `Connection::refresh()` is deprecated, you should use the original `Connection::ping()`

## [1.9.0] - 2020-11-02
### Added
* Added compatibility with doctrine/dbal 2.11
* Added Github Actions for CI
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ RUN set -ex \
autoconf \
make \
g++ \
&& pecl install -o xdebug-2.9.8 && docker-php-ext-enable xdebug \
&& pecl install -o xdebug-3.0.2 && docker-php-ext-enable xdebug \
&& apk del build-dependencies

ARG COMPOSER_VERSION=2.0.3
ARG COMPOSER_VERSION=2.0.8
RUN curl -sS https://getcomposer.org/installer | php -- \
--install-dir=/usr/local/bin --filename=composer --version=$COMPOSER_VERSION
23 changes: 10 additions & 13 deletions src/ConnectionTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Doctrine\DBAL\Connection as DBALConnection;
use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\FetchMode;
use Exception;
use Facile\DoctrineMySQLComeBack\Doctrine\DBAL\Driver\ServerGoneAwayExceptionsAwareInterface;
use ReflectionClass;
Expand All @@ -26,6 +27,9 @@ trait ConnectionTrait
/** @var ReflectionProperty|null */
private $selfReflectionNestingLevelProperty;

/** @var int */
protected $defaultFetchMode = FetchMode::ASSOCIATIVE;

/**
* @param array $params
* @param Driver|ServerGoneAwayExceptionsAwareInterface $driver
Expand Down Expand Up @@ -205,24 +209,17 @@ public function prepare($sql)
*/
protected function prepareWrapped($sql)
{
return new Statement($sql, $this);
}
$stmt = new Statement($sql, $this);
$stmt->setFetchMode($this->defaultFetchMode);

/**
* do not use, only used by Statement-class
* needs to be public for access from the Statement-class.
*
* @internal
*/
public function prepareUnwrapped($sql)
{
// returns the actual statement
return parent::prepare($sql);
return $stmt;
}

/**
* Forces reconnection by doing a dummy query.
*
* @deprecated Use ping()
*
* @throws Exception
*/
public function refresh()
Expand All @@ -231,7 +228,7 @@ public function refresh()
}

/**
* @param $attempt
* @param int $attempt
* @param bool $ignoreTransactionLevel
*
* @return bool
Expand Down
171 changes: 45 additions & 126 deletions src/Statement.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,67 @@

namespace Facile\DoctrineMySQLComeBack\Doctrine\DBAL;

use Doctrine\DBAL\Driver\Statement as DriverStatement;
use IteratorAggregate;
use PDO;
use Traversable;
use Doctrine\DBAL\ParameterType;

/**
* Class Statement.
* @internal
*/
class Statement implements IteratorAggregate, DriverStatement
class Statement extends \Doctrine\DBAL\Statement
{
/**
* @var string
* The connection this statement is bound to and executed on.
*
* @var Connection
*/
protected $sql;
protected $conn;

/**
* @var \Doctrine\DBAL\Statement
* @var mixed[][]
*/
protected $stmt;
private $boundValues = [];

/**
* @var Connection
* @var mixed[][]
*/
protected $conn;

private $boundValues = [];

private $boundParams = [];

private $fetchMode;

/**
* @param $sql
* @param ConnectionInterface $conn
* @var mixed[]|null
*/
public function __construct($sql, ConnectionInterface $conn)
{
$this->sql = $sql;
$this->conn = $conn;
$this->createStatement();
}
private $fetchMode;

/**
* Create Statement.
* @param $sql
* @param Connection $conn
*/
private function createStatement()
public function __construct($sql, Connection $conn)
{
$this->stmt = $this->conn->prepareUnwrapped($this->sql);
// Mysqli executes statement on Statement constructor, so we should retry to reconnect here too
$attempt = 0;
$retry = true;
while ($retry) {
$retry = false;
try {
parent::__construct($sql, $conn);
} catch (\Exception $e) {
if ($conn->canTryAgain($attempt) && $conn->isRetryableException($e, $sql)) {
$conn->close();
++$attempt;
$retry = true;
} else {
throw $e;
}
}
}
}

/**
* Recreate statement for retry.
*/
private function recreateStatement()
{
$this->createStatement();
$this->stmt = $this->conn->getWrappedConnection()->prepare($this->sql);

if (null !== $this->fetchMode) {
call_user_func_array([$this->stmt, 'setFetchMode'], $this->fetchMode);
}
Expand All @@ -86,7 +91,7 @@ public function execute($params = null)
while ($retry) {
$retry = false;
try {
$stmt = $this->stmt->execute($params);
$stmt = parent::execute($params);
} catch (\Exception $e) {
if ($this->conn->canTryAgain($attempt) && $this->conn->isRetryableException($e, $this->sql)) {
$this->conn->close();
Expand All @@ -109,9 +114,9 @@ public function execute($params = null)
*
* @return bool
*/
public function bindValue($name, $value, $type = PDO::PARAM_STR)
public function bindValue($name, $value, $type = ParameterType::STRING)
{
if ($this->stmt->bindValue($name, $value, $type)) {
if (parent::bindValue($name, $value, $type)) {
$this->boundValues[$name] = [$name, $value, $type];

return true;
Expand All @@ -121,17 +126,17 @@ public function bindValue($name, $value, $type = PDO::PARAM_STR)
}

/**
* @param string $name
* @param mixed $var
* @param string|int $param
* @param mixed $variable
* @param int $type
* @param int|null $length
*
* @return bool
*/
public function bindParam($name, &$var, $type = PDO::PARAM_STR, $length = null)
public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null)
{
if ($this->stmt->bindParam($name, $var, $type, $length)) {
$this->boundParams[$name] = [$name, &$var, $type, $length];
if (parent::bindParam($param, $variable, $type, $length)) {
$this->boundParams[$param] = [$param, &$variable, $type, $length];

return true;
}
Expand All @@ -140,38 +145,8 @@ public function bindParam($name, &$var, $type = PDO::PARAM_STR, $length = null)
}

/**
* @return bool
*/
public function closeCursor()
{
return $this->stmt->closeCursor();
}

/**
* @return int
*/
public function columnCount()
{
return $this->stmt->columnCount();
}

/**
* @return int
*/
public function errorCode()
{
return $this->stmt->errorCode();
}

/**
* @return array
*/
public function errorInfo()
{
return $this->stmt->errorInfo();
}

/**
* @deprecated Use one of the fetch- or iterate-related methods.
*
* @param int $fetchMode
* @param mixed $arg2
* @param mixed $arg3
Expand All @@ -180,68 +155,12 @@ public function errorInfo()
*/
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null)
{
if ($this->stmt->setFetchMode($fetchMode, $arg2, $arg3)) {
if (parent::setFetchMode($fetchMode, $arg2, $arg3)) {
$this->fetchMode = [$fetchMode, $arg2, $arg3];

return true;
}

return false;
}

/**
* @return Traversable
*/
public function getIterator()
{
return $this->stmt;
}

/**
* @param int|null $fetchMode
* @param int $cursorOrientation Only for doctrine/DBAL >= 2.6
* @param int $cursorOffset Only for doctrine/DBAL >= 2.6
* @return mixed
*/
public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0)
{
return $this->stmt->fetch($fetchMode, $cursorOrientation, $cursorOffset);
}

/**
* @param int|null $fetchMode
* @param int $fetchArgument Only for doctrine/DBAL >= 2.6
* @param null $ctorArgs Only for doctrine/DBAL >= 2.6
* @return mixed
*/
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null)
{
return $this->stmt->fetchAll($fetchMode, $fetchArgument, $ctorArgs);
}

/**
* @param int $columnIndex
*
* @return mixed
*/
public function fetchColumn($columnIndex = 0)
{
return $this->stmt->fetchColumn($columnIndex);
}

/**
* @return int
*/
public function rowCount()
{
return $this->stmt->rowCount();
}

/**
* @return \Doctrine\DBAL\Statement
*/
public function getWrappedStatement()
{
return $this->stmt;
}
}
Loading

0 comments on commit 660ac11

Please sign in to comment.