Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dropped support of fetching objects and non-zero column #3070

Merged
merged 1 commit into from
Apr 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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