Skip to content

Commit

Permalink
Dropped support for fetching objects and non-zero column
Browse files Browse the repository at this point in the history
1. `FetchMode::STANDARD_OBJECT` and `FetchMode::CUSTOM_OBJECT` are no longer supported.
2. `FetchMode::COLUMN` with a non-zero index is no longer supported.
3. Incompatible change in the `Connection::fetchColumn()` signature where the 3rd argument is now `$types`, not `$columnIndex`.
  • Loading branch information
morozov committed Apr 13, 2020
1 parent 438befb commit aa6ae1d
Show file tree
Hide file tree
Showing 20 changed files with 90 additions and 601 deletions.
8 changes: 8 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Upgrade to 3.0

## BC BREAK: Dropped support for `FetchMode::CUSTOM_OBJECT` and `::STANDARD_OBJECT`

Instead of fetching an object, fetch an array and map it to an object of the desired class.

## BC BREAK: Dropped support for the `$columnIndex` argument in `ResultStatement::fetchColumn()`, other `ResultStatement::fetch*()` methods invoked with `FetchMode::COLUMN` and `Connection::fetchColumn()`.

In order to fetch a column with an index other than `0`, use `FetchMode::NUMERIC` and the array element with the corresponding index.

## BC BREAK: Removed `EchoSQLLogger`

`EchoSQLLogger` is no longer available as part of the package.
Expand Down
6 changes: 0 additions & 6 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,6 @@ parameters:
- %currentWorkingDirectory%/src/Query/QueryBuilder.php
- %currentWorkingDirectory%/src/Schema/*SchemaManager.php

# FetchMode::CUSTOM_OBJECT requires variable property access
-
message: '~^Variable property access on object\.~'
paths:
- %currentWorkingDirectory%/src/Driver/*/*Statement.php

