Unverified Commit 90b68ab6 authored by Sergei Morozov's avatar Sergei Morozov Committed by GitHub

Merge pull request #4039 from morozov/refactor-portability-statement

Refactor portability statement into a functional composition
parents 9d22f7bc 7204a7df
...@@ -30,11 +30,8 @@ class Connection extends \Doctrine\DBAL\Connection ...@@ -30,11 +30,8 @@ class Connection extends \Doctrine\DBAL\Connection
public const PORTABILITY_SQLANYWHERE = 13; public const PORTABILITY_SQLANYWHERE = 13;
public const PORTABILITY_SQLSRV = 13; public const PORTABILITY_SQLSRV = 13;
/** @var int */ /** @var Converter */
private $portability = self::PORTABILITY_NONE; private $converter;
/** @var int */
private $case;
/** /**
* {@inheritdoc} * {@inheritdoc}
...@@ -44,53 +41,45 @@ class Connection extends \Doctrine\DBAL\Connection ...@@ -44,53 +41,45 @@ class Connection extends \Doctrine\DBAL\Connection
$ret = parent::connect(); $ret = parent::connect();
if ($ret) { if ($ret) {
$params = $this->getParams(); $params = $this->getParams();
$portability = self::PORTABILITY_NONE;
if (isset($params['portability'])) { if (isset($params['portability'])) {
if ($this->getDatabasePlatform()->getName() === 'oracle') { if ($this->getDatabasePlatform()->getName() === 'oracle') {
$params['portability'] &= self::PORTABILITY_ORACLE; $portability = $params['portability'] & self::PORTABILITY_ORACLE;
} elseif ($this->getDatabasePlatform()->getName() === 'postgresql') { } elseif ($this->getDatabasePlatform()->getName() === 'postgresql') {
$params['portability'] &= self::PORTABILITY_POSTGRESQL; $portability = $params['portability'] & self::PORTABILITY_POSTGRESQL;
} elseif ($this->getDatabasePlatform()->getName() === 'sqlite') { } elseif ($this->getDatabasePlatform()->getName() === 'sqlite') {
$params['portability'] &= self::PORTABILITY_SQLITE; $portability = $params['portability'] & self::PORTABILITY_SQLITE;
} elseif ($this->getDatabasePlatform()->getName() === 'sqlanywhere') { } elseif ($this->getDatabasePlatform()->getName() === 'sqlanywhere') {
$params['portability'] &= self::PORTABILITY_SQLANYWHERE; $portability = $params['portability'] & self::PORTABILITY_SQLANYWHERE;
} elseif ($this->getDatabasePlatform()->getName() === 'db2') { } elseif ($this->getDatabasePlatform()->getName() === 'db2') {
$params['portability'] &= self::PORTABILITY_DB2; $portability = $params['portability'] & self::PORTABILITY_DB2;
} elseif ($this->getDatabasePlatform()->getName() === 'mssql') { } elseif ($this->getDatabasePlatform()->getName() === 'mssql') {
$params['portability'] &= self::PORTABILITY_SQLSRV; $portability = $params['portability'] & self::PORTABILITY_SQLSRV;
} else { } else {
$params['portability'] &= self::PORTABILITY_OTHERVENDORS; $portability = $params['portability'] & self::PORTABILITY_OTHERVENDORS;
} }
$this->portability = $params['portability'];
} }
if (isset($params['fetch_case']) && ($this->portability & self::PORTABILITY_FIX_CASE) !== 0) { $case = null;
if (isset($params['fetch_case']) && ($portability & self::PORTABILITY_FIX_CASE) !== 0) {
if ($this->_conn instanceof PDOConnection) { if ($this->_conn instanceof PDOConnection) {
// make use of c-level support for case handling // make use of c-level support for case handling
$this->_conn->getWrappedConnection()->setAttribute(PDO::ATTR_CASE, $params['fetch_case']); $this->_conn->getWrappedConnection()->setAttribute(PDO::ATTR_CASE, $params['fetch_case']);
} else { } else {
$this->case = $params['fetch_case'] === ColumnCase::LOWER ? CASE_LOWER : CASE_UPPER; $case = $params['fetch_case'] === ColumnCase::LOWER ? CASE_LOWER : CASE_UPPER;
}
} }
} }
return $ret; $this->converter = new Converter(
} ($portability & self::PORTABILITY_EMPTY_TO_NULL) !== 0,
($portability & self::PORTABILITY_RTRIM) !== 0,
/** $case
* @return int );
*/
public function getPortability()
{
return $this->portability;
} }
/** return $ret;
* @return int
*/
public function getFetchCase()
{
return $this->case;
} }
/** /**
...@@ -98,20 +87,16 @@ class Connection extends \Doctrine\DBAL\Connection ...@@ -98,20 +87,16 @@ class Connection extends \Doctrine\DBAL\Connection
*/ */
public function executeQuery(string $query, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) : ResultStatement public function executeQuery(string $query, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) : ResultStatement
{ {
return new Statement(parent::executeQuery($query, $params, $types, $qcp), $this); return new Statement(parent::executeQuery($query, $params, $types, $qcp), $this->converter);
} }
public function prepare(string $sql) : DriverStatement public function prepare(string $sql) : DriverStatement
{ {
return new Statement(parent::prepare($sql), $this); return new Statement(parent::prepare($sql), $this->converter);
} }
public function query(string $sql) : ResultStatement public function query(string $sql) : ResultStatement
{ {
return new Statement( return new Statement(parent::query($sql), $this->converter);
$this->getWrappedConnection()
->query($sql),
$this
);
} }
} }
<?php
declare(strict_types=1);
namespace Doctrine\DBAL\Portability;
use function array_change_key_case;
use function array_map;
use function array_reduce;
use function is_string;
use function rtrim;
final class Converter
{
/** @var callable */
private $convertNumeric;
/** @var callable */
private $convertAssociative;
/** @var callable */
private $convertOne;
/** @var callable */
private $convertAllNumeric;
/** @var callable */
private $convertAllAssociative;
/** @var callable */
private $convertFirstColumn;
/**
* @param bool $convertEmptyStringToNull Whether each empty string should be converted to NULL
* @param bool $rightTrimString Whether each string should right-trimmed
* @param int|null $case Convert the case of the column names
* (one of {@link CASE_LOWER} and {@link CASE_UPPER})
*/
public function __construct(bool $convertEmptyStringToNull, bool $rightTrimString, ?int $case)
{
$id = static function ($value) {
return $value;
};
$convertValue = $this->createConvertValue($convertEmptyStringToNull, $rightTrimString);
$convertNumeric = $this->createConvertRow($convertValue, null);
$convertAssociative = $this->createConvertRow($convertValue, $case);
$this->convertNumeric = $this->createConvert($convertNumeric, $id);
$this->convertAssociative = $this->createConvert($convertAssociative, $id);
$this->convertOne = $this->createConvert($convertValue, $id);
$this->convertAllNumeric = $this->createConvertAll($convertNumeric, $id);
$this->convertAllAssociative = $this->createConvertAll($convertAssociative, $id);
$this->convertFirstColumn = $this->createConvertAll($convertValue, $id);
}
/**
* @param array<int,mixed>|false $row
*
* @return array<int,mixed>|false
*/
public function convertNumeric($row)
{
return ($this->convertNumeric)($row);
}
/**
* @param array<string,mixed>|false $row
*
* @return array<string,mixed>|false
*/
public function convertAssociative($row)
{
return ($this->convertAssociative)($row);
}
/**
* @param mixed|false $value
*
* @return mixed|false
*/
public function convertOne($value)
{
return ($this->convertOne)($value);
}
/**
* @param array<int,array<int,mixed>> $data
*
* @return array<int,array<int,mixed>>
*/
public function convertAllNumeric(array $data) : array
{
return ($this->convertAllNumeric)($data);
}
/**
* @param array<int,array<string,mixed>> $data
*
* @return array<int,array<string,mixed>>
*/
public function convertAllAssociative(array $data) : array
{
return ($this->convertAllAssociative)($data);
}
/**
* @param array<int,mixed> $data
*
* @return array<int,mixed>
*/
public function convertFirstColumn(array $data) : array
{
return ($this->convertFirstColumn)($data);
}
/**
* Creates a function that will convert each individual value retrieved from the database
*
* @param bool $convertEmptyStringToNull Whether each empty string should be converted to NULL
* @param bool $rightTrimString Whether each string should right-trimmed
*
* @return callable|null The resulting function or NULL if no conversion is needed
*/
private function createConvertValue(bool $convertEmptyStringToNull, bool $rightTrimString) : ?callable
{
$functions = [];
if ($convertEmptyStringToNull) {
$functions[] = static function ($value) {
if ($value === '') {
return null;
}
return $value;
};
}
if ($rightTrimString) {
$functions[] = static function ($value) {
if (! is_string($value)) {
return $value;
}
return rtrim($value);
};
}
return $this->compose(...$functions);
}
/**
* Creates a function that will convert each array-row retrieved from the database
*
* @param callable|null $function The function that will convert each value
* @param int|null $case Column name case
*
* @return callable|null The resulting function or NULL if no conversion is needed
*/
private function createConvertRow(?callable $function, ?int $case) : ?callable
{
$functions = [];
if ($function !== null) {
$functions[] = $this->createMapper($function);
}
if ($case !== null) {
$functions[] = static function (array $row) use ($case) : array {
return array_change_key_case($row, $case);
};
}
return $this->compose(...$functions);
}
/**
* Creates a function that will be applied to the return value of Statement::fetch*()
* or an identity function if no conversion is needed
*
* @param callable|null $function The function that will convert each tow
* @param callable $id Identity function
*/
private function createConvert(?callable $function, callable $id) : callable
{
if ($function === null) {
return $id;
}
return static function ($value) use ($function) {
if ($value === false) {
return false;
}
return $function($value);
};
}
/**
* Creates a function that will be applied to the return value of Statement::fetchAll*()
* or an identity function if no transformation is required
*
* @param callable|null $function The function that will transform each value
* @param callable $id Identity function
*/
private function createConvertAll(?callable $function, callable $id) : callable
{
if ($function === null) {
return $id;
}
return $this->createMapper($function);
}
/**
* Creates a function that maps each value of the array using the given function
*
* @param callable $function The function that maps each value of the array
*/
private function createMapper(callable $function) : callable
{
return static function (array $array) use ($function) : array {
return array_map($function, $array);
};
}
/**
* Creates a composition of the given set of functions
*
* @param callable ...$functions The functions to compose
*
* @return callable|null The composition or NULL if an empty set is provided
*/
private function compose(callable ...$functions) : ?callable
{
return array_reduce($functions, static function (?callable $carry, callable $item) : callable {
if ($carry === null) {
return $item;
}
return static function ($value) use ($carry, $item) {
return $item($carry($value));
};
});
}
}
...@@ -5,35 +5,28 @@ namespace Doctrine\DBAL\Portability; ...@@ -5,35 +5,28 @@ namespace Doctrine\DBAL\Portability;
use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\Statement as DriverStatement; use Doctrine\DBAL\Driver\Statement as DriverStatement;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use function array_change_key_case;
use function assert; use function assert;
use function is_string;
use function rtrim;
/** /**
* Portability wrapper for a Statement. * Portability wrapper for a Statement.
*/ */
class Statement implements DriverStatement class Statement implements DriverStatement
{ {
/** @var int */
private $portability;
/** @var DriverStatement|ResultStatement */ /** @var DriverStatement|ResultStatement */
private $stmt; private $stmt;
/** @var int */ /** @var Converter */
private $case; private $converter;
/** /**
* Wraps <tt>Statement</tt> and applies portability measures. * Wraps <tt>Statement</tt> and applies portability measures.
* *
* @param DriverStatement|ResultStatement $stmt * @param DriverStatement|ResultStatement $stmt
*/ */
public function __construct($stmt, Connection $conn) public function __construct($stmt, Converter $converter)
{ {
$this->stmt = $stmt; $this->stmt = $stmt;
$this->portability = $conn->getPortability(); $this->converter = $converter;
$this->case = $conn->getFetchCase();
} }
/** /**
...@@ -82,14 +75,20 @@ class Statement implements DriverStatement ...@@ -82,14 +75,20 @@ class Statement implements DriverStatement
return $this->stmt->execute($params); return $this->stmt->execute($params);
} }
public function rowCount() : int
{
assert($this->stmt instanceof DriverStatement);
return $this->stmt->rowCount();
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetchNumeric() public function fetchNumeric()
{ {
return $this->fixResult( return $this->converter->convertNumeric(
$this->stmt->fetchAssociative(), $this->stmt->fetchNumeric()
false
); );
} }
...@@ -98,9 +97,8 @@ class Statement implements DriverStatement ...@@ -98,9 +97,8 @@ class Statement implements DriverStatement
*/ */
public function fetchAssociative() public function fetchAssociative()
{ {
return $this->fixResult( return $this->converter->convertAssociative(
$this->stmt->fetchAssociative(), $this->stmt->fetchAssociative()
true
); );
} }
...@@ -109,15 +107,9 @@ class Statement implements DriverStatement ...@@ -109,15 +107,9 @@ class Statement implements DriverStatement
*/ */
public function fetchOne() public function fetchOne()
{ {
$value = $this->stmt->fetchOne(); return $this->converter->convertOne(
$this->stmt->fetchOne()
if (($this->portability & Connection::PORTABILITY_EMPTY_TO_NULL) !== 0 && $value === '') { );
$value = null;
} elseif (($this->portability & Connection::PORTABILITY_RTRIM) !== 0 && is_string($value)) {
$value = rtrim($value);
}
return $value;
} }
/** /**
...@@ -125,10 +117,8 @@ class Statement implements DriverStatement ...@@ -125,10 +117,8 @@ class Statement implements DriverStatement
*/ */
public function fetchAllNumeric() : array public function fetchAllNumeric() : array
{ {
return $this->fixResultSet( return $this->converter->convertAllNumeric(
$this->stmt->fetchAllNumeric(), $this->stmt->fetchAllNumeric()
false,
true
); );
} }
...@@ -137,10 +127,8 @@ class Statement implements DriverStatement ...@@ -137,10 +127,8 @@ class Statement implements DriverStatement
*/ */
public function fetchAllAssociative() : array public function fetchAllAssociative() : array
{ {
return $this->fixResultSet( return $this->converter->convertAllAssociative(
$this->stmt->fetchAllAssociative(), $this->stmt->fetchAllAssociative()
true,
true
); );
} }
...@@ -149,93 +137,8 @@ class Statement implements DriverStatement ...@@ -149,93 +137,8 @@ class Statement implements DriverStatement
*/ */
public function fetchColumn() : array public function fetchColumn() : array
{ {
return $this->fixResultSet( return $this->converter->convertFirstColumn(
$this->stmt->fetchColumn(), $this->stmt->fetchColumn()
true,
false
); );
} }
/**
* @param mixed $result
*
* @return mixed
*/
private function fixResult($result, bool $fixCase)
{
$iterateRow = ($this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM)) !== 0;
$fixCase = $fixCase && $this->case !== null && ($this->portability & Connection::PORTABILITY_FIX_CASE) !== 0;
return $this->fixRow($result, $iterateRow, $fixCase);
}
/**
* @param array<int,mixed> $resultSet
*
* @return array<int,mixed>
*/
private function fixResultSet(array $resultSet, bool $fixCase, bool $isArray) : array
{
$iterateRow = ($this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM)) !== 0;
$fixCase = $fixCase && $this->case !== null && ($this->portability & Connection::PORTABILITY_FIX_CASE) !== 0;
if (! $iterateRow && ! $fixCase) {
return $resultSet;
}
if (! $isArray) {
foreach ($resultSet as $num => $value) {
$resultSet[$num] = [$value];
}
}
foreach ($resultSet as $num => $row) {
$resultSet[$num] = $this->fixRow($row, $iterateRow, $fixCase);
}
if (! $isArray) {
foreach ($resultSet as $num => $row) {
$resultSet[$num] = $row[0];
}
}
return $resultSet;
}
/**
* @param mixed $row
* @param bool $iterateRow
* @param bool $fixCase
*
* @return mixed
*/
protected function fixRow($row, $iterateRow, $fixCase)
{
if ($row === false) {
return $row;
}
if ($fixCase) {
$row = array_change_key_case($row, $this->case);
}
if ($iterateRow) {
foreach ($row as $k => $v) {
if (($this->portability & Connection::PORTABILITY_EMPTY_TO_NULL) !== 0 && $v === '') {
$row[$k] = null;
} elseif (($this->portability & Connection::PORTABILITY_RTRIM) !== 0 && is_string($v)) {
$row[$k] = rtrim($v);
}
}
}
return $row;
}
public function rowCount() : int
{
assert($this->stmt instanceof DriverStatement);
return $this->stmt->rowCount();
}
} }
<?php
namespace Doctrine\DBAL\Tests\Portability;
use Doctrine\DBAL\Portability\Converter;
use PHPUnit\Framework\TestCase;
use const CASE_LOWER;
class ConverterTest extends TestCase
{
/**
* @param array<int,mixed>|false $row
* @param array<int,mixed>|false $expected
*
* @dataProvider convertNumericProvider
*/
public function testConvertNumeric($row, bool $convertEmptyStringToNull, bool $rightTrimString, $expected) : void
{
self::assertSame(
$expected,
$this->createConverter($convertEmptyStringToNull, $rightTrimString, null)
->convertNumeric($row)
);
}
/**
* @return iterable<string,array<int,mixed>>
*/
public static function convertNumericProvider() : iterable
{
$row = ['X ', ''];
yield 'None' => [
$row,
false,
false,
['X ', ''],
];
yield 'Trim' => [
$row,
false,
true,
['X', ''],
];
yield 'Empty to NULL' => [
$row,
true,
false,
['X ', null],
];
yield 'Empty to NULL and Trim' => [
$row,
true,
true,
['X', null],
];
yield 'False' => [false, true, true, false];
}
/**
* @param array<string,mixed>|false $row
* @param array<string,mixed>|false $expected
*
* @dataProvider convertAssociativeProvider
*/
public function testConvertAssociative($row, bool $convertEmptyStringToNull, bool $rightTrimString, ?int $case, $expected) : void
{
self::assertSame(
$expected,
$this->createConverter($convertEmptyStringToNull, $rightTrimString, $case)
->convertAssociative($row)
);
}
/**
* @return iterable<string,array<int,mixed>>
*/
public static function convertAssociativeProvider() : iterable
{
$row = [
'FOO' => '',
'BAR' => 'X ',
];
yield 'None' => [
$row,
false,
false,
null,
[
'FOO' => '',
'BAR' => 'X ',
],
];
yield 'Trim' => [
$row,
false,
true,
null,
[
'FOO' => '',
'BAR' => 'X',
],
];
yield 'Empty to NULL' => [
$row,
true,
false,
null,
[
'FOO' => null,
'BAR' => 'X ',
],
];
yield 'Empty to NULL and Trim' => [
$row,
true,
true,
null,
[
'FOO' => null,
'BAR' => 'X',
],
];
yield 'To lower' => [
$row,
false,
false,
CASE_LOWER,
[
'foo' => '',
'bar' => 'X ',
],
];
yield 'Trim and to lower' => [
$row,
false,
true,
CASE_LOWER,
[
'foo' => '',
'bar' => 'X',
],
];
yield 'Empty to NULL and to lower' => [
$row,
true,
false,
CASE_LOWER,
[
'foo' => null,
'bar' => 'X ',
],
];
yield 'Trim, empty to NULL and to lower' => [
$row,
true,
true,
CASE_LOWER,
[
'foo' => null,
'bar' => 'X',
],
];
yield 'False' => [false, true, true, null, false];
}
/**
* @param mixed|false $value
* @param mixed|false $expected
*
* @dataProvider convertOneProvider
*/
public function testConvertOne($value, bool $convertEmptyStringToNull, bool $rightTrimString, $expected) : void
{
self::assertSame(
$expected,
$this->createConverter($convertEmptyStringToNull, $rightTrimString, null)
->convertOne($value)
);
}
/**
* @return iterable<string,array<int,mixed>>
*/
public static function convertOneProvider() : iterable
{
yield 'None, trailing space' => ['X ', false, false, 'X '];
yield 'None, empty string' => ['', false, false, ''];
yield 'Trim, trailing space' => ['X ', false, true, 'X'];
yield 'Trim, empty string' => ['', false, true, ''];
yield 'Empty to NULL, trailing space' => ['X ', true, false, 'X '];
yield 'Empty to NULL, empty string' => ['', true, false, null];
yield 'Empty to NULL and Trim, trailing space' => ['X ', true, true, 'X'];
yield 'Empty to NULL and Trim, empty string' => ['', true, true, null];
yield 'False' => [false, true, true, false];
}
/**
* @param array<int,array<int,mixed>> $data
* @param array<int,array<int,mixed>> $expected
*
* @dataProvider convertAllNumericProvider
*/
public function testConvertAllNumeric(
array $data,
bool $convertEmptyStringToNull,
bool $rightTrimString,
array $expected
) : void {
self::assertSame(
$expected,
$this->createConverter($convertEmptyStringToNull, $rightTrimString, null)
->convertAllNumeric($data)
);
}
/**
* @return iterable<string,array<int,mixed>>
*/
public static function convertAllNumericProvider() : iterable
{
$data = [
['X ', ''],
['', 'Y '],
];
yield 'None' => [
$data,
false,
false,
[
['X ', ''],
['', 'Y '],
],
];
yield 'Trim' => [
$data,
false,
true,
[
['X', ''],
['', 'Y'],
],
];
yield 'Empty to NULL' => [
$data,
true,
false, [
['X ', null],
[null, 'Y '],
],
];
yield 'Empty to NULL and Trim' => [
$data,
true,
true, [
['X', null],
[null, 'Y'],
],
];
}
/**
* @param array<int,array<string,mixed>> $row
* @param array<int,array<string,mixed>> $expected
*
* @dataProvider convertAllAssociativeProvider
*/
public function testConvertAllAssociative(
array $row,
bool $convertEmptyStringToNull,
bool $rightTrimString,
?int $case,
array $expected
) : void {
self::assertSame(
$expected,
$this->createConverter($convertEmptyStringToNull, $rightTrimString, $case)
->convertAllAssociative($row)
);
}
/**
* @return iterable<string,array<int,mixed>>
*/
public static function convertAllAssociativeProvider() : iterable
{
$data = [
[
'FOO' => 'X ',
'BAR' => '',
],
[
'FOO' => '',
'BAR' => 'Y ',
],
];
yield 'None' => [
$data,
false,
false,
null,
[
[
'FOO' => 'X ',
'BAR' => '',
],
[
'FOO' => '',
'BAR' => 'Y ',
],
],
];
yield 'Trim' => [
$data,
false,
true,
null,
[
[
'FOO' => 'X',
'BAR' => '',
],
[
'FOO' => '',
'BAR' => 'Y',
],
],
];
yield 'Empty to NULL' => [
$data,
true,
false,
null,
[
[
'FOO' => 'X ',
'BAR' => null,
],
[
'FOO' => null,
'BAR' => 'Y ',
],
],
];
yield 'Empty to NULL and Trim' => [
$data,
true,
true,
null,
[
[
'FOO' => 'X',
'BAR' => null,
],
[
'FOO' => null,
'BAR' => 'Y',
],
],
];
yield 'To lower' => [
$data,
false,
false,
CASE_LOWER,
[
[
'foo' => 'X ',
'bar' => '',
],
[
'foo' => '',
'bar' => 'Y ',
],
],
];
yield 'Trim and to lower' => [
$data,
false,
true,
CASE_LOWER,
[
[
'foo' => 'X',
'bar' => '',
],
[
'foo' => '',
'bar' => 'Y',
],
],
];
yield 'Empty to NULL and to lower' => [
$data,
true,
false,
CASE_LOWER,
[
[
'foo' => 'X ',
'bar' => null,
],
[
'foo' => null,
'bar' => 'Y ',
],
],
];
yield 'Trim, empty to NULL and to lower' => [
$data,
true,
true,
CASE_LOWER,
[
[
'foo' => 'X',
'bar' => null,
],
[
'foo' => null,
'bar' => 'Y',
],
],
];
}
/**
* @param array<int,mixed> $column
* @param array<int,mixed> $expected
*
* @dataProvider convertFirstColumnProvider
*/
public function testConvertFirstColumn(
array $column,
bool $convertEmptyStringToNull,
bool $rightTrimString,
array $expected
) : void {
self::assertSame(
$expected,
$this->createConverter($convertEmptyStringToNull, $rightTrimString, null)
->convertFirstColumn($column)
);
}
/**
* @return iterable<string,array<int,mixed>>
*/
public static function convertFirstColumnProvider() : iterable
{
$column = ['X ', ''];
yield 'None' => [
$column,
false,
false,
['X ', ''],
];
yield 'Trim' => [
$column,
false,
true,
['X', ''],
];
yield 'Empty to NULL' => [
$column,
true,
false,
['X ', null],
];
yield 'Empty to NULL and Trim' => [
$column,
true,
true,
['X', null],
];
}
private function createConverter(bool $convertEmptyStringToNull, bool $rightTrimString, ?int $case) : Converter
{
return new Converter($convertEmptyStringToNull, $rightTrimString, $case);
}
}
...@@ -5,15 +5,13 @@ namespace Doctrine\DBAL\Tests\Portability; ...@@ -5,15 +5,13 @@ namespace Doctrine\DBAL\Tests\Portability;
use Doctrine\DBAL\Driver\Statement as DriverStatement; use Doctrine\DBAL\Driver\Statement as DriverStatement;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Portability\Connection; use Doctrine\DBAL\Portability\Connection;
use Doctrine\DBAL\Portability\Converter;
use Doctrine\DBAL\Portability\Statement; use Doctrine\DBAL\Portability\Statement;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
class StatementTest extends TestCase class StatementTest extends TestCase
{ {
/** @var Connection|MockObject */
protected $conn;
/** @var Statement */ /** @var Statement */
protected $stmt; protected $stmt;
...@@ -23,8 +21,8 @@ class StatementTest extends TestCase ...@@ -23,8 +21,8 @@ class StatementTest extends TestCase
protected function setUp() : void protected function setUp() : void
{ {
$this->wrappedStmt = $this->createMock(DriverStatement::class); $this->wrappedStmt = $this->createMock(DriverStatement::class);
$this->conn = $this->createConnection(); $converter = new Converter(false, false, null);
$this->stmt = $this->createStatement($this->wrappedStmt, $this->conn); $this->stmt = new Statement($this->wrappedStmt, $converter);
} }
/** /**
...@@ -114,9 +112,4 @@ class StatementTest extends TestCase ...@@ -114,9 +112,4 @@ class StatementTest extends TestCase
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
} }
protected function createStatement(DriverStatement $wrappedStatement, Connection $connection) : Statement
{
return new Statement($wrappedStatement, $connection);
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment