Skip to content

Commit

Permalink
Add StatementCursor;
Browse files Browse the repository at this point in the history
Statement recreation searches the cursor position is its not at 0;
Add switch-case block to handle reconnecting pre-tasks of basic PDOStatement calls;
Fix namespace Legow to LegoW;
  • Loading branch information
adamturcsan committed Nov 14, 2016
1 parent 7a357cc commit 89df08d
Show file tree
Hide file tree
Showing 14 changed files with 413 additions and 61 deletions.
3 changes: 2 additions & 1 deletion .gitignore
@@ -1,3 +1,4 @@
/vendor/
/tmp/
/test/configuration.xml
/test/configuration.xml
/phpunit-xdebug
2 changes: 2 additions & 0 deletions README.md
@@ -1,2 +1,4 @@
[![Build Status](https://travis-ci.org/adamturcsan/reconnecting-pdo.svg?branch=master)](https://travis-ci.org/adamturcsan/reconnecting-pdo)
[![Coverage Status](https://coveralls.io/repos/github/adamturcsan/reconnecting-pdo/badge.svg?branch=feature%2Freconnecting-statement)](https://coveralls.io/github/adamturcsan/reconnecting-pdo?branch=feature%2Freconnecting-statement)
# reconnecting-pdo
PDO object which can reconnect if server has gone away
2 changes: 1 addition & 1 deletion composer.json
Expand Up @@ -22,7 +22,7 @@
},
"autoload": {
"psr-4": {
"Legow\\ReconnectingPDO\\": "src/"
"LegoW\\ReconnectingPDO\\": "src/"
}
},
"require-dev": {
Expand Down
2 changes: 1 addition & 1 deletion src/ConnectionParametersMissingException.php
Expand Up @@ -7,7 +7,7 @@
* @license https://opensource.org/licenses/MIT MIT License
*/

namespace Legow\ReconnectingPDO;
namespace LegoW\ReconnectingPDO;

/**
* Description of ConnectionParametersMissingException
Expand Down
20 changes: 20 additions & 0 deletions src/CursorException.php
@@ -0,0 +1,20 @@
<?php

/*
* LegoW\ReconnectingPDO (https://github.com/adamturcsan/reconnecting-pdo)
*
* @copyright Copyright (c) 2014-2016 Legow Hosting Kft. (http://www.legow.hu)
* @license https://opensource.org/licenses/MIT MIT License
*/

namespace LegoW\ReconnectingPDO;

/**
* Description of CursorException
*
* @author Turcsán Ádám <turcsan.adam@legow.hu>
*/
class CursorException extends \Exception
{
//put your code here
}
2 changes: 1 addition & 1 deletion src/ExceededMaxReconnectionException.php
Expand Up @@ -7,7 +7,7 @@
* @license https://opensource.org/licenses/MIT MIT License
*/

namespace Legow\ReconnectingPDO;
namespace LegoW\ReconnectingPDO;

/**
* Description of ExceededMaxReconnectionException
Expand Down
6 changes: 3 additions & 3 deletions src/ReconnectingPDO.php
Expand Up @@ -7,7 +7,7 @@
* @license https://opensource.org/licenses/MIT MIT License
*/

namespace Legow\ReconnectingPDO;
namespace LegoW\ReconnectingPDO;

use PDO;

Expand All @@ -19,7 +19,7 @@
*
* @author Turcsán Ádám <turcsan.adam@legow.hu>
* @method PDOStatement|bool prepare(string $statement, array $driver_options = 'array()' [optional]) Prepares a statement for execution and returns a statement object
* @method bool beginTransaction(type $paramName) Initiates a transaction
* @method bool beginTransaction() Initiates a transaction
* @method bool commit() Commits a transaction
* @method bool rollBack() Rolls back a transaction
* @method bool inTransaction() Checks if inside a transaction
Expand Down Expand Up @@ -128,7 +128,7 @@ protected function call($method, $arguments)
}
}
if($returnValue instanceof \PDOStatement) {
return new ReconnectingPDOStatement($returnValue, $this, $this->maxReconnection);
return new ReconnectingPDOStatement($returnValue, $this);
}
return $returnValue;
}
Expand Down
2 changes: 1 addition & 1 deletion src/ReconnectingPDOException.php
Expand Up @@ -7,7 +7,7 @@
* @license https://opensource.org/licenses/MIT MIT License
*/

namespace Legow\ReconnectingPDO;
namespace LegoW\ReconnectingPDO;

/**
* Description of ReconnectingPDOException
Expand Down
130 changes: 87 additions & 43 deletions src/ReconnectingPDOStatement.php
Expand Up @@ -7,24 +7,25 @@
* @license https://opensource.org/licenses/MIT MIT License
*/

namespace Legow\ReconnectingPDO;
namespace LegoW\ReconnectingPDO;

use Legow\ReconnectingPDO\ReconnectingPDO;
use \PDOStatement;
use LegoW\ReconnectingPDO\ReconnectingPDO;
use LegoW\ReconnectingPDO\StatementCursor;
use PDOStatement;
use PDO;

/**
* Description of ReconnectingPDOStatement
*
* @author Turcsán Ádám <turcsan.adam@legow.hu>
* @method bool execute(array $parameters = null [optional]) Executes a prepared statement
* @method mixed fetch(int $fetchType = null [optional], int $cursor_orientation = PDO::FETCH_ORI_NEXT [optional], int $cursor_offset = 0 [optional]) Fetches the next row from a result set
* @method bool bindParam(mixed $parameter, mixed &$variable, int $dataType = PDO::PARAM_STR [optional], int $length = null [optional], $driver_options = null [optional]) Binds a parameter to the specified variable name
* @method bool bindColumn(mixed $column, mixed &$param, int $type = null [optional], int $maxlen = null [optional], $driverdata = null [optional]) Bind a column to a PHP variable
* @method bool bindValue(mixed $parameter, mixed $value, int $data_type = PDO::PARAM_STR [optional]) Binds a value to a parameter
* @method int rowCount() Returns the number of rows affected by the last SQL statement
*/
class ReconnectingPDOStatement
{

/**
* @var PDOStatement
*/
Expand All @@ -40,26 +41,52 @@ class ReconnectingPDOStatement
*/
protected $queryString;

/**
* @var StatementCursor
*/
protected $cursor;

/**
* @var array
*/
protected $seedData = [];

/**
* @var bool
*/
protected $executed = false;

/**
* @return \PDOStatement
*/
public function getPDOStatement()
{
return $this->statement;
}

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

/**
*
* @param PDOStatement $statement
* @param ReconnectingPDO $connection
*/
public function __construct(PDOStatement $statement, ReconnectingPDO $connection)
public function __construct(PDOStatement $statement,
ReconnectingPDO $connection, StatementCursor $cursor = null)
{
$this->statement = $statement;
$this->queryString = $statement->queryString;
$this->connection = $connection;
if ($cursor == null) {
$cursor = new StatementCursor();
}
$this->cursor = $cursor;
}

/**
Expand All @@ -70,21 +97,13 @@ public function __construct(PDOStatement $statement, ReconnectingPDO $connection
*/
public function __call($method, $arguments)
{
if(substr($method, 0, 4) == 'bind' && $method != 'bindColumn') {
if ($method == 'bindParam' || $method == 'bindValue') {
$key = $arguments[0];
$this->seedData[$method][$key] = $arguments;
return $this->call($method, $this->seedData[$method][$key]);
} elseif( $method == 'execute' ) {
$this->executed = true;
}
return $this->call($method, $arguments); // Avoid direct calling of magic method
}

public function bindColumn($column, &$param, $type = null, $maxlen = null, $driverdata = null)
{
$this->seedData['bindColumn'][$column] = &$param;
return $this->statement->bindColumn($column, $param, $type, $maxlen, $driverdata);
}

/**
* @param string $method
Expand All @@ -95,8 +114,22 @@ public function bindColumn($column, &$param, $type = null, $maxlen = null, $driv
protected function call($method, &$arguments)
{
try {
if($method == 'bindParam'){
return $this->statement->bindParam(...$arguments);
switch ($method) {
//Differenct method handlers
case 'bindParam':
return $this->statement->bindParam(...$arguments);
//Pre-call
case 'fetch':
case 'fetchAll':
case 'fetchColumn':
case 'fetchObject':
$this->trackCursor($method);
break;
case 'execute':
$this->executed = true;
break;
default:
break;
}
return call_user_func_array([$this->statement, $method], $arguments);
} catch (\PDOException $ex) {
Expand All @@ -109,53 +142,64 @@ protected function call($method, &$arguments)
}
}

protected function recreateStatement() {
protected function recreateStatement()
{
$shouldBeExecuted = $this->executed;
/* @var $reconnectingstatement ReconnectingPDOStatement */
$reconnectingstatement = $this->connection->prepare($this->queryString);
$this->executed = false;
$statement = $reconnectingstatement->getPDOStatement();
if(!empty($this->seedData)) {
/* @var $method string bindParam, bindColumn or bindValue*/
foreach($this->seedData as $method => $arguments) {
if (!empty($this->seedData)) {
/* @var $method string bindParam, bindColumn or bindValue */
foreach ($this->seedData as $method => $arguments) {
/* @var $key string Parameter name */
foreach($arguments as $key => $params) {
list($name, , $paramType) = $params; // Value comes from the seedData array, because it only takes it by reference
$statement->$key($name, $this->seedData[$method][$key][1], $paramType);
foreach ($arguments as $key => $params) {
list($name,, $paramType) = $params;
// Value comes from the seedData array, because bindParam only takes it by reference
$statement->$method($name,
$this->seedData[$method][$key][1], $paramType);
}
}
}
$this->statement = $statement;
if($shouldBeExecuted) {
if ($shouldBeExecuted) {
$this->execute();
$this->searchPosition();
}
}

/**
* @return \PDOStatement
*/
public function getPDOStatement()

protected function trackCursor()
{
return $this->statement;
$this->cursor->next();
}

/**
* @return bool
*/
public function isExecuted()

protected function searchPosition()
{
return $this->executed;
$position = $this->cursor->getPosition();
while ($this->cursor->prev()->getPosition() && $this->statement->fetch()) {
//Nothing to do here.
}
$this->cursor->setPosition($position);
}

public function fetch()

public function bindColumn($column, &$param, $type = null, $maxlen = null,
$driverdata = null)
{
$this->seedData['bindColumn'][$column] = &$param;
return $this->statement->bindColumn($column, $param, $type, $maxlen,
$driverdata);
}

public function fetch($fetchType = null,
$cursor_orientation = PDO::FETCH_ORI_NEXT, $cursor_offset = 0)
{
$args = func_get_args();
$result = $this->call('fetch', $args);
if(isset($this->seedData['bindColumn']) && count($this->seedData['bindColumn'])) {
foreach($this->seedData['bindColumn'] as $name => &$column) {
if (isset($this->seedData['bindColumn']) && count($this->seedData['bindColumn'])) {
foreach ($this->seedData['bindColumn'] as $name => $column) {
$this->seedData['bindColumn'][$name] = $result[$name];
}
}
return $result;
}

}
61 changes: 61 additions & 0 deletions src/StatementCursor.php
@@ -0,0 +1,61 @@
<?php

/*
* LegoW\ReconnectingPDO (https://github.com/adamturcsan/reconnecting-pdo)
*
* @copyright Copyright (c) 2014-2016 Legow Hosting Kft. (http://www.legow.hu)
* @license https://opensource.org/licenses/MIT MIT License
*/

namespace LegoW\ReconnectingPDO;

use LegoW\ReconnectingPDO\CursorException;
/**
* Description of StatementCursor
*
* @author Turcsán Ádám <turcsan.adam@legow.hu>
*/
class StatementCursor
{
/**
* Current cursor position
* @var int
*/
private $position = 0;

public function getPosition()
{
return $this->position;
}

/**
* @return $this
*/
public function next()
{
$this->position++;
return $this;
}
/**
*
* @return $this
* @throws CursorException
*/
public function prev()
{
if($this->getPosition() == 0) {
throw new CursorException("Position cannot be less than zero");
}
$this->position--;
return $this;
}

public function setPosition($position)
{
$direction = $position < $this->position ? -1 : 1;
while($this->position != $position) {
$this->position += $direction;
}
return $this;
}
}

0 comments on commit 89df08d

Please sign in to comment.