# Some APIs use variable method calls internally
-
message: '~^Variable method call on .*~'
Expand Down
16 changes: 6 additions & 10 deletions src/Cache/ArrayStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,8 @@ public function columnCount()
/**
* {@inheritdoc}
*/
public function setFetchMode($fetchMode, ...$args)
public function setFetchMode($fetchMode)
{
if (count($args) > 0) {
throw new InvalidArgumentException('Caching layer does not support 2nd/3rd argument to setFetchMode()');
}

$this->defaultFetchMode = $fetchMode;

return true;
Expand All @@ -84,7 +80,7 @@ public function getIterator()
/**
* {@inheritdoc}
*/
public function fetch($fetchMode = null, ...$args)
public function fetch($fetchMode = null)
{
if (! isset($this->data[$this->num])) {
return false;
Expand Down Expand Up @@ -115,10 +111,10 @@ public function fetch($fetchMode = null, ...$args)
/**
* {@inheritdoc}
*/
public function fetchAll($fetchMode = null, ...$args)
public function fetchAll($fetchMode = null)
{
$rows = [];
while ($row = $this->fetch($fetchMode, ...$args)) {
while ($row = $this->fetch($fetchMode)) {
$rows[] = $row;
}

Expand All @@ -128,11 +124,11 @@ public function fetchAll($fetchMode = null, ...$args)
/**
* {@inheritdoc}
*/
public function fetchColumn($columnIndex = 0)
public function fetchColumn()
{
$row = $this->fetch(FetchMode::NUMERIC);

// TODO: verify that return false is the correct behavior
return $row[$columnIndex] ?? false;
return $row[0] ?? false;
}
}
12 changes: 6 additions & 6 deletions src/Cache/ResultCacheStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public function columnCount()
/**
* {@inheritdoc}
*/
public function setFetchMode($fetchMode, ...$args)
public function setFetchMode($fetchMode)
{
$this->defaultFetchMode = $fetchMode;

Expand All @@ -124,7 +124,7 @@ public function getIterator()
/**
* {@inheritdoc}
*/
public function fetch($fetchMode = null, ...$args)
public function fetch($fetchMode = null)
{
if ($this->data === null) {
$this->data = [];
Expand Down Expand Up @@ -164,9 +164,9 @@ public function fetch($fetchMode = null, ...$args)
/**
* {@inheritdoc}
*/
public function fetchAll($fetchMode = null, ...$args)
public function fetchAll($fetchMode = null)
{
$data = $this->statement->fetchAll($fetchMode, ...$args);
$data = $this->statement->fetchAll($fetchMode);

if ($fetchMode === FetchMode::COLUMN) {
foreach ($data as $key => $value) {
Expand All @@ -183,12 +183,12 @@ public function fetchAll($fetchMode = null, ...$args)
/**
* {@inheritdoc}
*/
public function fetchColumn($columnIndex = 0)
public function fetchColumn()
{
$row = $this->fetch(FetchMode::NUMERIC);

// TODO: verify that return false is the correct behavior
return $row[$columnIndex] ?? false;
return $row[0] ?? false;
}

/**
Expand Down
5 changes: 2 additions & 3 deletions src/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -570,16 +570,15 @@ public function fetchArray($statement, array $params = [], array $types = [])
*
* @param string $statement The SQL query to be executed.
* @param mixed[] $params The prepared statement params.
* @param int $column The 0-indexed column number to retrieve.
* @param int[]|string[] $types The query parameter types.
*
* @return mixed|false False is returned if no rows are found.
*
* @throws DBALException
*/
public function fetchColumn($statement, array $params = [], $column = 0, array $types = [])
public function fetchColumn($statement, array $params = [], array $types = [])
{
return $this->executeQuery($statement, $params, $types)->fetchColumn($column);
return $this->executeQuery($statement, $params, $types)->fetchColumn();
}

/**
Expand Down
127 changes: 5 additions & 122 deletions src/Driver/IBMDB2/DB2Statement.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,17 @@
use Doctrine\DBAL\FetchMode;
use Doctrine\DBAL\ParameterType;
use IteratorAggregate;
use ReflectionClass;
use ReflectionObject;
use ReflectionProperty;
use stdClass;
use const CASE_LOWER;
use const DB2_BINARY;
use const DB2_CHAR;
use const DB2_LONG;
use const DB2_PARAM_FILE;
use const DB2_PARAM_IN;
use function array_change_key_case;
use function assert;
use function count;
use function db2_bind_param;
use function db2_execute;
use function db2_fetch_array;
use function db2_fetch_assoc;
use function db2_fetch_both;
use function db2_fetch_object;
use function db2_free_result;
use function db2_num_fields;
use function db2_num_rows;
Expand All @@ -34,16 +26,11 @@
use function error_get_last;
use function fclose;
use function fwrite;
use function gettype;
use function is_int;
use function is_object;
use function is_resource;
use function is_string;
use function ksort;
use function sprintf;
use function stream_copy_to_stream;
use function stream_get_meta_data;
use function strtolower;
use function tmpfile;

class DB2Statement implements IteratorAggregate, Statement
Expand All @@ -62,12 +49,6 @@ class DB2Statement implements IteratorAggregate, Statement
*/
private $lobs = [];

/** @var string Name of the default class to instantiate when fetching class instances. */
private $defaultFetchClass = '\stdClass';

/** @var mixed[] Constructor arguments for the default class to instantiate when fetching class instances. */
private $defaultFetchClassCtorArgs = [];

/** @var int */
private $defaultFetchMode = FetchMode::MIXED;

Expand Down Expand Up @@ -237,18 +218,10 @@ public function execute($params = null)
/**
* {@inheritdoc}
*/
public function setFetchMode($fetchMode, ...$args)
public function setFetchMode($fetchMode)
{
$this->defaultFetchMode = $fetchMode;

if (isset($args[0])) {
$this->defaultFetchClass = $args[0];
}

if (isset($args[1])) {
$this->defaultFetchClassCtorArgs = (array) $args[1];
}

return true;
}

Expand All @@ -263,7 +236,7 @@ public function getIterator()
/**
* {@inheritdoc}
*/
public function fetch($fetchMode = null, ...$args)
public function fetch($fetchMode = null)
{
// do not try fetching from the statement if it's not expected to contain result
// in order to prevent exceptional situation
Expand All @@ -282,29 +255,9 @@ public function fetch($fetchMode = null, ...$args)
case FetchMode::ASSOCIATIVE:
return db2_fetch_assoc($this->stmt);

case FetchMode::CUSTOM_OBJECT:
$className = $this->defaultFetchClass;
$ctorArgs = $this->defaultFetchClassCtorArgs;

if (count($args) > 0) {
$className = $args[0];
$ctorArgs = $args[1] ?? [];
}

$result = db2_fetch_object($this->stmt);

if ($result instanceof stdClass) {
$result = $this->castObject($result, $className, $ctorArgs);
}

return $result;

case FetchMode::NUMERIC:
return db2_fetch_array($this->stmt);

case FetchMode::STANDARD_OBJECT:
return db2_fetch_object($this->stmt);

default:
throw new DB2Exception('Given Fetch-Style ' . $fetchMode . ' is not supported.');
}
Expand All @@ -313,16 +266,11 @@ public function fetch($fetchMode = null, ...$args)
/**
* {@inheritdoc}
*/
public function fetchAll($fetchMode = null, ...$args)
public function fetchAll($fetchMode = null)
{
$rows = [];

switch ($fetchMode) {
case FetchMode::CUSTOM_OBJECT:
while (($row = $this->fetch($fetchMode, ...$args)) !== false) {
$rows[] = $row;
}
break;
case FetchMode::COLUMN:
while (($row = $this->fetchColumn()) !== false) {
$rows[] = $row;
Expand All @@ -340,15 +288,15 @@ public function fetchAll($fetchMode = null, ...$args)
/**
* {@inheritdoc}
*/
public function fetchColumn($columnIndex = 0)
public function fetchColumn()
{
$row = $this->fetch(FetchMode::NUMERIC);

if ($row === false) {
return false;
}

return $row[$columnIndex] ?? null;
return $row[0] ?? null;
}

/**
Expand All @@ -359,71 +307,6 @@ public function rowCount() : int
return @db2_num_rows($this->stmt);
}

/**
* Casts a stdClass object to the given class name mapping its' properties.
*
* @param stdClass $sourceObject Object to cast from.
* @param string|object $destinationClass Name of the class or class instance to cast to.
* @param mixed[] $ctorArgs Arguments to use for constructing the destination class instance.
*
* @return object
*
* @throws DB2Exception
*/
private function castObject(stdClass $sourceObject, $destinationClass, array $ctorArgs = [])
{
if (! is_string($destinationClass)) {
if (! is_object($destinationClass)) {
throw new DB2Exception(sprintf(
'Destination class has to be of type string or object, %s given.',
gettype($destinationClass)
));
}
} else {
$destinationClass = new ReflectionClass($destinationClass);
$destinationClass = $destinationClass->newInstanceArgs($ctorArgs);
}

$sourceReflection = new ReflectionObject($sourceObject);
$destinationClassReflection = new ReflectionObject($destinationClass);
/** @var ReflectionProperty[] $destinationProperties */
$destinationProperties = array_change_key_case($destinationClassReflection->getProperties(), CASE_LOWER);

foreach ($sourceReflection->getProperties() as $sourceProperty) {
$sourceProperty->setAccessible(true);

$name = $sourceProperty->getName();
$value = $sourceProperty->getValue($sourceObject);

// Try to find a case-matching property.
if ($destinationClassReflection->hasProperty($name)) {
$destinationProperty = $destinationClassReflection->getProperty($name);

$destinationProperty->setAccessible(true);
$destinationProperty->setValue($destinationClass, $value);

continue;
}

$name = strtolower($name);

// Try to find a property without matching case.
// Fallback for the driver returning either all uppercase or all lowercase column names.
if (isset($destinationProperties[$name])) {
$destinationProperty = $destinationProperties[$name];

$destinationProperty->setAccessible(true);
$destinationProperty->setValue($destinationClass, $value);

continue;
}

$destinationClass->$name = $value;
}

return $destinationClass;
}

/**
* @return resource
*
Expand Down
Loading

0 comments on commit aa6ae1d

Please sign in to comment.